From 9da44e3571549e9eb5f00f3de4f89446e305e78b Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Tue, 15 Aug 2023 09:18:49 -0700 Subject: [PATCH 01/10] [Reporting/Docs] Tighten the language around CSV settings (#163505) ## Summary Docs request to tighten the language around csv.maxSizeBytes on this [page](https://www.elastic.co/guide/en/kibana/8.8/reporting-settings-kb.html#reporting-csv-settings). - [x] test the links Closes: https://github.com/elastic/kibana/issues/159112 Replaces: https://github.com/elastic/kibana/pull/161189 --------- Co-authored-by: Amy Jonsson Co-authored-by: amyjtechwriter <61687663+amyjtechwriter@users.noreply.github.com> --- docs/settings/reporting-settings.asciidoc | 36 +++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/docs/settings/reporting-settings.asciidoc b/docs/settings/reporting-settings.asciidoc index 77f1b01cc21b4..424a661820423 100644 --- a/docs/settings/reporting-settings.asciidoc +++ b/docs/settings/reporting-settings.asciidoc @@ -203,26 +203,40 @@ The `file:` protocol is always denied, even if no network policy is configured. ==== CSV settings [[xpack-reporting-csv]] `xpack.reporting.csv.maxSizeBytes` {ess-icon}:: -The maximum {byte-units}[byte size] of a CSV file before being truncated. This setting exists to prevent large exports from causing performance and storage issues. Can be specified as number of bytes. Defaults to `10mb`. +The maximum {byte-units}[byte size] of a CSV file before being truncated. This setting exists to prevent large +exports from causing performance and storage issues. Can be specified as number of bytes. Defaults to `250mb`. [NOTE] ============ -Setting `xpack.reporting.csv.maxSizeBytes` much larger than the default 10 MB limit has the potential to negatively affect the -performance of {kib} and your {es} cluster. There is no enforced maximum for this setting, but a reasonable maximum value depends -on multiple factors: +We recommend using CSV reports to export moderate amounts of data only. The feature enables analysis of data in +external tools, but it's not intended for bulk export or to backup {es} data. If you need to export more than +250 MB of CSV, rather than increasing `xpack.reporting.csv.maxSizeBytes`, please use filters to create multiple +smaller reports, or extract the data you need directly from {es}. -* The `http.max_content_length` setting in {es}. -* Network proxies, which are often configured by default to block large requests with a 413 error. -* The amount of memory available to the {kib} server, which limits the size of CSV data that must be held temporarily. +The following deployment configurations may lead to failed report jobs or incomplete reports: -For information about {kib} memory limits, see <>. +* Any shard needed for search is unavailable. +* Data is stored on slow storage tiers. +* Network latency between nodes is high. +* {ccs-cap} is used. + +To export large amounts of data we recommend using {es} APIs directly. See {ref}/point-in-time-api.html[Point +in time API], or {ref}/sql-rest-format.html#_csv[SQL with CSV response data format]. ============ `xpack.reporting.csv.scroll.size`:: Number of documents retrieved from {es} for each scroll iteration during a CSV export. Defaults to `500`. +[NOTE] +============ +You may need to lower this setting if the default number of documents creates a strain on network resources. +============ `xpack.reporting.csv.scroll.duration`:: Amount of {time-units}[time] allowed before {kib} cleans the scroll context during a CSV export. Defaults to `30s`. +[NOTE] +============ +If search latency in {es} is sufficiently high, such as if you are using {ccs}, you may need to increase the setting. +============ `xpack.reporting.csv.checkForFormulas`:: Enables a check that warns you when there's a potential formula included in the output (=, -, +, and @ chars). See OWASP: https://www.owasp.org/index.php/CSV_Injection. Defaults to `true`. @@ -231,7 +245,11 @@ Enables a check that warns you when there's a potential formula included in the Escape formula values in cells with a `'`. See OWASP: https://www.owasp.org/index.php/CSV_Injection. Defaults to `true`. `xpack.reporting.csv.enablePanelActionDownload`:: -deprecated:[7.9.0,This setting has no effect.] Enables CSV export from a saved search on a dashboard. This action is available in the dashboard panel menu for the saved search. *NOTE*: This setting exists for backwards compatibility, but is unused and hardcoded to `true`. CSV export from a saved search on a dashboard is enabled when Reporting is enabled. +deprecated:[7.9.0,This setting has no effect.] Enables CSV export from a saved search on a dashboard. This action is available in the dashboard panel menu for the saved search. +[NOTE] +============ +This setting exists for backwards compatibility, and is hardcoded to `true`. CSV export from a saved search on a dashboard is enabled when Reporting is enabled. +============ `xpack.reporting.csv.useByteOrderMarkEncoding`:: Adds a byte order mark (`\ufeff`) at the beginning of the CSV file. Defaults to `false`. From d5a3ed1dee2ab263d0a7e6683c0a14a0e04103e2 Mon Sep 17 00:00:00 2001 From: Sander Philipse <94373878+sphilipse@users.noreply.github.com> Date: Tue, 15 Aug 2023 18:31:22 +0200 Subject: [PATCH 02/10] [Serverless] Add deployment URL (#163925) ## Summary This adds a link to the concrete project in Serverless ES3. We can't link to performance directly because that has been descoped for now. --- .../core-chrome-browser/src/project_navigation.ts | 2 +- .../chrome/navigation/src/cloud_links.tsx | 14 +++++++++++++- .../serverless_search/public/layout/nav.tsx | 7 +++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index 38317cfc1e0f2..b2a0384e3a1a9 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -45,7 +45,7 @@ export type AppDeepLinkId = | ObservabilityLink; /** @public */ -export type CloudLinkId = 'userAndRoles' | 'performance' | 'billingAndSub'; +export type CloudLinkId = 'userAndRoles' | 'performance' | 'billingAndSub' | 'deployment'; export type GetIsActiveFn = (params: { /** The current path name including the basePath + hash value but **without** any query params */ diff --git a/packages/shared-ux/chrome/navigation/src/cloud_links.tsx b/packages/shared-ux/chrome/navigation/src/cloud_links.tsx index 4efd73b8e3a97..fd1909551888b 100644 --- a/packages/shared-ux/chrome/navigation/src/cloud_links.tsx +++ b/packages/shared-ux/chrome/navigation/src/cloud_links.tsx @@ -17,7 +17,7 @@ export type CloudLinks = { }; export const getCloudLinks = (cloud: CloudStart): CloudLinks => { - const { billingUrl, performanceUrl, usersAndRolesUrl } = cloud; + const { billingUrl, deploymentUrl, performanceUrl, usersAndRolesUrl } = cloud; const links: CloudLinks = {}; @@ -54,5 +54,17 @@ export const getCloudLinks = (cloud: CloudStart): CloudLinks => { }; } + if (deploymentUrl) { + links.deployment = { + title: i18n.translate( + 'sharedUXPackages.chrome.sideNavigation.cloudLinks.deploymentLinkText', + { + defaultMessage: 'Project', + } + ), + href: deploymentUrl, + }; + } + return links; }; diff --git a/x-pack/plugins/serverless_search/public/layout/nav.tsx b/x-pack/plugins/serverless_search/public/layout/nav.tsx index fd460f8c95066..568b3e8ca5cdf 100644 --- a/x-pack/plugins/serverless_search/public/layout/nav.tsx +++ b/x-pack/plugins/serverless_search/public/layout/nav.tsx @@ -134,6 +134,13 @@ const navigationTree: NavigationTreeDefinition = { defaultMessage: 'Management', }), }, + { + id: 'cloudLinkDeployment', + cloudLink: 'deployment', + title: i18n.translate('xpack.serverlessSearch.nav.performance', { + defaultMessage: 'Performance', + }), + }, { id: 'cloudLinkUserAndRoles', cloudLink: 'userAndRoles', From 0ee8b1a0b0948b23aae501835c6f66a698f66264 Mon Sep 17 00:00:00 2001 From: Jiawei Wu <74562234+JiaweiWu@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:00:56 -0700 Subject: [PATCH 03/10] [RAM] Unskip Bulk Edit E2E Test and Fix Small Bug (#163888) ## Summary Resolves: https://github.com/elastic/kibana/issues/138050 Unskips the bulk edit e2e test, also fixes a small bug where we were not mapping the `mapped_params` in the rule transforms. ### 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 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../common/routes/rule/response/index.ts | 10 +++- .../common/routes/rule/response/types/v1.ts | 11 ++++- .../transform_rule_to_rule_response/v1.ts | 49 ++++++++++++++----- .../tests/alerting/group4/bulk_edit.ts | 28 ++++++----- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/alerting/common/routes/rule/response/index.ts b/x-pack/plugins/alerting/common/routes/rule/response/index.ts index 1b7180910ca0a..4be81ae30c79f 100644 --- a/x-pack/plugins/alerting/common/routes/rule/response/index.ts +++ b/x-pack/plugins/alerting/common/routes/rule/response/index.ts @@ -17,7 +17,13 @@ export { ruleSnoozeScheduleSchema, } from './schemas/latest'; -export type { RuleParams, RuleResponse, RuleSnoozeSchedule } from './types/latest'; +export type { + RuleParams, + RuleResponse, + RuleSnoozeSchedule, + RuleLastRun, + Monitoring, +} from './types/latest'; export { ruleNotifyWhen, @@ -67,4 +73,6 @@ export type { RuleParams as RuleParamsV1, RuleResponse as RuleResponseV1, RuleSnoozeSchedule as RuleSnoozeScheduleV1, + RuleLastRun as RuleLastRunV1, + Monitoring as MonitoringV1, } from './types/v1'; diff --git a/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts index cd19cf9fa5c5e..c6c2c7218ed88 100644 --- a/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/response/types/v1.ts @@ -6,10 +6,19 @@ */ import type { TypeOf } from '@kbn/config-schema'; -import { ruleParamsSchemaV1, ruleResponseSchemaV1, ruleSnoozeScheduleSchemaV1 } from '..'; +import { + ruleParamsSchemaV1, + ruleResponseSchemaV1, + ruleSnoozeScheduleSchemaV1, + ruleLastRunSchemaV1, + monitoringSchemaV1, +} from '..'; export type RuleParams = TypeOf; export type RuleSnoozeSchedule = TypeOf; +export type RuleLastRun = TypeOf; +export type Monitoring = TypeOf; + type RuleResponseSchemaType = TypeOf; export interface RuleResponse { diff --git a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts index 9c38431f24b9e..e43427fe4470a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/transforms/transform_rule_to_rule_response/v1.ts @@ -5,16 +5,36 @@ * 2.0. */ -import { RuleResponseV1, RuleParamsV1 } from '../../../../../common/routes/rule/response'; -import { Rule, RuleLastRun, RuleParams } from '../../../../application/rule/types'; +import { + RuleResponseV1, + RuleParamsV1, + RuleLastRunV1, + MonitoringV1, +} from '../../../../../common/routes/rule/response'; +import { Rule, RuleLastRun, RuleParams, Monitoring } from '../../../../application/rule/types'; -const transformRuleLastRun = (lastRun: RuleLastRun): RuleResponseV1['last_run'] => { +const transformRuleLastRun = (lastRun: RuleLastRun): RuleLastRunV1 => { return { outcome: lastRun.outcome, - outcome_order: lastRun.outcomeOrder, - ...(lastRun.warning ? { warning: lastRun.warning } : {}), + ...(lastRun.outcomeOrder !== undefined ? { outcome_order: lastRun.outcomeOrder } : {}), + ...(lastRun.warning !== undefined ? { warning: lastRun.warning } : {}), + ...(lastRun.outcomeMsg !== undefined ? { outcome_msg: lastRun.outcomeMsg } : {}), alerts_count: lastRun.alertsCount, - outcome_msg: lastRun.outcomeMsg, + }; +}; + +const transformMonitoring = (monitoring: Monitoring): MonitoringV1 => { + return { + run: { + history: monitoring.run.history.map((history) => ({ + success: history.success, + timestamp: history.timestamp, + ...(history.duration !== undefined ? { duration: history.duration } : {}), + ...(history.outcome ? { outcome: transformRuleLastRun(history.outcome) } : {}), + })), + calculated_metrics: monitoring.run.calculated_metrics, + last_run: monitoring.run.last_run, + }, }; }; @@ -48,6 +68,8 @@ export const transformRuleToRuleResponse = ( }) ), params: rule.params, + ...(rule.mapped_params ? { mapped_params: rule.mapped_params } : {}), + ...(rule.scheduledTaskId !== undefined ? { scheduled_task_id: rule.scheduledTaskId } : {}), created_by: rule.createdBy, updated_by: rule.updatedBy, created_at: rule.createdAt.toISOString(), @@ -57,13 +79,9 @@ export const transformRuleToRuleResponse = ( ? { api_key_created_by_user: rule.apiKeyCreatedByUser } : {}), ...(rule.throttle !== undefined ? { throttle: rule.throttle } : {}), - ...(rule.notifyWhen !== undefined ? { notify_when: rule.notifyWhen } : {}), mute_all: rule.muteAll, + ...(rule.notifyWhen !== undefined ? { notify_when: rule.notifyWhen } : {}), muted_alert_ids: rule.mutedInstanceIds, - ...(rule.scheduledTaskId !== undefined ? { scheduled_task_id: rule.scheduledTaskId } : {}), - ...(rule.isSnoozedUntil !== undefined - ? { is_snoozed_until: rule.isSnoozedUntil?.toISOString() || null } - : {}), execution_status: { status: rule.executionStatus.status, ...(rule.executionStatus.error ? { error: rule.executionStatus.error } : {}), @@ -73,10 +91,19 @@ export const transformRuleToRuleResponse = ( ? { last_duration: rule.executionStatus.lastDuration } : {}), }, + ...(rule.monitoring ? { monitoring: transformMonitoring(rule.monitoring) } : {}), + ...(rule.snoozeSchedule ? { snooze_schedule: rule.snoozeSchedule } : {}), + ...(rule.activeSnoozes ? { active_snoozes: rule.activeSnoozes } : {}), + ...(rule.isSnoozedUntil !== undefined + ? { is_snoozed_until: rule.isSnoozedUntil?.toISOString() || null } + : {}), ...(rule.lastRun !== undefined ? { last_run: rule.lastRun ? transformRuleLastRun(rule.lastRun) : null } : {}), ...(rule.nextRun !== undefined ? { next_run: rule.nextRun?.toISOString() || null } : {}), revision: rule.revision, ...(rule.running !== undefined ? { running: rule.running } : {}), + ...(rule.viewInAppRelativeUrl !== undefined + ? { view_in_app_relative_url: rule.viewInAppRelativeUrl } + : {}), }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts index cfd8be8d5b181..9e06b9f73422c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts @@ -14,7 +14,7 @@ import { getUrlPrefix, getTestRuleData, ObjectRemover, - createWaitForExecutionCount, + getEventLog, } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -34,10 +34,8 @@ const getSnoozeSchedule = () => { export default function createUpdateTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const retry = getService('retry'); - const waitForExecutionCount = createWaitForExecutionCount(supertest, Spaces.space1.id); - // Failing: See https://github.com/elastic/kibana/issues/138050 - describe.skip('bulkEdit', () => { + describe('bulkEdit', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); @@ -463,7 +461,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { }); }); - it('should bulk update API key with apiKey operation', async () => { + it('should not bulk update API key with apiKey operation', async () => { const { body: createdRule } = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') @@ -493,8 +491,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { expect(bulkApiKeyResponse.body.errors).to.have.length(0); expect(bulkApiKeyResponse.body.rules).to.have.length(1); expect(bulkApiKeyResponse.body.rules[0].api_key_owner).to.eql(null); - // Ensure revision is updated - expect(bulkApiKeyResponse.body.rules[0].revision).to.eql(1); + expect(bulkApiKeyResponse.body.rules[0].revision).to.eql(0); }); it(`shouldn't bulk edit rule from another space`, async () => { @@ -520,7 +517,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { .post(`${getUrlPrefix(Spaces.other.id)}/internal/alerting/rules/_bulk_edit`) .set('kbn-xsrf', 'foo') .send(payload) - .expect(200, { rules: [], errors: [], total: 0 }); + .expect(200, { rules: [], errors: [], skipped: [], total: 0 }); }); it('should return mapped params after bulk edit', async () => { @@ -575,7 +572,16 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { objectRemover.add(Spaces.space1.id, createdRule.id, 'rule', 'alerting'); - await waitForExecutionCount(1, createdRule.id); + await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: Spaces.space1.id, + type: 'alert', + id: createdRule.id, + provider: 'alerting', + actions: new Map([['execute', { equal: 1 }]]), + }); + }); const monitoringData = ( await supertest.get( @@ -583,8 +589,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { ) ).body.monitoring; - // single rule execution is recorded in monitoring history - expect(monitoringData.execution.history).to.have.length(1); + // single rule run is recorded in monitoring history + expect(monitoringData.run.history).to.have.length(1); const payload = { ids: [createdRule.id], From 005234df87f27e4a2bf0e5f229b3886c584f9949 Mon Sep 17 00:00:00 2001 From: christineweng <18648970+christineweng@users.noreply.github.com> Date: Tue, 15 Aug 2023 12:07:44 -0500 Subject: [PATCH 04/10] [Security Solution][Alert Details] Expandable flyout - host and user overview ui updates (#163896) ## Summary This PR updates properties of host and user over to be displayed in expandable flyout -> right section -> Insights. User section - Replaced IP with user domain - Added fall back (last seen date) if risk score is not available (without proper license) - Removed tech preview icon Host section - Replaced IP with host os family - Added fall bask (last seen date) if risk score is not available (without proper license) - Removed tech preview icon ![image](https://github.com/elastic/kibana/assets/18648970/06f2c0fd-ed9d-49e1-b9c2-144da23fed95) **How to Test** - add `xpack.securitySolution.enableExperimental: ['securityFlyoutEnabled']` to the `kibana.dev.json` file - go to the Alerts page, and click on the expand detail button on any row of the table - click on `Overview`, `Insights`, `Entities` ### 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 --- .../components/host_entity_overview.test.tsx | 37 +++++--- .../right/components/host_entity_overview.tsx | 95 ++++++++++--------- .../flyout/right/components/test_ids.ts | 8 +- .../flyout/right/components/translations.ts | 13 --- .../components/user_entity_overview.test.tsx | 38 +++++--- .../right/components/user_entity_overview.tsx | 73 +++++++------- .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 9 files changed, 139 insertions(+), 131 deletions(-) diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx index 9021318685373..8b61c823fb299 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx @@ -10,11 +10,12 @@ import { TestProviders } from '../../../common/mock'; import { HostEntityOverview } from './host_entity_overview'; import { useRiskScore } from '../../../explore/containers/risk_score'; import { useHostDetails } from '../../../explore/hosts/containers/hosts/details'; +import { useFirstLastSeen } from '../../../common/containers/use_first_last_seen'; import { - ENTITIES_HOST_OVERVIEW_IP_TEST_ID, + ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID, + ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID, ENTITIES_HOST_OVERVIEW_LINK_TEST_ID, ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID, - TECHNICAL_PREVIEW_ICON_TEST_ID, } from './test_ids'; import { RightPanelContext } from '../context'; import { mockContextValue } from '../mocks/mock_right_panel_context'; @@ -24,11 +25,13 @@ import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; const hostName = 'host'; -const ip = '10.200.000.000'; +const osFamily = 'Windows'; +const lastSeen = '2022-04-08T18:35:45.064Z'; +const lastSeenText = 'Apr 8, 2022 @ 18:35:45.064'; const from = '2022-04-05T12:00:00.000Z'; const to = '2022-04-08T12:00:00.;000Z'; const selectedPatterns = 'alerts'; -const hostData = { host: { ip: [ip] } }; +const hostData = { host: { os: { family: [osFamily] } } }; const riskLevel = [{ host: { risk: { calculated_level: 'Medium' } } }]; const panelContextValue = { @@ -60,9 +63,12 @@ jest.mock('../../../explore/hosts/containers/hosts/details'); const mockUseRiskScore = useRiskScore as jest.Mock; jest.mock('../../../explore/containers/risk_score'); +const mockUseFirstLastSeen = useFirstLastSeen as jest.Mock; +jest.mock('../../../common/containers/use_first_last_seen'); + describe('', () => { describe('license is valid', () => { - it('should render ip addresses and host risk classification', () => { + it('should render os family and host risk classification', () => { mockUseHostDetails.mockReturnValue([false, { hostDetails: hostData }]); mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: true }); @@ -74,8 +80,7 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_HOST_OVERVIEW_IP_TEST_ID)).toHaveTextContent(ip); - expect(getByTestId(TECHNICAL_PREVIEW_ICON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID)).toHaveTextContent(osFamily); expect(getByTestId(ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID)).toHaveTextContent('Medium'); }); @@ -90,16 +95,17 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_HOST_OVERVIEW_IP_TEST_ID)).toHaveTextContent('—'); - expect(getByTestId(TECHNICAL_PREVIEW_ICON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID)).toHaveTextContent('—'); expect(getByTestId(ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID)).toHaveTextContent('Unknown'); }); }); describe('license is not valid', () => { - it('should render ip but not host risk classification', () => { + it('should render os family and last seen', () => { mockUseHostDetails.mockReturnValue([false, { hostDetails: hostData }]); mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: false }); + mockUseFirstLastSeen.mockReturnValue([false, { lastSeen }]); + const { getByTestId, queryByTestId } = render( @@ -108,14 +114,17 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_HOST_OVERVIEW_IP_TEST_ID)).toHaveTextContent(ip); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID)).toHaveTextContent(osFamily); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID)).toHaveTextContent(lastSeenText); expect(queryByTestId(ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID)).not.toBeInTheDocument(); }); it('should render correctly if returned data is null', () => { mockUseHostDetails.mockReturnValue([false, { hostDetails: null }]); mockUseRiskScore.mockReturnValue({ data: null, isAuthorized: false }); - const { getByTestId, queryByTestId } = render( + mockUseFirstLastSeen.mockReturnValue([false, { lastSeen: null }]); + + const { getByTestId } = render( @@ -123,8 +132,8 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_HOST_OVERVIEW_IP_TEST_ID)).toHaveTextContent('—'); - expect(queryByTestId(TECHNICAL_PREVIEW_ICON_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID)).toHaveTextContent('—'); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID)).toHaveTextContent('—'); }); it('should navigate to left panel entities tab when clicking on title', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx index babd0b7c37015..18cac803894a9 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx @@ -9,7 +9,6 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, - EuiBetaBadge, EuiLink, EuiIcon, useEuiTheme, @@ -20,28 +19,29 @@ import { getOr } from 'lodash/fp'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { useRightPanelContext } from '../context'; import type { DescriptionList } from '../../../../common/utility_types'; +import { + FirstLastSeen, + FirstLastSeenType, +} from '../../../common/components/first_last_seen/first_last_seen'; import { buildHostNamesFilter, RiskScoreEntity, RiskSeverity, } from '../../../../common/search_strategy'; import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/field_renderers'; -import { NetworkDetailsLink } from '../../../common/components/links'; import { DescriptionListStyled } from '../../../common/components/page'; import { OverviewDescriptionList } from '../../../common/components/overview_description_list'; import { RiskScore } from '../../../explore/components/risk_score/severity/common'; -import { getEmptyTagValue } from '../../../common/components/empty_value'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useRiskScore } from '../../../explore/containers/risk_score'; import { useHostDetails } from '../../../explore/hosts/containers/hosts/details'; import * as i18n from '../../../overview/components/host_overview/translations'; -import { TECHNICAL_PREVIEW_TITLE, TECHNICAL_PREVIEW_MESSAGE } from './translations'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { - TECHNICAL_PREVIEW_ICON_TEST_ID, ENTITIES_HOST_OVERVIEW_TEST_ID, - ENTITIES_HOST_OVERVIEW_IP_TEST_ID, + ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID, + ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID, ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID, ENTITIES_HOST_OVERVIEW_LINK_TEST_ID, } from './test_ids'; @@ -105,6 +105,40 @@ export const HostEntityOverview: React.FC = ({ hostName endDate: to, }); + const hostOSFamily: DescriptionList[] = useMemo( + () => [ + { + title: i18n.FAMILY, + description: ( + + ), + }, + ], + [hostDetails] + ); + + const hostLastSeen: DescriptionList[] = useMemo( + () => [ + { + title: i18n.LAST_SEEN, + description: ( + + ), + }, + ], + [hostName, selectedPatterns] + ); + const { euiTheme } = useEuiTheme(); const xsFontSize = useEuiFontSize('xs').fontSize; @@ -112,23 +146,7 @@ export const HostEntityOverview: React.FC = ({ hostName const hostRiskData = hostRisk && hostRisk.length > 0 ? hostRisk[0] : undefined; return [ { - title: ( - <> - {i18n.HOST_RISK_CLASSIFICATION} - - - ), + title: i18n.HOST_RISK_CLASSIFICATION, description: ( <> {hostRiskData ? ( @@ -140,25 +158,7 @@ export const HostEntityOverview: React.FC = ({ hostName ), }, ]; - }, [euiTheme.size.xs, hostRisk]); - - const descriptionList: DescriptionList[] = useMemo( - () => [ - { - title: i18n.IP_ADDRESSES, - description: ( - (ip != null ? : getEmptyTagValue())} - /> - ), - }, - ], - [hostDetails] - ); + }, [hostRisk]); return ( @@ -185,16 +185,21 @@ export const HostEntityOverview: React.FC = ({ hostName - {isAuthorized && ( + {isAuthorized ? ( + ) : ( + )} 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 43868275c0399..9e8b112851be6 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 @@ -90,17 +90,17 @@ export const INSIGHTS_ENTITIES_TITLE_ICON_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(INSIGHTS_ENTITIES_TEST_ID); export const INSIGHTS_ENTITIES_CONTENT_TEST_ID = EXPANDABLE_PANEL_CONTENT_TEST_ID(INSIGHTS_ENTITIES_TEST_ID); -export const TECHNICAL_PREVIEW_ICON_TEST_ID = - 'securitySolutionDocumentDetailsFlyoutTechnicalPreviewIcon'; export const ENTITIES_USER_OVERVIEW_TEST_ID = 'securitySolutionDocumentDetailsFlyoutEntitiesUserOverview'; export const ENTITIES_USER_OVERVIEW_LINK_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}Link`; -export const ENTITIES_USER_OVERVIEW_IP_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}IP`; +export const ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}Domain`; +export const ENTITIES_USER_OVERVIEW_LAST_SEEN_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}LastSeen`; export const ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}RiskLevel`; export const ENTITIES_HOST_OVERVIEW_TEST_ID = 'securitySolutionDocumentDetailsFlyoutEntitiesHostOverview'; export const ENTITIES_HOST_OVERVIEW_LINK_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}Link`; -export const ENTITIES_HOST_OVERVIEW_IP_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}IP`; +export const ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}OsFamily`; +export const ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}LastSeen`; export const ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}RiskLevel`; /* Insights Threat Intelligence */ 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 65dcb49f36f21..f32e9abb1d48f 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 @@ -138,19 +138,6 @@ export const PREVALENCE_TITLE = i18n.translate( { defaultMessage: 'Prevalence' } ); -export const TECHNICAL_PREVIEW_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.technicalPreviewTitle', - { defaultMessage: 'Technical Preview' } -); - -export const TECHNICAL_PREVIEW_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.technicalPreviewMessage', - { - defaultMessage: - 'This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.', - } -); - export const THREAT_MATCH_DETECTED = i18n.translate( 'xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatch', { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.test.tsx index eea824bd3dcc8..4739130949e96 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.test.tsx @@ -9,12 +9,12 @@ import { render } from '@testing-library/react'; import { TestProviders } from '../../../common/mock'; import { UserEntityOverview } from './user_entity_overview'; import { useRiskScore } from '../../../explore/containers/risk_score'; - +import { useFirstLastSeen } from '../../../common/containers/use_first_last_seen'; import { - ENTITIES_USER_OVERVIEW_IP_TEST_ID, + ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID, + ENTITIES_USER_OVERVIEW_LAST_SEEN_TEST_ID, ENTITIES_USER_OVERVIEW_LINK_TEST_ID, ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID, - TECHNICAL_PREVIEW_ICON_TEST_ID, } from './test_ids'; import { useObservedUserDetails } from '../../../explore/users/containers/users/observed_details'; import { mockContextValue } from '../mocks/mock_right_panel_context'; @@ -25,11 +25,13 @@ import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; const userName = 'user'; -const ip = '10.200.000.000'; +const domain = 'n54bg2lfc7'; +const lastSeen = '2022-04-08T18:35:45.064Z'; +const lastSeenText = 'Apr 8, 2022 @ 18:35:45.064'; const from = '2022-04-05T12:00:00.000Z'; const to = '2022-04-08T12:00:00.;000Z'; const selectedPatterns = 'alerts'; -const userData = { host: { ip: [ip] } }; +const userData = { user: { domain: [domain] } }; const riskLevel = [{ user: { risk: { calculated_level: 'Medium' } } }]; const panelContextValue = { @@ -61,9 +63,12 @@ jest.mock('../../../explore/users/containers/users/observed_details'); const mockUseRiskScore = useRiskScore as jest.Mock; jest.mock('../../../explore/containers/risk_score'); +const mockUseFirstLastSeen = useFirstLastSeen as jest.Mock; +jest.mock('../../../common/containers/use_first_last_seen'); + describe('', () => { describe('license is valid', () => { - it('should render ip addresses and user risk classification', () => { + it('should render user domain and user risk classification', () => { mockUseUserDetails.mockReturnValue([false, { userDetails: userData }]); mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: true }); @@ -75,8 +80,7 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_USER_OVERVIEW_IP_TEST_ID)).toHaveTextContent(ip); - expect(getByTestId(TECHNICAL_PREVIEW_ICON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID)).toHaveTextContent(domain); expect(getByTestId(ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID)).toHaveTextContent('Medium'); }); @@ -91,16 +95,17 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_USER_OVERVIEW_IP_TEST_ID)).toHaveTextContent('—'); - expect(getByTestId(TECHNICAL_PREVIEW_ICON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID)).toHaveTextContent('—'); expect(getByTestId(ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID)).toHaveTextContent('Unknown'); }); }); describe('license is not valid', () => { - it('should render ip but not user risk classification', () => { + it('should render domain and last seen', () => { mockUseUserDetails.mockReturnValue([false, { userDetails: userData }]); mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: false }); + mockUseFirstLastSeen.mockReturnValue([false, { lastSeen }]); + const { getByTestId, queryByTestId } = render( @@ -109,14 +114,17 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_USER_OVERVIEW_IP_TEST_ID)).toHaveTextContent(ip); + expect(getByTestId(ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID)).toHaveTextContent(domain); + expect(getByTestId(ENTITIES_USER_OVERVIEW_LAST_SEEN_TEST_ID)).toHaveTextContent(lastSeenText); expect(queryByTestId(ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID)).not.toBeInTheDocument(); }); it('should render correctly if returned data is null', () => { mockUseUserDetails.mockReturnValue([false, { userDetails: null }]); mockUseRiskScore.mockReturnValue({ data: null, isAuthorized: false }); - const { getByTestId, queryByTestId } = render( + mockUseFirstLastSeen.mockReturnValue([false, { lastSeen: null }]); + + const { getByTestId } = render( @@ -124,8 +132,8 @@ describe('', () => { ); - expect(getByTestId(ENTITIES_USER_OVERVIEW_IP_TEST_ID)).toHaveTextContent('—'); - expect(queryByTestId(TECHNICAL_PREVIEW_ICON_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID)).toHaveTextContent('—'); + expect(getByTestId(ENTITIES_USER_OVERVIEW_LAST_SEEN_TEST_ID)).toHaveTextContent('—'); }); it('should navigate to left panel entities tab when clicking on title', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx index 3e015659a7ebc..ed3da595b7a21 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx @@ -9,7 +9,6 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, - EuiBetaBadge, EuiIcon, EuiLink, useEuiTheme, @@ -22,26 +21,27 @@ import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { useRightPanelContext } from '../context'; import type { DescriptionList } from '../../../../common/utility_types'; +import { + FirstLastSeen, + FirstLastSeenType, +} from '../../../common/components/first_last_seen/first_last_seen'; import { buildUserNamesFilter, RiskScoreEntity, RiskSeverity, } from '../../../../common/search_strategy'; import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/field_renderers'; -import { NetworkDetailsLink } from '../../../common/components/links'; import { DescriptionListStyled } from '../../../common/components/page'; import { OverviewDescriptionList } from '../../../common/components/overview_description_list'; import { RiskScore } from '../../../explore/components/risk_score/severity/common'; -import { getEmptyTagValue } from '../../../common/components/empty_value'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useRiskScore } from '../../../explore/containers/risk_score'; import * as i18n from '../../../overview/components/user_overview/translations'; -import { TECHNICAL_PREVIEW_TITLE, TECHNICAL_PREVIEW_MESSAGE } from './translations'; import { - TECHNICAL_PREVIEW_ICON_TEST_ID, ENTITIES_USER_OVERVIEW_TEST_ID, - ENTITIES_USER_OVERVIEW_IP_TEST_ID, + ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID, + ENTITIES_USER_OVERVIEW_LAST_SEEN_TEST_ID, ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID, ENTITIES_USER_OVERVIEW_LINK_TEST_ID, } from './test_ids'; @@ -90,7 +90,7 @@ export const UserEntityOverview: React.FC = ({ userName () => (userName ? buildUserNamesFilter([userName]) : undefined), [userName] ); - const [_, { userDetails: data }] = useObservedUserDetails({ + const [_, { userDetails }] = useObservedUserDetails({ endDate: to, userName, indexNames: selectedPatterns, @@ -103,22 +103,38 @@ export const UserEntityOverview: React.FC = ({ userName timerange, }); - const descriptionList: DescriptionList[] = useMemo( + const userDomain: DescriptionList[] = useMemo( () => [ { - title: i18n.HOST_IP, + title: i18n.USER_DOMAIN, description: ( (ip != null ? : getEmptyTagValue())} /> ), }, ], - [data] + [userDetails] + ); + + const userLastSeen: DescriptionList[] = useMemo( + () => [ + { + title: i18n.LAST_SEEN, + description: ( + + ), + }, + ], + [userName, selectedPatterns] ); const { euiTheme } = useEuiTheme(); @@ -129,23 +145,7 @@ export const UserEntityOverview: React.FC = ({ userName return [ { - title: ( - <> - {i18n.USER_RISK_CLASSIFICATION} - - - ), - + title: i18n.USER_RISK_CLASSIFICATION, description: ( <> {userRiskData ? ( @@ -157,7 +157,7 @@ export const UserEntityOverview: React.FC = ({ userName ), }, ]; - }, [euiTheme.size.xs, userRisk]); + }, [userRisk]); return ( @@ -184,16 +184,21 @@ export const UserEntityOverview: React.FC = ({ userName - {isAuthorized && ( + {isAuthorized ? ( + ) : ( + )} diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 69b5cdb5dd9e9..2f997dec6acbd 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -33356,8 +33356,6 @@ "xpack.securitySolution.flyout.documentDetails.severityTitle": "Sévérité", "xpack.securitySolution.flyout.documentDetails.share": "Partager l'alerte", "xpack.securitySolution.flyout.documentDetails.tableTab": "Tableau", - "xpack.securitySolution.flyout.documentDetails.technicalPreviewMessage": "Cette fonctionnalité est en version d'évaluation technique et pourra être modifiée ou retirée complètement dans une future version. Elastic s'efforcera au maximum de corriger tout problème, mais les fonctionnalités en version d'évaluation technique ne sont pas soumises aux accords de niveau de service d'assistance des fonctionnalités officielles en disponibilité générale.", - "xpack.securitySolution.flyout.documentDetails.technicalPreviewTitle": "Version d'évaluation technique", "xpack.securitySolution.flyout.documentDetails.threatIntelligenceButton": "Threat Intelligence", "xpack.securitySolution.flyout.documentDetails.threatIntelligenceTitle": "Threat Intelligence", "xpack.securitySolution.flyout.documentDetails.visualizationsTitle": "Visualisations", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 56e128816276b..81bdfd0f3ba59 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -33355,8 +33355,6 @@ "xpack.securitySolution.flyout.documentDetails.severityTitle": "深刻度", "xpack.securitySolution.flyout.documentDetails.share": "アラートを共有", "xpack.securitySolution.flyout.documentDetails.tableTab": "表", - "xpack.securitySolution.flyout.documentDetails.technicalPreviewMessage": "この機能はテクニカルプレビュー中であり、将来のリリースでは変更されたり完全に削除されたりする場合があります。Elasticは最善の努力を講じてすべての問題の修正に努めますが、テクニカルプレビュー中の機能には正式なGA機能のサポートSLAが適用されません。", - "xpack.securitySolution.flyout.documentDetails.technicalPreviewTitle": "テクニカルプレビュー", "xpack.securitySolution.flyout.documentDetails.threatIntelligenceButton": "脅威インテリジェンス", "xpack.securitySolution.flyout.documentDetails.threatIntelligenceTitle": "脅威インテリジェンス", "xpack.securitySolution.flyout.documentDetails.visualizationsTitle": "ビジュアライゼーション", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8caefd7824672..fe6dc047c1a3d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -33351,8 +33351,6 @@ "xpack.securitySolution.flyout.documentDetails.severityTitle": "严重性", "xpack.securitySolution.flyout.documentDetails.share": "共享告警", "xpack.securitySolution.flyout.documentDetails.tableTab": "表", - "xpack.securitySolution.flyout.documentDetails.technicalPreviewMessage": "此功能处于技术预览状态,在未来版本中可能会更改或完全移除。Elastic 将尽最大努力来修复任何问题,但处于技术预览状态的功能不受正式 GA 功能支持 SLA 的约束。", - "xpack.securitySolution.flyout.documentDetails.technicalPreviewTitle": "技术预览", "xpack.securitySolution.flyout.documentDetails.threatIntelligenceButton": "威胁情报", "xpack.securitySolution.flyout.documentDetails.threatIntelligenceTitle": "威胁情报", "xpack.securitySolution.flyout.documentDetails.visualizationsTitle": "可视化", From 39f2a2567a930b628b84eca895c1507a990ebebf Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Tue, 15 Aug 2023 19:09:19 +0200 Subject: [PATCH 05/10] [ML] Hide paging controls in swim lane if only one page is available (#163931) --- .../ml/public/application/explorer/swimlane_container.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index a6595ed797e80..05e6fdafe28d2 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -244,6 +244,7 @@ export const SwimlaneContainer: FC = ({ const isPaginationVisible = (showSwimlane || isLoading) && swimlaneLimit !== undefined && + swimlaneLimit > (perPage ?? 5) && onPaginationChange && fromPage && perPage; From fb6ac2e4459ff5b981c41cdf410c2b321614942b Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Tue, 15 Aug 2023 19:10:07 +0200 Subject: [PATCH 06/10] [ML] AIOps: Add/edit change point charts embeddable from the Dashboard app (#163694) --- .../ml/agg_utils/src/validate_number.ts | 5 +- x-pack/plugins/aiops/kibana.jsonc | 3 +- .../change_point_detection_context.tsx | 40 +++ .../change_point_detection_root.tsx | 9 +- .../chart_component.tsx | 5 +- .../change_point_detection/charts_grid.tsx | 31 +- .../change_point_detection/fields_config.tsx | 81 ++--- .../max_series_control.tsx | 72 +++++ .../metric_field_selector.tsx | 27 +- .../partitions_selector.tsx | 192 ++++++++++++ .../split_field_selector.tsx | 105 ++++--- .../change_point_chart_initializer.tsx | 284 +++++++++++++----- .../plugins/aiops/public/embeddable/const.ts | 2 + .../embeddable_change_point_chart.tsx | 7 +- .../embeddable_change_point_chart_factory.ts | 14 +- .../embeddable_chart_component_wrapper.tsx | 68 ++++- .../embeddable/handle_explicit_input.tsx | 36 ++- .../plugins/aiops/public/embeddable/types.ts | 21 ++ .../aiops/public/hooks/use_data_source.tsx | 20 +- x-pack/plugins/aiops/public/plugin.tsx | 11 +- x-pack/plugins/aiops/public/types.ts | 4 +- .../edit_change_point_charts_panel.tsx | 59 ++++ .../plugins/aiops/public/ui_actions/index.ts | 22 ++ x-pack/plugins/aiops/tsconfig.json | 1 + 24 files changed, 862 insertions(+), 257 deletions(-) create mode 100644 x-pack/plugins/aiops/public/components/change_point_detection/max_series_control.tsx create mode 100644 x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx create mode 100644 x-pack/plugins/aiops/public/embeddable/types.ts create mode 100644 x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx create mode 100644 x-pack/plugins/aiops/public/ui_actions/index.ts diff --git a/x-pack/packages/ml/agg_utils/src/validate_number.ts b/x-pack/packages/ml/agg_utils/src/validate_number.ts index 5acfca3fd0234..15da7b250c324 100644 --- a/x-pack/packages/ml/agg_utils/src/validate_number.ts +++ b/x-pack/packages/ml/agg_utils/src/validate_number.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { memoize } from 'lodash'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export interface NumberValidationResult { @@ -29,7 +30,7 @@ export function numberValidator(conditions?: { throw new Error('Invalid validator conditions'); } - return (value: number): NumberValidationResult | null => { + return memoize((value: number): NumberValidationResult | null => { const result = {} as NumberValidationResult; if (conditions?.min !== undefined && value < conditions.min) { result.min = true; @@ -44,5 +45,5 @@ export function numberValidator(conditions?: { return result; } return null; - }; + }); } diff --git a/x-pack/plugins/aiops/kibana.jsonc b/x-pack/plugins/aiops/kibana.jsonc index 02558e7329093..9b787992c7c54 100644 --- a/x-pack/plugins/aiops/kibana.jsonc +++ b/x-pack/plugins/aiops/kibana.jsonc @@ -16,7 +16,8 @@ "embeddable", "presentationUtil", "dashboard", - "fieldFormats" + "fieldFormats", + "unifiedSearch" ], "optionalPlugins": [ "cases" diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_context.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_context.tsx index 7dcc96f59b05d..bd3b163fda585 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_context.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_context.tsx @@ -94,6 +94,46 @@ export interface ChangePointAnnotation { export type SelectedChangePoint = FieldConfig & ChangePointAnnotation; +export const ChangePointDetectionControlsContext = createContext<{ + metricFieldOptions: DataViewField[]; + splitFieldsOptions: DataViewField[]; +}>({ + splitFieldsOptions: [], + metricFieldOptions: [], +}); + +export const useChangePointDetectionControlsContext = () => { + return useContext(ChangePointDetectionControlsContext); +}; + +export const ChangePointDetectionControlsContextProvider: FC = ({ children }) => { + const { dataView } = useDataSource(); + + const metricFieldOptions = useMemo(() => { + return dataView.fields.filter(({ aggregatable, type }) => aggregatable && type === 'number'); + }, [dataView]); + + const splitFieldsOptions = useMemo(() => { + return dataView.fields.filter( + ({ aggregatable, esTypes, displayName }) => + aggregatable && + esTypes && + esTypes.some((el) => + [ES_FIELD_TYPES.KEYWORD, ES_FIELD_TYPES.IP].includes(el as ES_FIELD_TYPES) + ) && + !['_id', '_index'].includes(displayName) + ); + }, [dataView]); + + const value = { metricFieldOptions, splitFieldsOptions }; + + return ( + + {children} + + ); +}; + export const ChangePointDetectionContextProvider: FC = ({ children }) => { const { dataView, savedSearch } = useDataSource(); const { diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx index b207a1186a237..0e5c23ac21010 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx @@ -28,7 +28,10 @@ import { AIOPS_STORAGE_KEYS } from '../../types/storage'; import { PageHeader } from '../page_header'; import { ChangePointDetectionPage } from './change_point_detection_page'; -import { ChangePointDetectionContextProvider } from './change_point_detection_context'; +import { + ChangePointDetectionContextProvider, + ChangePointDetectionControlsContextProvider, +} from './change_point_detection_context'; import { timeSeriesDataViewWarning } from '../../application/utils/time_series_dataview_check'; import { ReloadContextProvider } from '../../hooks/use_reload'; @@ -87,7 +90,9 @@ export const ChangePointDetectionAppState: FC - + + + diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/chart_component.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/chart_component.tsx index 323f59c6c5646..0fb6a675c2bdc 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/chart_component.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/chart_component.tsx @@ -16,6 +16,8 @@ export interface ChartComponentProps { annotation: ChangePointAnnotation; interval: string; + + onLoading?: (isLoading: boolean) => void; } export interface ChartComponentPropsAll { @@ -29,7 +31,7 @@ export interface ChartComponentPropsAll { } export const ChartComponent: FC = React.memo( - ({ annotation, fieldConfig, interval }) => { + ({ annotation, fieldConfig, interval, onLoading }) => { const { lens: { EmbeddableComponent }, } = useAiopsAppContext(); @@ -55,6 +57,7 @@ export const ChartComponent: FC = React.memo( name: 'Change point detection', }} disableTriggers + onLoad={onLoading} /> ); } diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/charts_grid.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/charts_grid.tsx index 06879622a13fe..6cbda6c9ced9b 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/charts_grid.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/charts_grid.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { type FC, useMemo, useState, useEffect, useRef } from 'react'; +import React, { type FC, useMemo, useState, useEffect, useRef, useCallback } from 'react'; import { EuiBadge, EuiDescriptionList, @@ -42,10 +42,28 @@ interface ChartsGridProps { * @param changePoints * @constructor */ -export const ChartsGrid: FC<{ changePoints: SelectedChangePoint[]; interval: string }> = ({ - changePoints, - interval, -}) => { +export const ChartsGrid: FC<{ + changePoints: SelectedChangePoint[]; + interval: string; + onRenderComplete?: () => void; +}> = ({ changePoints, interval, onRenderComplete }) => { + // Render is complete when all chart components in the grid are ready + const loadCounter = useRef>( + Object.fromEntries(changePoints.map((v, i) => [i, true])) + ); + + const onLoadCallback = useCallback( + (chartId: number, isLoading: boolean) => { + if (!onRenderComplete) return; + loadCounter.current[chartId] = isLoading; + const isLoadComplete = Object.values(loadCounter.current).every((v) => !v); + if (isLoadComplete) { + onRenderComplete(); + } + }, + [onRenderComplete] + ); + return ( = 2 ? 2 : 1} @@ -122,6 +140,9 @@ export const ChartsGrid: FC<{ changePoints: SelectedChangePoint[]; interval: str fieldConfig={{ splitField: v.splitField, fn: v.fn, metricField: v.metricField }} annotation={v} interval={interval} + onLoading={(isLoading) => { + onLoadCallback(index, isLoading); + }} /> diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx index e2e0bf0a6d328..45b2ccc1c097a 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx @@ -11,18 +11,15 @@ import { EuiButtonIcon, EuiCallOut, EuiContextMenu, - EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, - EuiIcon, EuiPanel, EuiPopover, EuiProgress, EuiSpacer, EuiSwitch, - EuiToolTip, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -35,7 +32,7 @@ import { } from '@kbn/presentation-util-plugin/public'; import { EuiContextMenuProps } from '@elastic/eui/src/components/context_menu/context_menu'; import { isDefined } from '@kbn/ml-is-defined'; -import { numberValidator } from '@kbn/ml-agg-utils'; +import { MaxSeriesControl } from './max_series_control'; import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../../common/constants'; import { useCasesModal } from '../../hooks/use_cases_modal'; import { type EmbeddableChangePointChartInput } from '../../embeddable/embeddable_change_point_chart'; @@ -54,7 +51,6 @@ import { } from './change_point_detection_context'; import { useChangePointResults } from './use_change_point_agg_request'; import { useSplitFieldCardinality } from './use_split_field_cardinality'; -import { MAX_SERIES } from '../../embeddable/const'; const selectControlCss = { width: '350px' }; @@ -183,8 +179,8 @@ const FieldPanel: FC = ({ const splitFieldCardinality = useSplitFieldCardinality(fieldConfig.splitField, combinedQuery); const [isExpanded, setIsExpanded] = useState(true); - const [isActionMenuOpen, setIsActionMenuOpen] = useState(false); + const [isDashboardFormValid, setIsDashboardFormValid] = useState(true); const canEditDashboards = capabilities.dashboard?.createNew ?? false; const { create: canCreateCase, update: canUpdateCase } = cases?.helpers?.canUseCases() ?? { @@ -218,13 +214,6 @@ const FieldPanel: FC = ({ const timeRange = useTimeRangeUpdates(); - const maxSeriesValidator = useMemo( - () => numberValidator({ min: 1, max: MAX_SERIES, integerOnly: true }), - [] - ); - - const maxSeriesInvalid = maxSeriesValidator(dashboardAttachment.maxSeriesToPlot) !== null; - const panels = useMemo(() => { return [ { @@ -348,54 +337,20 @@ const FieldPanel: FC = ({ /> {isDefined(fieldConfig.splitField) && selectedPartitions.length === 0 ? ( - - } - label={ - - - - - - - - - - - } - > - - setDashboardAttachment((prevState) => { - return { - ...prevState, - maxSeriesToPlot: Number(e.target.value), - }; - }) - } - min={1} - max={MAX_SERIES} - /> - + { + setDashboardAttachment((prevState) => { + return { + ...prevState, + maxSeriesToPlot: v, + }; + }); + }} + onValidationChange={(result) => { + setIsDashboardFormValid(result === null); + }} + /> ) : null} @@ -405,7 +360,7 @@ const FieldPanel: FC = ({ type={'submit'} fullWidth onClick={setDashboardAttachmentReady.bind(null, true)} - disabled={maxSeriesInvalid} + disabled={!isDashboardFormValid} > = ({ fieldConfig.fn, fieldConfig.metricField, fieldConfig.splitField, + isDashboardFormValid, onRemove, openCasesModalCallback, removeDisabled, selectedPartitions, timeRange, - maxSeriesInvalid, ]); const onSaveCallback: SaveModalDashboardProps['onSave'] = useCallback( diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/max_series_control.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/max_series_control.tsx new file mode 100644 index 0000000000000..b7f98ca82f90e --- /dev/null +++ b/x-pack/plugins/aiops/public/components/change_point_detection/max_series_control.tsx @@ -0,0 +1,72 @@ +/* + * 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, { type FC } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiFieldNumber, EuiFormRow, EuiIcon, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { type NumberValidationResult, numberValidator } from '@kbn/ml-agg-utils'; +import { MAX_SERIES } from '../../embeddable/const'; + +const maxSeriesValidator = numberValidator({ min: 1, max: MAX_SERIES, integerOnly: true }); + +export const MaxSeriesControl: FC<{ + disabled?: boolean; + value: number; + onChange: (update: number) => void; + onValidationChange?: (result: NumberValidationResult | null) => void; + inline?: boolean; +}> = ({ value, onChange, onValidationChange, disabled, inline = true }) => { + const maxSeriesValidationResult = maxSeriesValidator(value); + const maxSeriesInvalid = maxSeriesValidationResult !== null; + + const label = i18n.translate('xpack.aiops.changePointDetection.maxSeriesToPlotLabel', { + defaultMessage: 'Max series', + }); + + return ( + + } + label={inline ? undefined : label} + > + + + + } + compressed + fullWidth + isInvalid={maxSeriesInvalid} + value={value} + onChange={(e) => { + const newValue = Number(e.target.value); + onChange(newValue); + if (onValidationChange) { + onValidationChange(maxSeriesValidator(newValue)); + } + }} + min={1} + max={MAX_SERIES} + /> + + ); +}; diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/metric_field_selector.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/metric_field_selector.tsx index 3b0d0017fb499..2f2db17ee6afc 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/metric_field_selector.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/metric_field_selector.tsx @@ -8,22 +8,23 @@ import React, { type FC, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiComboBox, type EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; -import { useChangePointDetectionContext } from './change_point_detection_context'; +import { useChangePointDetectionControlsContext } from './change_point_detection_context'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; interface MetricFieldSelectorProps { value: string; onChange: (value: string) => void; + inline?: boolean; } export const MetricFieldSelector: FC = React.memo( - ({ value, onChange }) => { + ({ value, onChange, inline = true }) => { const { fieldStats } = useAiopsAppContext(); - const { metricFieldOptions } = useChangePointDetectionContext(); + const { metricFieldOptions } = useChangePointDetectionControlsContext(); - const { renderOption, closeFlyout } = fieldStats!.useFieldStatsTrigger(); + const { renderOption, closeFlyout } = fieldStats?.useFieldStatsTrigger() ?? {}; - const options = useMemo(() => { + const options = useMemo>>(() => { return metricFieldOptions.map((v) => { return { value: v.name, @@ -41,26 +42,30 @@ export const MetricFieldSelector: FC = React.memo( if (typeof option !== 'undefined') { onChange(option.value as string); } - closeFlyout(); + if (closeFlyout) { + closeFlyout(); + } }, [onChange, closeFlyout] ); + const label = i18n.translate('xpack.aiops.changePointDetection.selectMetricFieldLabel', { + defaultMessage: 'Metric field', + }); + return ( <> - + diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx new file mode 100644 index 0000000000000..6e040c7d77e62 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx @@ -0,0 +1,192 @@ +/* + * 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, { type FC, useState, useCallback, useMemo, useEffect } from 'react'; +import { EuiComboBox, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { type SearchRequest } from '@elastic/elasticsearch/lib/api/types'; +import { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types'; +import { debounce } from 'lodash'; +import usePrevious from 'react-use/lib/usePrevious'; +import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; +import { useCancellableSearch } from '../../hooks/use_cancellable_search'; +import { useDataSource } from '../../hooks/use_data_source'; + +export interface PartitionsSelectorProps { + splitField: string; + value: string[]; + onChange: (update: string[]) => void; + enableSearch?: boolean; +} + +function getQueryPayload( + indexPattern: string, + fieldName: string, + queryString: string = '', + selectedPartitions?: string[] +) { + return { + params: { + index: indexPattern, + size: 0, + ...(selectedPartitions?.length + ? { + query: { + bool: { + must_not: [ + { + terms: { + [fieldName]: selectedPartitions, + }, + }, + ], + }, + }, + } + : {}), + aggs: { + aggResults: { + filter: { + bool: { + must: { + wildcard: { + [fieldName]: { + value: `*${queryString}*`, + }, + }, + }, + }, + }, + aggs: { + partitionValues: { + terms: { + field: fieldName, + }, + }, + }, + }, + }, + } as SearchRequest, + }; +} + +interface PartitionsResponse { + aggregations: { + aggResults: { + partitionValues: { buckets: Array<{ key: string }> }; + }; + }; +} + +export const PartitionsSelector: FC = ({ + value, + onChange, + splitField, + enableSearch = true, +}) => { + const { dataView } = useDataSource(); + const { + notifications: { toasts }, + } = useAiopsAppContext(); + const prevSplitField = usePrevious(splitField); + const [options, setOptions] = useState>>([]); + const [isLoading, setIsLoading] = useState(enableSearch); + const { runRequest, cancelRequest } = useCancellableSearch(); + + const fetchResults = useCallback( + async (searchValue: string) => { + if (!enableSearch) return; + + cancelRequest(); + setIsLoading(true); + try { + const requestPayload = getQueryPayload( + dataView.getIndexPattern(), + splitField, + searchValue, + value + ); + + const result = await runRequest( + requestPayload + ); + + if (result === null) { + setOptions([]); + return; + } + + setOptions( + result.rawResponse.aggregations.aggResults.partitionValues.buckets.map((v) => ({ + value: v.key, + label: v.key, + })) + ); + } catch (e) { + toasts.addError(e, { + title: i18n.translate('xpack.aiops.changePointDetection.fetchPartitionsErrorTitle', { + defaultMessage: 'Failed to fetch partitions', + }), + }); + } + setIsLoading(false); + }, + [enableSearch, cancelRequest, dataView, splitField, value, runRequest, toasts] + ); + + useEffect( + function onSplitFieldChange() { + if (splitField !== prevSplitField) { + fetchResults(''); + onChange([]); + } + }, + [splitField, prevSplitField, fetchResults, onChange] + ); + + const selectedOptions = useMemo>>(() => { + return value.map((v) => ({ value: v, label: v })); + }, [value]); + + const onChangeCallback = useCallback( + (udpate: EuiComboBoxOptionOption[]) => { + onChange(udpate.map((v) => v.value as string)); + }, + [onChange] + ); + + const onSearchChange = useMemo(() => debounce(fetchResults, 500), [fetchResults]); + + const onCreateOption = useCallback( + (v: string) => { + onChange([...value, v]); + }, + [onChange, value] + ); + + return ( + + + isLoading={isLoading} + fullWidth + compressed + options={options} + selectedOptions={selectedOptions} + onChange={onChangeCallback} + onSearchChange={enableSearch ? onSearchChange : undefined} + onCreateOption={!enableSearch ? onCreateOption : undefined} + isClearable + data-test-subj="aiopsChangePointPartitions" + /> + + ); +}; diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/split_field_selector.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/split_field_selector.tsx index 6d8540565015d..7fc672a1abe41 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/split_field_selector.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/split_field_selector.tsx @@ -9,63 +9,70 @@ import React, { FC, useMemo, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiComboBox, type EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; -import { useChangePointDetectionContext } from './change_point_detection_context'; +import { useChangePointDetectionControlsContext } from './change_point_detection_context'; interface SplitFieldSelectorProps { value: string | undefined; onChange: (value: string | undefined) => void; + inline?: boolean; } -export const SplitFieldSelector: FC = React.memo(({ value, onChange }) => { - const { fieldStats } = useAiopsAppContext(); - const { renderOption, closeFlyout } = fieldStats!.useFieldStatsTrigger(); +export const SplitFieldSelector: FC = React.memo( + ({ value, onChange, inline = true }) => { + const { fieldStats } = useAiopsAppContext(); + const { renderOption, closeFlyout } = fieldStats?.useFieldStatsTrigger() ?? {}; - const { splitFieldsOptions } = useChangePointDetectionContext(); + const { splitFieldsOptions } = useChangePointDetectionControlsContext(); - const options = useMemo(() => { - return [ - { - value: undefined, - label: i18n.translate('xpack.aiops.changePointDetection.notSelectedSplitFieldLabel', { - defaultMessage: '--- Not selected ---', - }), - }, - ...splitFieldsOptions.map((v) => ({ - value: v.name, - label: v.displayName, - ...(v.name ? { field: { id: v.name, type: v?.type } } : {}), - })), - ]; - }, [splitFieldsOptions]); + const options = useMemo>>(() => { + return [ + { + value: undefined, + label: i18n.translate('xpack.aiops.changePointDetection.notSelectedSplitFieldLabel', { + defaultMessage: '--- Not selected ---', + }), + }, + ...splitFieldsOptions.map((v) => ({ + value: v.name, + label: v.displayName, + ...(v.name ? { field: { id: v.name, type: v?.type } } : {}), + })), + ]; + }, [splitFieldsOptions]); + + const selection = options.filter((v) => v.value === value); - const selection = options.filter((v) => v.value === value); + const onChangeCallback = useCallback( + (selectedOptions: EuiComboBoxOptionOption[]) => { + const option = selectedOptions[0]; + const newValue = option?.value as string; + onChange(newValue); + if (closeFlyout) { + closeFlyout(); + } + }, + [onChange, closeFlyout] + ); - const onChangeCallback = useCallback( - (selectedOptions: EuiComboBoxOptionOption[]) => { - const option = selectedOptions[0]; - const newValue = option?.value as string; - onChange(newValue); - closeFlyout(); - }, - [onChange, closeFlyout] - ); + const label = i18n.translate('xpack.aiops.changePointDetection.selectSpitFieldLabel', { + defaultMessage: 'Split field', + }); - return ( - - - - ); -}); + return ( + + + + ); + } +); diff --git a/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx b/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx index b16f5dde6a406..50488c06cec7c 100644 --- a/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx +++ b/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx @@ -5,59 +5,97 @@ * 2.0. */ -import React, { FC, useState } from 'react'; +import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { EuiButton, EuiButtonEmpty, EuiForm, EuiFormRow, + EuiHorizontalRule, + EuiModal, EuiModalBody, EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiFieldNumber, - EuiFieldText, - EuiModal, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import usePrevious from 'react-use/lib/usePrevious'; +import { pick } from 'lodash'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; +import { ES_FIELD_TYPES } from '@kbn/field-types'; +import { PartitionsSelector } from '../components/change_point_detection/partitions_selector'; +import { DEFAULT_SERIES } from './const'; +import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart_component'; +import { type EmbeddableChangePointChartExplicitInput } from './types'; +import { MaxSeriesControl } from '../components/change_point_detection/max_series_control'; +import { SplitFieldSelector } from '../components/change_point_detection/split_field_selector'; +import { MetricFieldSelector } from '../components/change_point_detection/metric_field_selector'; +import { + ChangePointDetectionControlsContextProvider, + useChangePointDetectionControlsContext, +} from '../components/change_point_detection/change_point_detection_context'; +import { useAiopsAppContext } from '../hooks/use_aiops_app_context'; import { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; import { FunctionPicker } from '../components/change_point_detection/function_picker'; - -export const MAX_ANOMALY_CHARTS_ALLOWED = 50; - -export const DEFAULT_MAX_SERIES_TO_PLOT = 6; +import { DataSourceContextProvider } from '../hooks/use_data_source'; +import { DEFAULT_AGG_FUNCTION } from '../components/change_point_detection/constants'; export interface AnomalyChartsInitializerProps { - defaultTitle: string; initialInput?: Partial; - onCreate: (props: { panelTitle: string; maxSeriesToPlot?: number }) => void; + onCreate: (props: EmbeddableChangePointChartExplicitInput) => void; onCancel: () => void; } export const ChangePointChartInitializer: FC = ({ - defaultTitle, initialInput, onCreate, onCancel, }) => { - const [panelTitle, setPanelTitle] = useState(defaultTitle); - const [maxSeriesToPlot, setMaxSeriesToPlot] = useState( - initialInput?.maxSeriesToPlot ?? DEFAULT_MAX_SERIES_TO_PLOT + const { + unifiedSearch: { + ui: { IndexPatternSelect }, + }, + } = useAiopsAppContext(); + + const [dataViewId, setDataViewId] = useState(initialInput?.dataViewId ?? ''); + + const [formInput, setFormInput] = useState( + pick(initialInput ?? {}, [ + 'fn', + 'metricField', + 'splitField', + 'maxSeriesToPlot', + 'partitions', + ]) as FormControlsProps ); - const [fn, setFn] = useState(initialInput?.fn ?? 'avg'); + const [isFormValid, setIsFormValid] = useState(true); - const isPanelTitleValid = panelTitle.length > 0; - const isMaxSeriesToPlotValid = - maxSeriesToPlot >= 1 && maxSeriesToPlot <= MAX_ANOMALY_CHARTS_ALLOWED; - const isFormValid = isPanelTitleValid && isMaxSeriesToPlotValid; + const updatedProps = useMemo(() => { + return { + ...formInput, + title: isPopulatedObject(formInput) + ? i18n.translate('xpack.aiops.changePointDetection.attachmentTitle', { + defaultMessage: 'Change point: {function}({metric}){splitBy}', + values: { + function: formInput.fn, + metric: formInput?.metricField, + splitBy: formInput?.splitField + ? i18n.translate('xpack.aiops.changePointDetection.splitByTitle', { + defaultMessage: ' split by "{splitField}"', + values: { splitField: formInput.splitField }, + }) + : '', + }, + }) + : '', + dataViewId, + }; + }, [formInput, dataViewId]); return ( - + = ({ - } - isInvalid={!isPanelTitleValid} + fullWidth + label={i18n.translate('xpack.aiops.embeddableChangePointChart.dataViewLabel', { + defaultMessage: 'Data view', + })} > - setPanelTitle(e.target.value)} - isInvalid={!isPanelTitleValid} + { + setDataViewId(newId ?? ''); + }} /> - + + + - } - > - - - - - ) : undefined - } - label={ - - } - > - setMaxSeriesToPlot(parseInt(e.target.value, 10))} - min={1} - max={MAX_ANOMALY_CHARTS_ALLOWED} - /> - + + - + = ({ = ({ ); }; + +export type FormControlsProps = Pick< + EmbeddableChangePointChartProps, + 'metricField' | 'splitField' | 'fn' | 'maxSeriesToPlot' | 'partitions' +>; + +export const FormControls: FC<{ + formInput?: FormControlsProps; + onChange: (update: FormControlsProps) => void; + onValidationChange: (isValid: boolean) => void; +}> = ({ formInput, onChange, onValidationChange }) => { + const { metricFieldOptions, splitFieldsOptions } = useChangePointDetectionControlsContext(); + const prevMetricFieldOptions = usePrevious(metricFieldOptions); + + const enableSearch = useMemo(() => { + const field = splitFieldsOptions.find((v) => v.name === formInput?.splitField); + if (field && field.esTypes) { + return field.esTypes?.some((t) => t === ES_FIELD_TYPES.KEYWORD); + } else { + return false; + } + }, [splitFieldsOptions, formInput?.splitField]); + + useEffect( + function setDefaultOnDataViewChange() { + if (!isPopulatedObject(formInput)) { + onChange({ + fn: DEFAULT_AGG_FUNCTION, + metricField: metricFieldOptions[0]?.name, + splitField: undefined, + partitions: undefined, + maxSeriesToPlot: DEFAULT_SERIES, + }); + return; + } + + if (metricFieldOptions === prevMetricFieldOptions) return; + + onChange({ + fn: formInput.fn, + metricField: metricFieldOptions[0]?.name, + splitField: undefined, + partitions: undefined, + maxSeriesToPlot: formInput.maxSeriesToPlot, + }); + }, + [metricFieldOptions, prevMetricFieldOptions, formInput, onChange] + ); + + const updateCallback = useCallback( + (update: Partial) => { + onChange({ + ...formInput, + ...update, + } as FormControlsProps); + }, + [formInput, onChange] + ); + + if (!isPopulatedObject(formInput)) return null; + + return ( + <> + + } + > + updateCallback({ fn: v })} /> + + + updateCallback({ metricField: v })} + /> + + updateCallback({ splitField: v })} + /> + + {formInput.splitField ? ( + updateCallback({ partitions: v })} + splitField={formInput.splitField} + enableSearch={enableSearch} + /> + ) : null} + + updateCallback({ maxSeriesToPlot: v })} + onValidationChange={(result) => onValidationChange(result === null)} + /> + + ); +}; diff --git a/x-pack/plugins/aiops/public/embeddable/const.ts b/x-pack/plugins/aiops/public/embeddable/const.ts index ef655dd25bd7a..d7031b34f2d1e 100644 --- a/x-pack/plugins/aiops/public/embeddable/const.ts +++ b/x-pack/plugins/aiops/public/embeddable/const.ts @@ -6,3 +6,5 @@ */ export const MAX_SERIES = 50; + +export const DEFAULT_SERIES = 6; diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx index 1db2088867497..86bb933bea360 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx @@ -21,6 +21,7 @@ import { DatePickerContextProvider } from '@kbn/ml-date-picker'; import { pick } from 'lodash'; import { LensPublicStart } from '@kbn/lens-plugin/public'; import { Subject } from 'rxjs'; +import type { DataView } from '@kbn/data-views-plugin/common'; import { EmbeddableInputTracker } from './embeddable_chart_component_wrapper'; import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../common/constants'; import { AiopsAppContext, type AiopsAppDependencies } from '../hooks/use_aiops_app_context'; @@ -29,7 +30,7 @@ import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart export type EmbeddableChangePointChartInput = EmbeddableInput & EmbeddableChangePointChartProps; -export type EmbeddableChangePointChartOutput = EmbeddableOutput; +export type EmbeddableChangePointChartOutput = EmbeddableOutput & { indexPatterns?: DataView[] }; export interface EmbeddableChangePointChartDeps { theme: ThemeServiceStart; @@ -113,6 +114,10 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable< input$={input$} initialInput={input} reload$={this.reload$} + onOutputChange={this.updateOutput.bind(this)} + onRenderComplete={this.onRenderComplete.bind(this)} + onLoading={this.onLoading.bind(this)} + onError={this.onError.bind(this)} /> diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts index 348f50659a932..9bf35b0ca2b1a 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts @@ -44,11 +44,8 @@ export class EmbeddableChangePointChartFactory implements EmbeddableFactoryDefin private readonly getStartServices: StartServicesAccessor ) {} - /** - * TODO - */ public isEditable = async () => { - return false; + return true; }; getDisplayName() { @@ -57,19 +54,16 @@ export class EmbeddableChangePointChartFactory implements EmbeddableFactoryDefin }); } - /** - * TODO - */ canCreateNew() { - return false; + return true; } public async getExplicitInput(): Promise> { - const [coreStart] = await this.getStartServices(); + const [coreStart, pluginStart] = await this.getStartServices(); try { const { resolveEmbeddableChangePointUserInput } = await import('./handle_explicit_input'); - return await resolveEmbeddableChangePointUserInput(coreStart); + return await resolveEmbeddableChangePointUserInput(coreStart, pluginStart); } catch (e) { return Promise.reject(); } diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx index a856aec67e924..3cc8a6d6e47a0 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx @@ -6,7 +6,7 @@ */ import { type Observable } from 'rxjs'; -import React, { FC, useMemo } from 'react'; +import React, { FC, useCallback, useEffect, useMemo } from 'react'; import { useTimefilter } from '@kbn/ml-date-picker'; import { css } from '@emotion/react'; import useObservable from 'react-use/lib/useObservable'; @@ -15,10 +15,17 @@ import type { ChangePointAnnotation, ChangePointDetectionRequestParams, } from '../components/change_point_detection/change_point_detection_context'; -import { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; +import type { + EmbeddableChangePointChartInput, + EmbeddableChangePointChartOutput, +} from './embeddable_change_point_chart'; import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart_component'; import { FilterQueryContextProvider, useFilerQueryUpdates } from '../hooks/use_filters_query'; -import { DataSourceContextProvider, useDataSource } from '../hooks/use_data_source'; +import { + DataSourceContextProvider, + type DataSourceContextProviderProps, + useDataSource, +} from '../hooks/use_data_source'; import { useAiopsAppContext } from '../hooks/use_aiops_app_context'; import { useTimeBuckets } from '../hooks/use_time_buckets'; import { createMergedEsQuery } from '../application/utils/search_utils'; @@ -31,16 +38,37 @@ const defaultSort = { direction: 'asc', }; -export const EmbeddableInputTracker: FC<{ +export interface EmbeddableInputTrackerProps { input$: Observable; initialInput: EmbeddableChangePointChartInput; reload$: Observable; -}> = ({ input$, initialInput, reload$ }) => { + onOutputChange: (output: Partial) => void; + onRenderComplete: () => void; + onLoading: () => void; + onError: (error: Error) => void; +} + +export const EmbeddableInputTracker: FC = ({ + input$, + initialInput, + reload$, + onOutputChange, + onRenderComplete, + onLoading, + onError, +}) => { const input = useObservable(input$, initialInput); + const onChange = useCallback>( + ({ dataViews }) => { + onOutputChange({ indexPatterns: dataViews }); + }, + [onOutputChange] + ); + return ( - + @@ -68,12 +99,21 @@ export const EmbeddableInputTracker: FC<{ * @param partitions * @constructor */ -export const ChartGridEmbeddableWrapper: FC = ({ +export const ChartGridEmbeddableWrapper: FC< + EmbeddableChangePointChartProps & { + onRenderComplete: () => void; + onLoading: () => void; + onError: (error: Error) => void; + } +> = ({ fn, metricField, maxSeriesToPlot, splitField, partitions, + onError, + onLoading, + onRenderComplete, }) => { const { filters, query, timeRange } = useFilerQueryUpdates(); @@ -134,7 +174,18 @@ export const ChartGridEmbeddableWrapper: FC = ( return { interval } as ChangePointDetectionRequestParams; }, [interval]); - const { results } = useChangePointResults(fieldConfig, requestParams, combinedQuery, 10000); + const { results, isLoading } = useChangePointResults( + fieldConfig, + requestParams, + combinedQuery, + 10000 + ); + + useEffect(() => { + if (isLoading) { + onLoading(); + } + }, [onLoading, isLoading]); const changePoints = useMemo(() => { let resultChangePoints: ChangePointAnnotation[] = results.sort((a, b) => { @@ -163,6 +214,7 @@ export const ChartGridEmbeddableWrapper: FC = ( ({ ...r, ...fieldConfig }))} interval={requestParams.interval} + onRenderComplete={onRenderComplete} /> ) : ( diff --git a/x-pack/plugins/aiops/public/embeddable/handle_explicit_input.tsx b/x-pack/plugins/aiops/public/embeddable/handle_explicit_input.tsx index 20027c10cd22e..16dfd6f3c1c0f 100644 --- a/x-pack/plugins/aiops/public/embeddable/handle_explicit_input.tsx +++ b/x-pack/plugins/aiops/public/embeddable/handle_explicit_input.tsx @@ -6,41 +6,47 @@ */ import type { CoreStart } from '@kbn/core/public'; -import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import React from 'react'; +import { EmbeddableChangePointChartExplicitInput } from './types'; +import { AiopsAppDependencies } from '..'; +import { AiopsAppContext } from '../hooks/use_aiops_app_context'; +import type { AiopsPluginStartDeps } from '../types'; import { ChangePointChartInitializer } from './change_point_chart_initializer'; -import { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; +import type { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; export async function resolveEmbeddableChangePointUserInput( coreStart: CoreStart, + pluginStart: AiopsPluginStartDeps, input?: EmbeddableChangePointChartInput -): Promise> { +): Promise { const { overlays } = coreStart; return new Promise(async (resolve, reject) => { try { - const title = input?.title; - const { theme$ } = coreStart.theme; const modalSession = overlays.openModal( toMountPoint( - wrapWithTheme( + { + onCreate={(update: EmbeddableChangePointChartExplicitInput) => { modalSession.close(); - resolve({ - title: panelTitle, - maxSeriesToPlot, - }); + resolve(update); }} onCancel={() => { modalSession.close(); reject(); }} - />, - theme$ - ) + /> + , + { theme: coreStart.theme, i18n: coreStart.i18n } ) ); } catch (error) { diff --git a/x-pack/plugins/aiops/public/embeddable/types.ts b/x-pack/plugins/aiops/public/embeddable/types.ts new file mode 100644 index 0000000000000..0184c2e4fa3eb --- /dev/null +++ b/x-pack/plugins/aiops/public/embeddable/types.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IEmbeddable } from '@kbn/embeddable-plugin/public'; +import { + EmbeddableChangePointChartInput, + EmbeddableChangePointChartOutput, +} from './embeddable_change_point_chart'; +import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart_component'; + +export type EmbeddableChangePointChartExplicitInput = { + title: string; +} & Omit; + +export interface EditChangePointChartsPanelContext { + embeddable: IEmbeddable; +} diff --git a/x-pack/plugins/aiops/public/hooks/use_data_source.tsx b/x-pack/plugins/aiops/public/hooks/use_data_source.tsx index 68502f8e2648e..e0fd8a431df53 100644 --- a/x-pack/plugins/aiops/public/hooks/use_data_source.tsx +++ b/x-pack/plugins/aiops/public/hooks/use_data_source.tsx @@ -28,16 +28,24 @@ export interface DataViewAndSavedSearch { dataView: DataView; } +export interface DataSourceContextProviderProps { + dataViewId?: string; + savedSearchId?: string; + /** Output resolves data view objects */ + onChange?: (update: { dataViews: DataView[] }) => void; +} + /** * Context provider that resolves current data view and the saved search * * @param children * @constructor */ -export const DataSourceContextProvider: FC<{ dataViewId?: string; savedSearchId?: string }> = ({ +export const DataSourceContextProvider: FC = ({ dataViewId, savedSearchId, children, + onChange, }) => { const [value, setValue] = useState(); const [error, setError] = useState(); @@ -59,7 +67,7 @@ export const DataSourceContextProvider: FC<{ dataViewId?: string; savedSearchId? }; // support only data views for now - if (dataViewId !== undefined) { + if (dataViewId) { dataViewAndSavedSearch.dataView = await dataViews.get(dataViewId); } @@ -74,14 +82,18 @@ export const DataSourceContextProvider: FC<{ dataViewId?: string; savedSearchId? useEffect(() => { resolveDataSource() .then((result) => { + setError(undefined); setValue(result); + if (onChange) { + onChange({ dataViews: [result.dataView] }); + } }) .catch((e) => { setError(e); }); - }, [resolveDataSource]); + }, [resolveDataSource, onChange, dataViewId]); - if (!value && !error) return null; + if ((!value || !value?.dataView) && !error) return null; if (error) { return ( diff --git a/x-pack/plugins/aiops/public/plugin.tsx b/x-pack/plugins/aiops/public/plugin.tsx index 0023d2f2baa9e..c896ccc7d5b3e 100755 --- a/x-pack/plugins/aiops/public/plugin.tsx +++ b/x-pack/plugins/aiops/public/plugin.tsx @@ -16,12 +16,14 @@ import type { } from './types'; import { getEmbeddableChangePointChart } from './embeddable/embeddable_change_point_chart_component'; +export type AiopsCoreSetup = CoreSetup; + export class AiopsPlugin implements Plugin { public setup( - core: CoreSetup, - { embeddable, cases, licensing }: AiopsPluginSetupDeps + core: AiopsCoreSetup, + { embeddable, cases, licensing, uiActions }: AiopsPluginSetupDeps ) { firstValueFrom(licensing.license$).then(async (license) => { if (license.hasAtLeast('platinum')) { @@ -30,6 +32,11 @@ export class AiopsPlugin registerEmbeddable(core, embeddable); } + if (uiActions) { + const { registerAiopsUiActions } = await import('./ui_actions'); + registerAiopsUiActions(uiActions, core); + } + if (cases) { const [coreStart, pluginStart] = await core.getStartServices(); const { registerChangePointChartsAttachment } = await import( diff --git a/x-pack/plugins/aiops/public/types.ts b/x-pack/plugins/aiops/public/types.ts index 10cec5ae49df8..9c28951c25c99 100755 --- a/x-pack/plugins/aiops/public/types.ts +++ b/x-pack/plugins/aiops/public/types.ts @@ -13,7 +13,7 @@ import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; -import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import type { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { CasesUiSetup } from '@kbn/cases-plugin/public'; @@ -24,6 +24,8 @@ export interface AiopsPluginSetupDeps { embeddable: EmbeddableSetup; cases: CasesUiSetup; licensing: LicensingPluginSetup; + + uiActions: UiActionsSetup; } export interface AiopsPluginStartDeps { diff --git a/x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx b/x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx new file mode 100644 index 0000000000000..ae50937921f33 --- /dev/null +++ b/x-pack/plugins/aiops/public/ui_actions/edit_change_point_charts_panel.tsx @@ -0,0 +1,59 @@ +/* + * 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 { UiActionsActionDefinition } from '@kbn/ui-actions-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { ViewMode } from '@kbn/embeddable-plugin/common'; +import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../common/constants'; +import type { EditChangePointChartsPanelContext } from '../embeddable/types'; +import type { AiopsCoreSetup } from '../plugin'; + +export const EDIT_CHANGE_POINT_CHARTS_ACTION = 'editChangePointChartsPanelAction'; + +export function createEditChangePointChartsPanelAction( + getStartServices: AiopsCoreSetup['getStartServices'] +): UiActionsActionDefinition { + return { + id: 'edit-change-point-charts', + type: EDIT_CHANGE_POINT_CHARTS_ACTION, + getIconType(context): string { + return 'pencil'; + }, + getDisplayName: () => + i18n.translate('xpack.aiops.actions.editChangePointChartsName', { + defaultMessage: 'Edit change point charts', + }), + async execute({ embeddable }) { + if (!embeddable) { + throw new Error('Not possible to execute an action without the embeddable context'); + } + + const [coreStart, pluginStart] = await getStartServices(); + + try { + const { resolveEmbeddableChangePointUserInput } = await import( + '../embeddable/handle_explicit_input' + ); + + const result = await resolveEmbeddableChangePointUserInput( + coreStart, + pluginStart, + embeddable.getInput() + ); + embeddable.updateInput(result); + } catch (e) { + return Promise.reject(); + } + }, + async isCompatible({ embeddable }) { + return ( + embeddable.type === EMBEDDABLE_CHANGE_POINT_CHART_TYPE && + embeddable.getInput().viewMode === ViewMode.EDIT + ); + }, + }; +} diff --git a/x-pack/plugins/aiops/public/ui_actions/index.ts b/x-pack/plugins/aiops/public/ui_actions/index.ts new file mode 100644 index 0000000000000..cd00842c662c8 --- /dev/null +++ b/x-pack/plugins/aiops/public/ui_actions/index.ts @@ -0,0 +1,22 @@ +/* + * 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 { UiActionsSetup } from '@kbn/ui-actions-plugin/public'; +import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; +import { createEditChangePointChartsPanelAction } from './edit_change_point_charts_panel'; +import type { AiopsCoreSetup } from '../plugin'; + +export function registerAiopsUiActions(uiActions: UiActionsSetup, core: AiopsCoreSetup) { + // Initialize actions + const editChangePointChartPanelAction = createEditChangePointChartsPanelAction( + core.getStartServices + ); + // Register actions + uiActions.registerAction(editChangePointChartPanelAction); + // Assign and register triggers + uiActions.attachAction(CONTEXT_MENU_TRIGGER, editChangePointChartPanelAction.id); +} diff --git a/x-pack/plugins/aiops/tsconfig.json b/x-pack/plugins/aiops/tsconfig.json index dd9dc07a3b33a..6ee1275439d6e 100644 --- a/x-pack/plugins/aiops/tsconfig.json +++ b/x-pack/plugins/aiops/tsconfig.json @@ -62,6 +62,7 @@ "@kbn/core-theme-browser", "@kbn/core-lifecycle-browser", "@kbn/cases-plugin", + "@kbn/react-kibana-mount", ], "exclude": [ "target/**/*", From a13b6787b0c013d976d502b015a4dc1b39f485b2 Mon Sep 17 00:00:00 2001 From: Brandon Kobel Date: Tue, 15 Aug 2023 13:14:48 -0400 Subject: [PATCH 07/10] Adding serverless circuit breakers for alerting rules and actions (#163835) ## Summary Setting circuit breakers for alerting rules and actions as previously agreed upon in: [2023-07 Serverless Alerting Circuit Breakers](https://docs.google.com/document/d/1Ux5IMgay5G0fAmYpVPr6WTFtE9yhutFYf_dPAfEPa5s/edit) --- config/serverless.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config/serverless.yml b/config/serverless.yml index 96cdcd7f52d15..ac1af15dc673e 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -97,3 +97,12 @@ xpack.graph.enabled: false # Disable cases in stack management xpack.cases.stack.enabled: false + +# Alerting and action circuit breakers +xpack.alerting.rules.run.actions.max: 3000 +xpack.alerting.rules.run.timeout: 1m +xpack.alerting.rules.run.ruleTypeOverrides: + - id: siem.indicatorRule + timeout: 1m +xpack.alerting.rules.minimumScheduleInterval.enforce: true +xpack.actions.run.maxAttempts: 10 From c180112b099e14b0f2581a495768ab34404123e9 Mon Sep 17 00:00:00 2001 From: Bena Kansara <69037875+benakansara@users.noreply.github.com> Date: Tue, 15 Aug 2023 19:21:55 +0200 Subject: [PATCH 08/10] Add KQL filtering in APM rules (#163825) Resolves https://github.com/elastic/apm-dev/issues/929 Adds KQL filtering to the following APM rules: - Latency threshold rule - Failed transaction rate rule - Error count threshold rule ### KQL Filter ON Screenshot 2023-07-31 at 16 45 13 ### KQL Filter OFF Screenshot 2023-07-31 at 16 47 23 ### Note Opening a new PR as https://github.com/elastic/kibana/pull/163307 pinged many teams after merging to main. Removing teams from reviewers list doesn't unsubscribe them from notifications. --- x-pack/plugins/apm/common/rules/schema.ts | 6 + .../error_count_rule_type/index.stories.tsx | 19 +- .../error_count_rule_type/index.tsx | 38 ++- .../index.stories.tsx | 10 +- .../transaction_duration_rule_type/index.tsx | 40 ++- .../index.stories.tsx | 8 +- .../index.tsx | 40 ++- .../ui_components/apm_rule_kql_filter.tsx | 109 +++++++ .../apm_rule_params_container/index.tsx | 6 +- .../plugins/apm/server/routes/alerts/route.ts | 1 + .../get_error_count_chart_preview.ts | 22 +- .../register_error_count_rule_type.test.ts | 64 +++++ .../register_error_count_rule_type.ts | 26 +- .../get_transaction_duration_chart_preview.ts | 23 +- ...ter_transaction_duration_rule_type.test.ts | 66 +++++ ...register_transaction_duration_rule_type.ts | 32 ++- ...et_transaction_error_rate_chart_preview.ts | 34 ++- ...r_transaction_error_rate_rule_type.test.ts | 79 +++++ ...gister_transaction_error_rate_rule_type.ts | 32 ++- .../autocomplete_field/autocomplete_field.tsx | 4 +- .../autocomplete_field/index.ts | 0 .../autocomplete_field/suggestion_item.tsx | 0 .../kuery_bar.tsx | 14 +- .../with_kuery_autocompletion.tsx | 2 +- .../custom_equation/metric_row_with_agg.tsx | 4 +- .../threshold/threshold_rule_expression.tsx | 12 +- x-pack/plugins/observability/public/index.ts | 3 + x-pack/plugins/observability/server/index.ts | 1 + .../lib/rules/threshold/lib/metric_query.ts | 15 +- .../server/utils/get_parsed_filtered_query.ts | 21 ++ .../alerts/error_count_threshold.spec.ts | 173 +++++++++-- .../alerts/preview_chart_error_count.spec.ts | 264 ++++++++++++++++- .../alerts/preview_chart_error_rate.spec.ts | 258 +++++++++++++++++ ...preview_chart_transaction_duration.spec.ts | 272 ++++++++++++++++-- .../tests/alerts/transaction_duration.spec.ts | 148 ++++++++-- .../alerts/transaction_error_rate.spec.ts | 160 +++++++++-- 36 files changed, 1814 insertions(+), 192 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_kql_filter.tsx rename x-pack/plugins/observability/public/components/{threshold/components => rule_kql_filter}/autocomplete_field/autocomplete_field.tsx (98%) rename x-pack/plugins/observability/public/components/{threshold/components => rule_kql_filter}/autocomplete_field/index.ts (100%) rename x-pack/plugins/observability/public/components/{threshold/components => rule_kql_filter}/autocomplete_field/suggestion_item.tsx (100%) rename x-pack/plugins/observability/public/components/{threshold/components => rule_kql_filter}/kuery_bar.tsx (85%) rename x-pack/plugins/observability/public/components/{threshold/containers => rule_kql_filter}/with_kuery_autocompletion.tsx (97%) create mode 100644 x-pack/plugins/observability/server/utils/get_parsed_filtered_query.ts diff --git a/x-pack/plugins/apm/common/rules/schema.ts b/x-pack/plugins/apm/common/rules/schema.ts index 889324326bbd6..02fb3a458015a 100644 --- a/x-pack/plugins/apm/common/rules/schema.ts +++ b/x-pack/plugins/apm/common/rules/schema.ts @@ -17,6 +17,8 @@ export const errorCountParamsSchema = schema.object({ environment: schema.string(), groupBy: schema.maybe(schema.arrayOf(schema.string())), errorGroupingKey: schema.maybe(schema.string()), + useKqlFilter: schema.maybe(schema.boolean()), + kqlFilter: schema.maybe(schema.string()), }); export const transactionDurationParamsSchema = schema.object({ @@ -33,6 +35,8 @@ export const transactionDurationParamsSchema = schema.object({ ]), environment: schema.string(), groupBy: schema.maybe(schema.arrayOf(schema.string())), + useKqlFilter: schema.maybe(schema.boolean()), + kqlFilter: schema.maybe(schema.string()), }); export const anomalyParamsSchema = schema.object({ @@ -58,6 +62,8 @@ export const transactionErrorRateParamsSchema = schema.object({ serviceName: schema.maybe(schema.string()), environment: schema.string(), groupBy: schema.maybe(schema.arrayOf(schema.string())), + useKqlFilter: schema.maybe(schema.boolean()), + kqlFilter: schema.maybe(schema.string()), }); type ErrorCountParamsType = TypeOf; diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.stories.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.stories.tsx index ddcae65209f67..c471c05f575b4 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.stories.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.stories.tsx @@ -11,7 +11,7 @@ import { CoreStart } from '@kbn/core/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; import { TIME_UNITS } from '@kbn/triggers-actions-ui-plugin/public'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; -import { RuleParams, ErrorCountRuleType } from '.'; +import { ErrorCountRuleParams, ErrorCountRuleType } from '.'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; import { AlertMetadata } from '../../utils/helper'; @@ -22,10 +22,15 @@ const coreMock = { uiSettings: { get: () => {} }, } as unknown as CoreStart; -const KibanaReactContext = createKibanaReactContext(coreMock); +const KibanaReactContext = createKibanaReactContext({ + ...coreMock, + dataViews: { + create: async () => {}, + }, +}); interface Args { - ruleParams: RuleParams; + ruleParams: ErrorCountRuleParams; metadata?: AlertMetadata; } @@ -54,7 +59,7 @@ export const CreatingInApmFromInventory: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); @@ -83,7 +88,7 @@ export const CreatingInApmFromService: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); @@ -112,7 +117,7 @@ export const EditingInStackManagement: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); @@ -142,7 +147,7 @@ export const CreatingInStackManagement: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx index 5136abea4d03c..e302a51f2a5db 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx @@ -16,6 +16,7 @@ import { } from '@kbn/triggers-actions-ui-plugin/public'; import { EuiFormRow } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; +import { EuiSwitchEvent } from '@elastic/eui'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { asInteger } from '../../../../../common/utils/formatters'; import { @@ -46,8 +47,9 @@ import { LoadingState, NoDataState, } from '../../ui_components/chart_preview/chart_preview_helper'; +import { ApmRuleKqlFilter } from '../../ui_components/apm_rule_kql_filter'; -export interface RuleParams { +export interface ErrorCountRuleParams { windowSize?: number; windowUnit?: TIME_UNITS; threshold?: number; @@ -55,10 +57,12 @@ export interface RuleParams { environment?: string; groupBy?: string[] | undefined; errorGroupingKey?: string; + useKqlFilter?: boolean; + kqlFilter?: string; } interface Props { - ruleParams: RuleParams; + ruleParams: ErrorCountRuleParams; metadata?: AlertMetadata; setRuleParams: (key: string, value: any) => void; setRuleProperty: (key: string, value: any) => void; @@ -101,6 +105,7 @@ export function ErrorCountRuleType(props: Props) { start, end, groupBy: params.groupBy, + kqlFilter: params.kqlFilter, }, }, } @@ -114,6 +119,7 @@ export function ErrorCountRuleType(props: Props) { params.serviceName, params.errorGroupingKey, params.groupBy, + params.kqlFilter, ] ); @@ -124,7 +130,7 @@ export function ErrorCountRuleType(props: Props) { [setRuleParams] ); - const fields = [ + const filterFields = [ { @@ -150,7 +156,9 @@ export function ErrorCountRuleType(props: Props) { onChange={(value) => setRuleParams('errorGroupingKey', value)} serviceName={params.serviceName} />, + ]; + const criteriaFields = [ , ]; + const fields = [ + ...(!ruleParams.useKqlFilter ? filterFields : []), + ...criteriaFields, + ]; + const errorCountChartPreview = data?.errorCountChartPreview; const series = errorCountChartPreview?.series ?? []; const hasData = series.length > 0; @@ -227,12 +240,31 @@ export function ErrorCountRuleType(props: Props) { ); + const onToggleKqlFilter = (e: EuiSwitchEvent) => { + setRuleParams('serviceName', undefined); + setRuleParams('errorGroupingKey', undefined); + setRuleParams('environment', ENVIRONMENT_ALL.value); + setRuleParams('kqlFilter', undefined); + setRuleParams('useKqlFilter', e.target.checked); + }; + + const kqlFilter = ( + <> + + + ); + return ( ); interface Args { - ruleParams: RuleParams; + ruleParams: TransactionDurationRuleParams; metadata?: AlertMetadata; } @@ -43,7 +43,8 @@ export const CreatingInApmServiceOverview: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = + useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); @@ -80,7 +81,8 @@ export const CreatingInStackManagement: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = + useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx index dcde3f4dd3e88..92c1aa301f516 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx @@ -17,6 +17,7 @@ import { } from '@kbn/triggers-actions-ui-plugin/public'; import { EuiFormRow } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; +import { EuiSwitchEvent } from '@elastic/eui'; import { AggregationType } from '../../../../../common/rules/apm_rule_types'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { getDurationFormatter } from '../../../../../common/utils/formatters'; @@ -53,8 +54,9 @@ import { LoadingState, NoDataState, } from '../../ui_components/chart_preview/chart_preview_helper'; +import { ApmRuleKqlFilter } from '../../ui_components/apm_rule_kql_filter'; -export interface RuleParams { +export interface TransactionDurationRuleParams { aggregationType: AggregationType; environment: string; threshold: number; @@ -64,6 +66,8 @@ export interface RuleParams { windowSize: number; windowUnit: string; groupBy?: string[] | undefined; + useKqlFilter?: boolean; + kqlFilter?: string; } const TRANSACTION_ALERT_AGGREGATION_TYPES: Record = { @@ -82,7 +86,7 @@ const TRANSACTION_ALERT_AGGREGATION_TYPES: Record = { }; interface Props { - ruleParams: RuleParams; + ruleParams: TransactionDurationRuleParams; metadata?: AlertMetadata; setRuleParams: (key: string, value: any) => void; setRuleProperty: (key: string, value: any) => void; @@ -131,6 +135,7 @@ export function TransactionDurationRuleType(props: Props) { start, end, groupBy: params.groupBy, + kqlFilter: params.kqlFilter, }, }, } @@ -146,6 +151,7 @@ export function TransactionDurationRuleType(props: Props) { params.windowSize, params.windowUnit, params.groupBy, + params.kqlFilter, ] ); @@ -186,7 +192,7 @@ export function TransactionDurationRuleType(props: Props) { [setRuleParams] ); - const fields = [ + const filterFields = [ setRuleParams('transactionName', value)} serviceName={params.serviceName} />, + ]; + + const criteriaFields = [ , ]; + const fields = [ + ...(!ruleParams.useKqlFilter ? filterFields : []), + ...criteriaFields, + ]; + const groupAlertsBy = ( <> ); + const onToggleKqlFilter = (e: EuiSwitchEvent) => { + setRuleParams('serviceName', undefined); + setRuleParams('transactionType', undefined); + setRuleParams('transactionName', undefined); + setRuleParams('environment', ENVIRONMENT_ALL.value); + setRuleParams('kqlFilter', undefined); + setRuleParams('useKqlFilter', e.target.checked); + }; + + const kqlFilter = ( + <> + + + ); + return ( diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.stories.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.stories.tsx index cd94439db0389..2c5ab725b5055 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.stories.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.stories.tsx @@ -9,7 +9,7 @@ import { Story } from '@storybook/react'; import React, { ComponentType, useState } from 'react'; import { CoreStart } from '@kbn/core/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; -import { RuleParams, TransactionErrorRateRuleType } from '.'; +import { ErrorRateRuleParams, TransactionErrorRateRuleType } from '.'; import { AlertMetadata } from '../../utils/helper'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; @@ -18,7 +18,7 @@ const KibanaReactContext = createKibanaReactContext({ } as unknown as Partial); interface Args { - ruleParams: RuleParams; + ruleParams: ErrorRateRuleParams; metadata?: AlertMetadata; } @@ -42,7 +42,7 @@ export const CreatingInApmServiceOverview: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); @@ -78,7 +78,7 @@ export const CreatingInStackManagement: Story = ({ ruleParams, metadata, }) => { - const [params, setParams] = useState(ruleParams); + const [params, setParams] = useState(ruleParams); function setRuleParams(property: string, value: any) { setParams({ ...params, [property]: value }); diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx index cec7f8cc7f129..a3032c32521e2 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx @@ -16,6 +16,7 @@ import { } from '@kbn/triggers-actions-ui-plugin/public'; import { EuiFormRow } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; +import { EuiSwitchEvent } from '@elastic/eui'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { asPercent } from '../../../../../common/utils/formatters'; import { @@ -46,8 +47,9 @@ import { LoadingState, NoDataState, } from '../../ui_components/chart_preview/chart_preview_helper'; +import { ApmRuleKqlFilter } from '../../ui_components/apm_rule_kql_filter'; -export interface RuleParams { +export interface ErrorRateRuleParams { windowSize?: number; windowUnit?: string; threshold?: number; @@ -56,10 +58,12 @@ export interface RuleParams { transactionName?: string; environment?: string; groupBy?: string[] | undefined; + useKqlFilter?: boolean; + kqlFilter?: string; } export interface Props { - ruleParams: RuleParams; + ruleParams: ErrorRateRuleParams; metadata?: AlertMetadata; setRuleParams: (key: string, value: any) => void; setRuleProperty: (key: string, value: any) => void; @@ -103,6 +107,7 @@ export function TransactionErrorRateRuleType(props: Props) { start, end, groupBy: params.groupBy, + kqlFilter: params.kqlFilter, }, }, } @@ -117,6 +122,7 @@ export function TransactionErrorRateRuleType(props: Props) { params.windowSize, params.windowUnit, params.groupBy, + params.kqlFilter, ] ); @@ -127,7 +133,7 @@ export function TransactionErrorRateRuleType(props: Props) { [setRuleParams] ); - const fields = [ + const filterFields = [ { @@ -159,6 +165,9 @@ export function TransactionErrorRateRuleType(props: Props) { onChange={(value) => setRuleParams('transactionName', value)} serviceName={params.serviceName} />, + ]; + + const criteriaFields = [ , ]; + const fields = [ + ...(!ruleParams.useKqlFilter ? filterFields : []), + ...criteriaFields, + ]; + const errorRateChartPreview = data?.errorRateChartPreview; const series = errorRateChartPreview?.series ?? []; const hasData = series.length > 0; @@ -237,11 +251,31 @@ export function TransactionErrorRateRuleType(props: Props) { ); + const onToggleKqlFilter = (e: EuiSwitchEvent) => { + setRuleParams('serviceName', undefined); + setRuleParams('transactionType', undefined); + setRuleParams('transactionName', undefined); + setRuleParams('environment', ENVIRONMENT_ALL.value); + setRuleParams('kqlFilter', undefined); + setRuleParams('useKqlFilter', e.target.checked); + }; + + const kqlFilter = ( + <> + + + ); + return ( void; + onToggleKqlFilter: any; +} + +export function ApmRuleKqlFilter({ + ruleParams, + setRuleParams, + onToggleKqlFilter, +}: Props) { + const FILTER_TYPING_DEBOUNCE_MS = 500; + + const { dataView: derivedIndexPattern } = useApmDataView(); + + const onFilterChange = useCallback( + (filter: string) => { + setRuleParams('kqlFilter', filter); + }, + [setRuleParams] + ); + + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const debouncedOnFilterChange = useCallback( + debounce(onFilterChange, FILTER_TYPING_DEBOUNCE_MS), + [onFilterChange] + ); + + const placeHolder = i18n.translate( + 'xpack.apm.rule.kqlSearchFieldPlaceholder', + { + defaultMessage: 'Search for APM data… (e.g. service.name: service-1)', + } + ); + + const kqlFilterToggle = ( + <> + + + + ); + + const kqlFilter = + ruleParams.useKqlFilter && derivedIndexPattern ? ( + <> + + + + + + ) : null; + + return ( + <> + {kqlFilterToggle} + {kqlFilter} + + ); +} diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.tsx index b651fb29a824f..ed046a9abc31f 100644 --- a/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/apm_rule_params_container/index.tsx @@ -25,6 +25,7 @@ interface Props { defaultParams: Record; fields: React.ReactNode[]; groupAlertsBy?: React.ReactNode; + kqlFilter?: React.ReactNode; chartPreview?: React.ReactNode; minimumWindowSize?: MinimumWindowSize; } @@ -33,6 +34,7 @@ export function ApmRuleParamsContainer(props: Props) { const { fields, groupAlertsBy, + kqlFilter, setRuleParams, defaultParams, chartPreview, @@ -62,8 +64,7 @@ export function ApmRuleParamsContainer(props: Props) { {showMinimumWindowSizeWarning && minimumWindowSize && ( )} - - + {kqlFilter} {fields.map((field, index) => ( @@ -71,7 +72,6 @@ export function ApmRuleParamsContainer(props: Props) { ))} - {chartPreview} {groupAlertsBy} diff --git a/x-pack/plugins/apm/server/routes/alerts/route.ts b/x-pack/plugins/apm/server/routes/alerts/route.ts index 8de52e452ca67..67470d19180ce 100644 --- a/x-pack/plugins/apm/server/routes/alerts/route.ts +++ b/x-pack/plugins/apm/server/routes/alerts/route.ts @@ -34,6 +34,7 @@ const alertParamsRt = t.intersection([ }), t.partial({ groupBy: t.array(t.string), + kqlFilter: t.string, }), ]); diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts index cf87eea545a48..e1bf2ba2b7a43 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; +import { + getParsedFilterQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { ERROR_GROUP_ID, @@ -38,6 +42,7 @@ export async function getTransactionErrorCountChartPreview({ start, end, groupBy: groupByFields, + kqlFilter, } = alertParams; const allGroupByFields = getAllGroupByFields( @@ -45,17 +50,24 @@ export async function getTransactionErrorCountChartPreview({ groupByFields ); - const query = { - bool: { - filter: [ + const termFilterQuery = !kqlFilter + ? [ ...termQuery(SERVICE_NAME, serviceName, { queryEmptyString: false, }), ...termQuery(ERROR_GROUP_ID, errorGroupingKey, { queryEmptyString: false, }), - ...rangeQuery(start, end), ...environmentQuery(environment), + ] + : []; + + const query = { + bool: { + filter: [ + ...termFilterQuery, + ...getParsedFilterQuery(kqlFilter), + ...rangeQuery(start, end), { term: { [PROCESSOR_EVENT]: ProcessorEvent.error } }, ], }, diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.test.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.test.ts index 2e517683394bf..cc509c41fb8b2 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.test.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.test.ts @@ -697,4 +697,68 @@ describe('Error count alert', () => { alertDetailsUrl: 'mockedAlertsLocator > getLocation', }); }); + + it('sends alert when rule is configured with a filter query', async () => { + const { services, dependencies, executor, scheduleActions } = + createRuleTypeMocks(); + + registerErrorCountRuleType(dependencies); + + const params = { + threshold: 2, + windowSize: 5, + windowUnit: 'm', + serviceName: undefined, + kqlFilter: 'service.name: foo and service.environment: env-foo', + groupBy: ['service.name', 'service.environment'], + }; + + services.scopedClusterClient.asCurrentUser.search.mockResponse({ + hits: { + hits: [], + total: { + relation: 'eq', + value: 2, + }, + }, + aggregations: { + error_counts: { + buckets: [ + { + key: ['foo', 'env-foo'], + doc_count: 5, + }, + ], + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }); + + await executor({ params }); + ['foo_env-foo'].forEach((instanceName) => + expect(services.alertFactory.create).toHaveBeenCalledWith(instanceName) + ); + + expect(scheduleActions).toHaveBeenCalledTimes(1); + + expect(scheduleActions).toHaveBeenCalledWith('threshold_met', { + serviceName: 'foo', + environment: 'env-foo', + threshold: 2, + triggerValue: 5, + reason: + 'Error count is 5 in the last 5 mins for service: foo, env: env-foo. Alert when > 2.', + interval: '5 mins', + viewInAppUrl: + 'http://localhost:5601/eyr/app/apm/services/foo/errors?environment=env-foo', + alertDetailsUrl: 'mockedAlertsLocator > getLocation', + }); + }); }); diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts index fe405aafd3c22..6f736fb3e5d82 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts @@ -19,7 +19,10 @@ import { ALERT_REASON, } from '@kbn/rule-data-utils'; import { createLifecycleRuleTypeFactory } from '@kbn/rule-registry-plugin/server'; -import { termQuery } from '@kbn/observability-plugin/server'; +import { + getParsedFilterQuery, + termQuery, +} from '@kbn/observability-plugin/server'; import { addSpaceIdToPath } from '@kbn/spaces-plugin/common'; import { asyncForEach } from '@kbn/std'; import { firstValueFrom } from 'rxjs'; @@ -119,6 +122,18 @@ export function registerErrorCountRuleType({ savedObjectsClient, }); + const termFilterQuery = !ruleParams.kqlFilter + ? [ + ...termQuery(SERVICE_NAME, ruleParams.serviceName, { + queryEmptyString: false, + }), + ...termQuery(ERROR_GROUP_ID, ruleParams.errorGroupingKey, { + queryEmptyString: false, + }), + ...environmentQuery(ruleParams.environment), + ] + : []; + const searchParams = { index: indices.error, body: { @@ -135,13 +150,8 @@ export function registerErrorCountRuleType({ }, }, { term: { [PROCESSOR_EVENT]: ProcessorEvent.error } }, - ...termQuery(SERVICE_NAME, ruleParams.serviceName, { - queryEmptyString: false, - }), - ...termQuery(ERROR_GROUP_ID, ruleParams.errorGroupingKey, { - queryEmptyString: false, - }), - ...environmentQuery(ruleParams.environment), + ...termFilterQuery, + ...getParsedFilterQuery(ruleParams.kqlFilter), ], }, }, diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts index 2aefb0598fcb9..12df75f19334b 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts @@ -6,7 +6,11 @@ */ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; +import { + getParsedFilterQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; import { AggregationType, ApmRuleType, @@ -56,6 +60,7 @@ export async function getTransactionDurationChartPreview({ start, end, groupBy: groupByFields, + kqlFilter, } = alertParams; const searchAggregatedTransactions = await getSearchTransactionsEvents({ config, @@ -63,9 +68,8 @@ export async function getTransactionDurationChartPreview({ kuery: '', }); - const query = { - bool: { - filter: [ + const termFilterQuery = !kqlFilter + ? [ ...termQuery(SERVICE_NAME, serviceName, { queryEmptyString: false, }), @@ -75,8 +79,16 @@ export async function getTransactionDurationChartPreview({ ...termQuery(TRANSACTION_NAME, transactionName, { queryEmptyString: false, }), - ...rangeQuery(start, end), ...environmentQuery(environment), + ] + : []; + + const query = { + bool: { + filter: [ + ...termFilterQuery, + ...getParsedFilterQuery(kqlFilter), + ...rangeQuery(start, end), ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), ] as QueryDslQueryContainer[], }, @@ -125,6 +137,7 @@ export async function getTransactionDurationChartPreview({ }, body: { size: 0, track_total_hits: false, query, aggs }, }; + const resp = await apmEventClient.search( 'get_transaction_duration_chart_preview', params diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.test.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.test.ts index 0d006c1368df1..1e62211e3f19a 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.test.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.test.ts @@ -283,4 +283,70 @@ describe('registerTransactionDurationRuleType', () => { transactionName: 'tx-java', }); }); + + it('sends alert when rule is configured with a filter query', async () => { + const { services, dependencies, executor, scheduleActions } = + createRuleTypeMocks(); + + registerTransactionDurationRuleType(dependencies); + + services.scopedClusterClient.asCurrentUser.search.mockResponse({ + hits: { + hits: [], + total: { + relation: 'eq', + value: 2, + }, + }, + aggregations: { + series: { + buckets: [ + { + key: ['opbeans-java', 'development', 'request'], + avgLatency: { + value: 5500000, + }, + }, + ], + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }); + + const params = { + threshold: 3000, + windowSize: 5, + windowUnit: 'm', + transactionType: undefined, + serviceName: undefined, + aggregationType: 'avg', + kqlFilter: 'service.name: opbeans-java and transaction.type: request', + groupBy: ['service.name', 'service.environment', 'transaction.type'], + }; + + await executor({ params }); + expect(scheduleActions).toHaveBeenCalledTimes(1); + expect(scheduleActions).toHaveBeenCalledWith('threshold_met', { + alertDetailsUrl: expect.stringContaining( + 'http://localhost:5601/eyr/app/observability/alerts/' + ), + environment: 'development', + interval: `5 mins`, + reason: + 'Avg. latency is 5.5 s in the last 5 mins for service: opbeans-java, env: development, type: request. Alert when > 3.0 s.', + transactionType: 'request', + serviceName: 'opbeans-java', + threshold: 3000, + triggerValue: '5,500 ms', + viewInAppUrl: + 'http://localhost:5601/eyr/app/apm/services/opbeans-java?transactionType=request&environment=development', + }); + }); }); diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts index 66e3c8a725632..c64eb650d8d84 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts @@ -15,7 +15,10 @@ import { ProcessorEvent, TimeUnitChar, } from '@kbn/observability-plugin/common'; -import { termQuery } from '@kbn/observability-plugin/server'; +import { + getParsedFilterQuery, + termQuery, +} from '@kbn/observability-plugin/server'; import { ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, @@ -136,6 +139,21 @@ export function registerTransactionDurationRuleType({ searchAggregatedTransactions ); + const termFilterQuery = !ruleParams.kqlFilter + ? [ + ...termQuery(SERVICE_NAME, ruleParams.serviceName, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_TYPE, ruleParams.transactionType, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_NAME, ruleParams.transactionName, { + queryEmptyString: false, + }), + ...environmentQuery(ruleParams.environment), + ] + : []; + const searchParams = { index, body: { @@ -154,16 +172,8 @@ export function registerTransactionDurationRuleType({ ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), - ...termQuery(SERVICE_NAME, ruleParams.serviceName, { - queryEmptyString: false, - }), - ...termQuery(TRANSACTION_TYPE, ruleParams.transactionType, { - queryEmptyString: false, - }), - ...termQuery(TRANSACTION_NAME, ruleParams.transactionName, { - queryEmptyString: false, - }), - ...environmentQuery(ruleParams.environment), + ...termFilterQuery, + ...getParsedFilterQuery(ruleParams.kqlFilter), ] as QueryDslQueryContainer[], }, }, diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts index f451fe7b188d6..e2f3888455f96 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; +import { + getParsedFilterQuery, + rangeQuery, + termQuery, +} from '@kbn/observability-plugin/server'; import { ApmRuleType } from '../../../../../common/rules/apm_rule_types'; import { SERVICE_NAME, @@ -48,6 +52,7 @@ export async function getTransactionErrorRateChartPreview({ end, transactionName, groupBy: groupByFields, + kqlFilter, } = alertParams; const searchAggregatedTransactions = await getSearchTransactionsEvents({ @@ -61,6 +66,21 @@ export async function getTransactionErrorRateChartPreview({ groupByFields ); + const termFilterQuery = !kqlFilter + ? [ + ...termQuery(SERVICE_NAME, serviceName, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_TYPE, transactionType, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_NAME, transactionName, { + queryEmptyString: false, + }), + ...environmentQuery(environment), + ] + : []; + const params = { apm: { events: [getProcessorEventForTransactions(searchAggregatedTransactions)], @@ -71,17 +91,9 @@ export async function getTransactionErrorRateChartPreview({ query: { bool: { filter: [ - ...termQuery(SERVICE_NAME, serviceName, { - queryEmptyString: false, - }), - ...termQuery(TRANSACTION_TYPE, transactionType, { - queryEmptyString: false, - }), - ...termQuery(TRANSACTION_NAME, transactionName, { - queryEmptyString: false, - }), + ...termFilterQuery, + ...getParsedFilterQuery(kqlFilter), ...rangeQuery(start, end), - ...environmentQuery(environment), ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.test.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.test.ts index c50bd62210e32..4f779ca4d7412 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.test.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.test.ts @@ -429,4 +429,83 @@ describe('Transaction error rate alert', () => { alertDetailsUrl: 'mockedAlertsLocator > getLocation', }); }); + + it('sends alert when rule is configured with a filter query', async () => { + const { services, dependencies, executor, scheduleActions } = + createRuleTypeMocks(); + + registerTransactionErrorRateRuleType({ + ...dependencies, + }); + + services.scopedClusterClient.asCurrentUser.search.mockResponse({ + hits: { + hits: [], + total: { + relation: 'eq', + value: 1, + }, + }, + aggregations: { + series: { + buckets: [ + { + key: ['bar', 'env-bar', 'type-bar'], + outcomes: { + buckets: [ + { + key: 'success', + doc_count: 90, + }, + { + key: 'failure', + doc_count: 10, + }, + ], + }, + }, + ], + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }); + + const params = { + threshold: 10, + windowSize: 5, + windowUnit: 'm', + kqlFilter: + 'service.name: bar and service.environment: env-bar and transaction.type: type-bar', + groupBy: ['service.name', 'service.environment', 'transaction.type'], + }; + + await executor({ params }); + + expect(services.alertFactory.create).toHaveBeenCalledTimes(1); + + expect(services.alertFactory.create).toHaveBeenCalledWith( + 'bar_env-bar_type-bar' + ); + + expect(scheduleActions).toHaveBeenCalledWith('threshold_met', { + serviceName: 'bar', + transactionType: 'type-bar', + environment: 'env-bar', + reason: + 'Failed transactions is 10% in the last 5 mins for service: bar, env: env-bar, type: type-bar. Alert when > 10%.', + threshold: 10, + triggerValue: '10', + interval: '5 mins', + viewInAppUrl: + 'http://localhost:5601/eyr/app/apm/services/bar?transactionType=type-bar&environment=env-bar', + alertDetailsUrl: 'mockedAlertsLocator > getLocation', + }); + }); }); diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts index 845aa18b21107..7b39de2a1b3af 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts @@ -14,7 +14,10 @@ import { TimeUnitChar, } from '@kbn/observability-plugin/common'; import { asPercent } from '@kbn/observability-plugin/common/utils/formatters'; -import { termQuery } from '@kbn/observability-plugin/server'; +import { + getParsedFilterQuery, + termQuery, +} from '@kbn/observability-plugin/server'; import { ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, @@ -139,6 +142,21 @@ export function registerTransactionErrorRateRuleType({ ? indices.metric : indices.transaction; + const termFilterQuery = !ruleParams.kqlFilter + ? [ + ...termQuery(SERVICE_NAME, ruleParams.serviceName, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_TYPE, ruleParams.transactionType, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_NAME, ruleParams.transactionName, { + queryEmptyString: false, + }), + ...environmentQuery(ruleParams.environment), + ] + : []; + const searchParams = { index, body: { @@ -165,16 +183,8 @@ export function registerTransactionErrorRateRuleType({ ], }, }, - ...termQuery(SERVICE_NAME, ruleParams.serviceName, { - queryEmptyString: false, - }), - ...termQuery(TRANSACTION_TYPE, ruleParams.transactionType, { - queryEmptyString: false, - }), - ...termQuery(TRANSACTION_NAME, ruleParams.transactionName, { - queryEmptyString: false, - }), - ...environmentQuery(ruleParams.environment), + ...termFilterQuery, + ...getParsedFilterQuery(ruleParams.kqlFilter), ], }, }, diff --git a/x-pack/plugins/observability/public/components/threshold/components/autocomplete_field/autocomplete_field.tsx b/x-pack/plugins/observability/public/components/rule_kql_filter/autocomplete_field/autocomplete_field.tsx similarity index 98% rename from x-pack/plugins/observability/public/components/threshold/components/autocomplete_field/autocomplete_field.tsx rename to x-pack/plugins/observability/public/components/rule_kql_filter/autocomplete_field/autocomplete_field.tsx index d47ce71e02b0e..4aaa44e742108 100644 --- a/x-pack/plugins/observability/public/components/threshold/components/autocomplete_field/autocomplete_field.tsx +++ b/x-pack/plugins/observability/public/components/rule_kql_filter/autocomplete_field/autocomplete_field.tsx @@ -85,10 +85,10 @@ export class AutocompleteField extends React.Component< placeholder={placeholder} value={value} aria-label={ariaLabel} - data-test-subj="thresholdRuleSearchField" + data-test-subj="ruleKqlFilterSearchField" /> {areSuggestionsVisible && !isLoadingSuggestions && suggestions.length > 0 ? ( - + {suggestions.map((suggestion, suggestionIndex) => ( {({ isLoadingSuggestions, loadSuggestions, suggestions }) => ( @@ -91,7 +83,7 @@ export function MetricsExplorerKueryBar({ loadSuggestions={curryLoadSuggestions(loadSuggestions)} onChange={handleChange} onSubmit={onSubmit} - placeholder={placeholder || defaultPlaceholder} + placeholder={placeholder} suggestions={suggestions} value={draftQuery} /> diff --git a/x-pack/plugins/observability/public/components/threshold/containers/with_kuery_autocompletion.tsx b/x-pack/plugins/observability/public/components/rule_kql_filter/with_kuery_autocompletion.tsx similarity index 97% rename from x-pack/plugins/observability/public/components/threshold/containers/with_kuery_autocompletion.tsx rename to x-pack/plugins/observability/public/components/rule_kql_filter/with_kuery_autocompletion.tsx index 4426952cf173e..86a9300e98aa0 100644 --- a/x-pack/plugins/observability/public/components/threshold/containers/with_kuery_autocompletion.tsx +++ b/x-pack/plugins/observability/public/components/rule_kql_filter/with_kuery_autocompletion.tsx @@ -14,7 +14,7 @@ import { } from '@kbn/kibana-react-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { QuerySuggestion } from '@kbn/unified-search-plugin/public'; -import { InfraClientStartDeps, RendererFunction } from '../types'; +import { InfraClientStartDeps, RendererFunction } from '../threshold/types'; interface WithKueryAutocompletionLifecycleProps { kibana: KibanaReactContextValue; diff --git a/x-pack/plugins/observability/public/components/threshold/components/custom_equation/metric_row_with_agg.tsx b/x-pack/plugins/observability/public/components/threshold/components/custom_equation/metric_row_with_agg.tsx index fcc09399bb3da..5b0925ea27dd3 100644 --- a/x-pack/plugins/observability/public/components/threshold/components/custom_equation/metric_row_with_agg.tsx +++ b/x-pack/plugins/observability/public/components/threshold/components/custom_equation/metric_row_with_agg.tsx @@ -25,7 +25,7 @@ import { Aggregators, CustomMetricAggTypes } from '../../../../../common/thresho import { MetricRowControls } from './metric_row_controls'; import { NormalizedFields, MetricRowBaseProps } from './types'; import { ClosablePopoverTitle } from '../closable_popover_title'; -import { MetricsExplorerKueryBar } from '../kuery_bar'; +import { RuleFlyoutKueryBar } from '../../../rule_kql_filter/kuery_bar'; interface MetricRowWithAggProps extends MetricRowBaseProps { aggType?: CustomMetricAggTypes; @@ -184,7 +184,7 @@ export function MetricRowWithAgg({ { defaultMessage: 'KQL Filter {name}', values: { name } } )} > - @@ -366,7 +373,8 @@ export default function Expressions(props: Props) { - Array> = ( - filterQuery -) => { - if (!filterQuery) return []; - - try { - const parsedQuery = toElasticsearchQuery(fromKueryExpression(filterQuery)); - return [parsedQuery]; - } catch (error) { - return []; - } -}; +import { getParsedFilterQuery } from '../../../../utils/get_parsed_filtered_query'; export const calculateCurrentTimeframe = ( metricParams: MetricExpressionParams, diff --git a/x-pack/plugins/observability/server/utils/get_parsed_filtered_query.ts b/x-pack/plugins/observability/server/utils/get_parsed_filtered_query.ts new file mode 100644 index 0000000000000..fabefa63f0695 --- /dev/null +++ b/x-pack/plugins/observability/server/utils/get_parsed_filtered_query.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 { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; + +export const getParsedFilterQuery: (filter: string | undefined) => Array> = ( + filter +) => { + if (!filter) return []; + + try { + const parsedQuery = toElasticsearchQuery(fromKueryExpression(filter)); + return [parsedQuery]; + } catch (error) { + return []; + } +}; diff --git a/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts index 56ff934db3259..7ee8f4a61aa3f 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/error_count_threshold.spec.ts @@ -35,13 +35,16 @@ export default function ApiTest({ getService }: FtrProviderContext) { const synthtraceEsClient = getService('synthtraceEsClient'); registry.when('error count threshold alert', { config: 'basic', archives: [] }, () => { - let ruleId: string; + let ruleId1: string; + let ruleId2: string; let alertId: string; let startedAt: string; - let actionId: string | undefined; + let actionId1: string | undefined; + let actionId2: string | undefined; const APM_ALERTS_INDEX = '.alerts-observability.apm.alerts-default'; - const ALERT_ACTION_INDEX_NAME = 'alert-action-error-count'; + const ALERT_ACTION_INDEX_NAME1 = 'alert-action-error-count1'; + const ALERT_ACTION_INDEX_NAME2 = 'alert-action-error-count2'; const errorMessage = '[ResponseError] index_not_found_exception'; const errorGroupingKey = getErrorGroupingKey(errorMessage); @@ -75,12 +78,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { after(async () => { await synthtraceEsClient.clean(); - await supertest.delete(`/api/alerting/rule/${ruleId}`).set('kbn-xsrf', 'foo'); - await supertest.delete(`/api/actions/connector/${actionId}`).set('kbn-xsrf', 'foo'); - await esDeleteAllIndices(ALERT_ACTION_INDEX_NAME); + await supertest.delete(`/api/alerting/rule/${ruleId1}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/actions/connector/${actionId1}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/alerting/rule/${ruleId2}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/actions/connector/${actionId2}`).set('kbn-xsrf', 'foo'); + await esDeleteAllIndices([ALERT_ACTION_INDEX_NAME1, ALERT_ACTION_INDEX_NAME2]); await es.deleteByQuery({ index: APM_ALERTS_INDEX, - query: { term: { 'kibana.alert.rule.uuid': ruleId } }, + query: { term: { 'kibana.alert.rule.uuid': ruleId1 } }, + }); + await es.deleteByQuery({ + index: APM_ALERTS_INDEX, + query: { term: { 'kibana.alert.rule.uuid': ruleId2 } }, }); await es.deleteByQuery({ index: '.kibana-event-log-*', @@ -88,22 +97,23 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - describe('create alert', () => { + describe('create alert without filter query', () => { before(async () => { - actionId = await createIndexConnector({ + actionId1 = await createIndexConnector({ supertest, - name: 'Error count API test', - indexName: ALERT_ACTION_INDEX_NAME, + name: 'Error count without filter query', + indexName: ALERT_ACTION_INDEX_NAME1, }); const createdRule = await createApmRule({ supertest, ruleTypeId: ApmRuleType.ErrorCount, - name: 'Apm error count', + name: 'Apm error count without filter query', params: { environment: 'production', threshold: 1, windowSize: 1, windowUnit: 'h', + kqlFilter: '', groupBy: [ 'service.name', 'service.environment', @@ -115,7 +125,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { actions: [ { group: 'threshold_met', - id: actionId, + id: actionId1, params: { documents: [ { @@ -135,12 +145,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { ], }); expect(createdRule.id).to.not.eql(undefined); - ruleId = createdRule.id; + ruleId1 = createdRule.id; }); it('checks if rule is active', async () => { const executionStatus = await waitForRuleStatus({ - id: ruleId, + id: ruleId1, expectedStatus: 'active', supertest, }); @@ -151,7 +161,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const resp = await waitForAlertInIndex({ es, indexName: APM_ALERTS_INDEX, - ruleId, + ruleId: ruleId1, }); alertId = (resp.hits.hits[0]._source as any)['kibana.alert.uuid']; startedAt = (resp.hits.hits[0]._source as any)['kibana.alert.start']; @@ -167,13 +177,13 @@ export default function ApiTest({ getService }: FtrProviderContext) { const rangeFrom = moment(startedAt).subtract('5', 'minute').toISOString(); const resp = await waitForDocumentInIndex<{ message: string }>({ es, - indexName: ALERT_ACTION_INDEX_NAME, + indexName: ALERT_ACTION_INDEX_NAME1, }); expect(resp.hits.hits[0]._source?.message).eql( `Error count is 15 in the last 1 hr for service: opbeans-java, env: production, name: tx-java, error key: ${errorGroupingKey}, error name: ${errorMessage}. Alert when > 1. -Apm error count is active with the following conditions: +Apm error count without filter query is active with the following conditions: - Service name: opbeans-java - Environment: production @@ -212,5 +222,132 @@ Apm error count is active with the following conditions: expect(serviceTabAlertCount).to.be(0); }); }); + + describe('create alert with filter query', () => { + before(async () => { + actionId2 = await createIndexConnector({ + supertest, + name: 'Error count with filter query', + indexName: ALERT_ACTION_INDEX_NAME2, + }); + const createdRule = await createApmRule({ + supertest, + ruleTypeId: ApmRuleType.ErrorCount, + name: 'Apm error count with filter query', + params: { + environment: 'ENVIRONMENT_ALL', + threshold: 1, + windowSize: 1, + windowUnit: 'h', + serviceName: undefined, + kqlFilter: 'service.name: opbeans-java and service.environment: production', + groupBy: [ + 'service.name', + 'service.environment', + 'transaction.name', + 'error.grouping_key', + 'error.grouping_name', + ], + }, + actions: [ + { + group: 'threshold_met', + id: actionId2, + params: { + documents: [ + { + message: `${errorCountMessage} +- Transaction name: {{context.transactionName}} +- Error grouping key: {{context.errorGroupingKey}} +- Error grouping name: {{context.errorGroupingName}}`, + }, + ], + }, + frequency: { + notify_when: 'onActionGroupChange', + throttle: null, + summary: false, + }, + }, + ], + }); + expect(createdRule.id).to.not.eql(undefined); + ruleId2 = createdRule.id; + }); + + it('checks if rule is active', async () => { + const executionStatus = await waitForRuleStatus({ + id: ruleId2, + expectedStatus: 'active', + supertest, + }); + expect(executionStatus.status).to.be('active'); + }); + + it('indexes alert document with all group-by fields', async () => { + const resp = await waitForAlertInIndex({ + es, + indexName: APM_ALERTS_INDEX, + ruleId: ruleId2, + }); + alertId = (resp.hits.hits[0]._source as any)['kibana.alert.uuid']; + startedAt = (resp.hits.hits[0]._source as any)['kibana.alert.start']; + + expect(resp.hits.hits[0]._source).property('service.name', 'opbeans-java'); + expect(resp.hits.hits[0]._source).property('service.environment', 'production'); + expect(resp.hits.hits[0]._source).property('transaction.name', 'tx-java'); + expect(resp.hits.hits[0]._source).property('error.grouping_key', errorGroupingKey); + expect(resp.hits.hits[0]._source).property('error.grouping_name', errorMessage); + }); + + it('returns correct message', async () => { + const rangeFrom = moment(startedAt).subtract('5', 'minute').toISOString(); + const resp = await waitForDocumentInIndex<{ message: string }>({ + es, + indexName: ALERT_ACTION_INDEX_NAME2, + }); + + expect(resp.hits.hits[0]._source?.message).eql( + `Error count is 15 in the last 1 hr for service: opbeans-java, env: production, name: tx-java, error key: ${errorGroupingKey}, error name: ${errorMessage}. Alert when > 1. + +Apm error count with filter query is active with the following conditions: + +- Service name: opbeans-java +- Environment: production +- Error count: 15 errors over the last 1 hr +- Threshold: 1 + +[View alert details](http://mockedpublicbaseurl/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)) + +- Transaction name: tx-java +- Error grouping key: ${errorGroupingKey} +- Error grouping name: ${errorMessage}` + ); + }); + + it('shows the correct alert count for each service on service inventory', async () => { + const serviceInventoryAlertCounts = await fetchServiceInventoryAlertCounts(apmApiClient); + expect(serviceInventoryAlertCounts).to.eql({ + 'opbeans-node': 0, + 'opbeans-java': 2, + }); + }); + + it('shows the correct alert count in opbeans-java service', async () => { + const serviceTabAlertCount = await fetchServiceTabAlertCount({ + apmApiClient, + serviceName: 'opbeans-java', + }); + expect(serviceTabAlertCount).to.be(2); + }); + + it('shows the correct alert count in opbeans-node service', async () => { + const serviceTabAlertCount = await fetchServiceTabAlertCount({ + apmApiClient, + serviceName: 'opbeans-node', + }); + expect(serviceTabAlertCount).to.be(0); + }); + }); }); } diff --git a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_count.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_count.spec.ts index 959a1567c6c8e..ea2c8c470a70b 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_count.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_count.spec.ts @@ -11,6 +11,7 @@ import { ERROR_GROUP_ID, } from '@kbn/apm-plugin/common/es_fields/apm'; import type { PreviewChartResponseItem } from '@kbn/apm-plugin/server/routes/alerts/route'; +import { getErrorGroupingKey } from '@kbn/apm-synthtrace-client/src/lib/apm/instance'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { generateErrorData } from './generate_data'; @@ -34,6 +35,20 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }); + const getOptionsWithFilterQuery = () => ({ + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + interval: '5m', + kqlFilter: 'service.name: synth-go', + serviceName: undefined, + errorGroupingKey: undefined, + environment: 'ENVIRONMENT_ALL', + }, + }, + }); + registry.when(`without data loaded`, { config: 'basic', archives: [] }, () => { it('error_count (without data)', async () => { const options = getOptions(); @@ -80,7 +95,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { start: new Date(start).toISOString(), end: new Date(end).toISOString(), serviceName: 'synth-go', - errorGroupingKey: '98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + errorGroupingKey: `${getErrorGroupingKey('Error 1')}`, environment: 'ENVIRONMENT_ALL', interval: '5m', }, @@ -167,11 +182,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { })) ).to.eql([ { - name: 'synth-go_production_98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + name: `synth-go_production_${getErrorGroupingKey('Error 1')}`, y: 250, }, { - name: 'synth-go_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + name: `synth-go_production_${getErrorGroupingKey('Error 0')}`, y: 125, }, ]); @@ -182,7 +197,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { params: { query: { ...getOptions().params.query, - errorGroupingKey: 'cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + errorGroupingKey: `${getErrorGroupingKey('Error 0')}`, groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, ERROR_GROUP_ID], }, }, @@ -202,7 +217,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { })) ).to.eql([ { - name: 'synth-go_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + name: `synth-go_production_${getErrorGroupingKey('Error 0')}`, y: 125, }, ]); @@ -263,19 +278,250 @@ export default function ApiTest({ getService }: FtrProviderContext) { })) ).to.eql([ { - name: 'synth-go_production_98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + name: `synth-go_production_${getErrorGroupingKey('Error 1')}`, + y: 250, + }, + { + name: `synth-java_production_${getErrorGroupingKey('Error 1')}`, + y: 250, + }, + { + name: `synth-go_production_${getErrorGroupingKey('Error 0')}`, + y: 125, + }, + { + name: `synth-java_production_${getErrorGroupingKey('Error 0')}`, + y: 125, + }, + ]); + }); + }); + }); + + registry.when(`with data loaded and using KQL filter`, { config: 'basic', archives: [] }, () => { + describe('error_count', () => { + before(async () => { + await generateErrorData({ serviceName: 'synth-go', start, end, synthtraceEsClient }); + await generateErrorData({ serviceName: 'synth-java', start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + it('with data', async () => { + const options = getOptionsWithFilterQuery(); + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.some((item: PreviewChartResponseItem) => + item.data.some((coordinate) => coordinate.x && coordinate.y) + ) + ).to.equal(true); + }); + + it('with error grouping key in filter query', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: `service.name: synth-go and error.grouping_key: ${getErrorGroupingKey( + 'Error 1' + )}`, + }, + }, + }; + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production', y: 250 }]); + }); + + it('with no group by parameter', async () => { + const options = getOptionsWithFilterQuery(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(1); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production', y: 375 }]); + }); + + it('with default group by fields', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(1); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production', y: 375 }]); + }); + + it('with group by on error grouping key', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, ERROR_GROUP_ID], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(2); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: `synth-go_production_${getErrorGroupingKey('Error 1')}`, + y: 250, + }, + { + name: `synth-go_production_${getErrorGroupingKey('Error 0')}`, + y: 125, + }, + ]); + }); + + it('with group by on error grouping key and filter on error grouping key', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: `service.name: synth-go and error.grouping_key: ${getErrorGroupingKey( + 'Error 0' + )}`, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, ERROR_GROUP_ID], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(1); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: `synth-go_production_${getErrorGroupingKey('Error 0')}`, + y: 125, + }, + ]); + }); + + it('with empty filter query', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: '', + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production', y: 375 }, + { name: 'synth-java_production', y: 375 }, + ]); + }); + + it('with empty filter query and group by on error grouping key', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: '', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, ERROR_GROUP_ID], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: `synth-go_production_${getErrorGroupingKey('Error 1')}`, y: 250, }, { - name: 'synth-java_production_98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + name: `synth-java_production_${getErrorGroupingKey('Error 1')}`, y: 250, }, { - name: 'synth-go_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + name: `synth-go_production_${getErrorGroupingKey('Error 0')}`, y: 125, }, { - name: 'synth-java_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + name: `synth-java_production_${getErrorGroupingKey('Error 0')}`, y: 125, }, ]); diff --git a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_rate.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_rate.spec.ts index c3840aaff7571..8e77035c27696 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_rate.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_rate.spec.ts @@ -36,6 +36,21 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }); + const getOptionsWithFilterQuery = () => ({ + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + interval: '5m', + kqlFilter: 'service.name: synth-go and transaction.type: request', + serviceName: undefined, + transactionType: undefined, + transactionName: undefined, + environment: 'ENVIRONMENT_ALL', + }, + }, + }); + registry.when(`without data loaded`, { config: 'basic', archives: [] }, () => { it('transaction_error_rate without data', async () => { const options = getOptions(); @@ -306,4 +321,247 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); }); + + registry.when(`with data loaded and using KQL filter`, { config: 'basic', archives: [] }, () => { + describe('transaction_error_rate', () => { + before(async () => { + await generateErrorData({ serviceName: 'synth-go', start, end, synthtraceEsClient }); + await generateErrorData({ serviceName: 'synth-java', start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + it('with data', async () => { + const options = getOptionsWithFilterQuery(); + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.some((item: PreviewChartResponseItem) => + item.data.some((coordinate) => coordinate.x && coordinate.y) + ) + ).to.equal(true); + }); + + it('with transaction name in filter query', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: + 'service.name: synth-go and transaction.type: request and transaction.name: GET /banana', + }, + }, + }; + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 50 }]); + }); + + it('with nonexistent transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: + 'service.name: synth-go and transaction.type: request and transaction.name: foo', + }, + }, + }; + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series).to.eql([]); + }); + + it('with no group by parameter', async () => { + const options = getOptionsWithFilterQuery(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(1); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 37.5 }]); + }); + + it('with default group by fields', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(1); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 37.5 }]); + }); + + it('with group by on transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(2); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: 'synth-go_production_request_GET /banana', + y: 50, + }, + { + name: 'synth-go_production_request_GET /apple', + y: 25, + }, + ]); + }); + + it('with group by on transaction name and filter on transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: + 'service.name: synth-go and transaction.type: request and transaction.name: GET /apple', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(1); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request_GET /apple', y: 25 }]); + }); + + it('with empty filter query', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: '', + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request', y: 37.5 }, + { name: 'synth-java_production_request', y: 37.5 }, + ]); + }); + + it('with empty filter query and group by on transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: '', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: 'synth-go_production_request_GET /banana', + y: 50, + }, + { + name: 'synth-java_production_request_GET /banana', + y: 50, + }, + { + name: 'synth-go_production_request_GET /apple', + y: 25, + }, + { + name: 'synth-java_production_request_GET /apple', + y: 25, + }, + ]); + }); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_transaction_duration.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_transaction_duration.spec.ts index ccb7fec009df3..d882bd84d1193 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_transaction_duration.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_transaction_duration.spec.ts @@ -32,6 +32,22 @@ export default function ApiTest({ getService }: FtrProviderContext) { transactionType: 'request', environment: 'ENVIRONMENT_ALL', interval: '5m', + kqlFilter: '', + }, + }, + }); + + const getOptionsWithFilterQuery = () => ({ + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + interval: '5m', + kqlFilter: 'service.name: synth-go and transaction.type: request', + serviceName: undefined, + transactionType: undefined, + transactionName: undefined, + environment: 'ENVIRONMENT_ALL', }, }, }); @@ -78,16 +94,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = { params: { query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - serviceName: 'synth-go', + ...getOptions().params.query, transactionName: 'GET /banana', - transactionType: 'request', - environment: 'ENVIRONMENT_ALL', - interval: '5m', }, }, }; + const response = await apmApiClient.readUser({ ...options, endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', @@ -106,16 +118,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = { params: { query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - serviceName: 'synth-go', - transactionType: 'request', + ...getOptions().params.query, transactionName: 'foo', - environment: 'ENVIRONMENT_ALL', - interval: '5m', }, }, }; + const response = await apmApiClient.readUser({ ...options, endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', @@ -225,16 +233,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = { params: { query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), + ...getOptions().params.query, serviceName: '', transactionName: '', transactionType: '', - environment: 'ENVIRONMENT_ALL', - interval: '5m', }, }, }; + const response = await apmApiClient.readUser({ ...options, endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', @@ -256,17 +262,243 @@ export default function ApiTest({ getService }: FtrProviderContext) { const options = { params: { query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), + ...getOptions().params.query, serviceName: '', transactionName: '', transactionType: '', - environment: 'ENVIRONMENT_ALL', - interval: '5m', groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], }, }, }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(4); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request_GET /apple', y: 10000 }, + { name: 'synth-java_production_request_GET /apple', y: 10000 }, + { name: 'synth-go_production_request_GET /banana', y: 5000 }, + { name: 'synth-java_production_request_GET /banana', y: 5000 }, + ]); + }); + }); + }); + + registry.when(`with data loaded and using KQL filter`, { config: 'basic', archives: [] }, () => { + describe('transaction_duration', () => { + before(async () => { + await generateLatencyData({ serviceName: 'synth-go', start, end, synthtraceEsClient }); + await generateLatencyData({ serviceName: 'synth-java', start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + it('with data', async () => { + const options = getOptionsWithFilterQuery(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.latencyChartPreview.series.some((item: PreviewChartResponseItem) => + item.data.some((coordinate) => coordinate.x && coordinate.y) + ) + ).to.equal(true); + }); + + it('with transaction name in filter query', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: + 'service.name: synth-go and transaction.type: request and transaction.name: GET /banana', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 5000 }]); + }); + + it('with nonexistent transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: + 'service.name: synth-go and transaction.type: request and transaction.name: foo', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series).to.eql([]); + }); + + it('with no group by parameter', async () => { + const options = getOptionsWithFilterQuery(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(1); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 7500 }]); + }); + + it('with default group by fields', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(1); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 7500 }]); + }); + + it('with group by on transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(2); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request_GET /apple', y: 10000 }, + { name: 'synth-go_production_request_GET /banana', y: 5000 }, + ]); + }); + + it('with group by on transaction name and filter on transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: + 'service.name: synth-go and transaction.type: request and transaction.name: GET /apple', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(1); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request_GET /apple', y: 10000 }]); + }); + + it('with empty filter query', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: '', + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request', y: 7500 }, + { name: 'synth-java_production_request', y: 7500 }, + ]); + }); + + it('with empty filter query and group by on transaction name', async () => { + const options = { + params: { + query: { + ...getOptionsWithFilterQuery().params.query, + kqlFilter: '', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + const response = await apmApiClient.readUser({ ...options, endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', diff --git a/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts index 4fa40d566552f..549b8a33e9428 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/transaction_duration.spec.ts @@ -32,11 +32,13 @@ export default function ApiTest({ getService }: FtrProviderContext) { const synthtraceEsClient = getService('synthtraceEsClient'); registry.when('transaction duration alert', { config: 'basic', archives: [] }, () => { - let ruleId: string; - let actionId: string | undefined; - + let ruleId1: string; + let actionId1: string | undefined; + let ruleId2: string; + let actionId2: string | undefined; const APM_ALERTS_INDEX = '.alerts-observability.apm.alerts-default'; - const ALERT_ACTION_INDEX_NAME = 'alert-action-transaction-duration'; + const ALERT_ACTION_INDEX_NAME1 = 'alert-action-transaction-duration1'; + const ALERT_ACTION_INDEX_NAME2 = 'alert-action-transaction-duration2'; before(async () => { const opbeansJava = apm @@ -66,12 +68,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { after(async () => { await synthtraceEsClient.clean(); - await supertest.delete(`/api/alerting/rule/${ruleId}`).set('kbn-xsrf', 'foo'); - await supertest.delete(`/api/actions/connector/${actionId}`).set('kbn-xsrf', 'foo'); - await esDeleteAllIndices([ALERT_ACTION_INDEX_NAME]); + await supertest.delete(`/api/alerting/rule/${ruleId1}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/actions/connector/${actionId1}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/alerting/rule/${ruleId2}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/actions/connector/${actionId2}`).set('kbn-xsrf', 'foo'); + await esDeleteAllIndices([ALERT_ACTION_INDEX_NAME1, ALERT_ACTION_INDEX_NAME2]); + await es.deleteByQuery({ + index: APM_ALERTS_INDEX, + query: { term: { 'kibana.alert.rule.uuid': ruleId1 } }, + }); await es.deleteByQuery({ index: APM_ALERTS_INDEX, - query: { term: { 'kibana.alert.rule.uuid': ruleId } }, + query: { term: { 'kibana.alert.rule.uuid': ruleId2 } }, }); await es.deleteByQuery({ index: '.kibana-event-log-*', @@ -79,17 +87,17 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - describe('create alert with transaction.name group by', () => { + describe('create rule without filter query', () => { before(async () => { - actionId = await createIndexConnector({ + actionId1 = await createIndexConnector({ supertest, - name: 'Transation duration API test', - indexName: ALERT_ACTION_INDEX_NAME, + name: 'Transation duration without filter query', + indexName: ALERT_ACTION_INDEX_NAME1, }); const createdRule = await createApmRule({ supertest, ruleTypeId: ApmRuleType.TransactionDuration, - name: 'Apm transaction duration', + name: 'Apm transaction duration without filter query', params: { threshold: 3000, windowSize: 5, @@ -98,6 +106,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { serviceName: 'opbeans-java', environment: 'production', aggregationType: AggregationType.Avg, + kqlFilter: '', groupBy: [ 'service.name', 'service.environment', @@ -108,7 +117,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { actions: [ { group: 'threshold_met', - id: actionId, + id: actionId1, params: { documents: [{ message: 'Transaction Name: {{context.transactionName}}' }], }, @@ -121,12 +130,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { ], }); expect(createdRule.id).to.not.eql(undefined); - ruleId = createdRule.id; + ruleId1 = createdRule.id; }); it('checks if rule is active', async () => { const executionStatus = await waitForRuleStatus({ - id: ruleId, + id: ruleId1, expectedStatus: 'active', supertest, }); @@ -136,7 +145,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns correct message', async () => { const resp = await waitForDocumentInIndex<{ message: string }>({ es, - indexName: ALERT_ACTION_INDEX_NAME, + indexName: ALERT_ACTION_INDEX_NAME1, }); expect(resp.hits.hits[0]._source?.message).eql(`Transaction Name: tx-java`); @@ -146,7 +155,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const resp = await waitForAlertInIndex({ es, indexName: APM_ALERTS_INDEX, - ruleId, + ruleId: ruleId1, }); expect(resp.hits.hits[0]._source).property('service.name', 'opbeans-java'); @@ -179,5 +188,108 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(serviceTabAlertCount).to.be(0); }); }); + + describe('create rule with filter query', () => { + before(async () => { + actionId2 = await createIndexConnector({ + supertest, + name: 'Transation duration with filter query', + indexName: ALERT_ACTION_INDEX_NAME2, + }); + const createdRule = await createApmRule({ + supertest, + ruleTypeId: ApmRuleType.TransactionDuration, + name: 'Apm transaction duration with filter query', + params: { + threshold: 3000, + windowSize: 5, + windowUnit: 'm', + transactionType: undefined, + serviceName: undefined, + environment: 'ENVIRONMENT_ALL', + aggregationType: AggregationType.Avg, + kqlFilter: + 'service.name: opbeans-node and transaction.type: request and service.environment: production', + groupBy: [ + 'service.name', + 'service.environment', + 'transaction.type', + 'transaction.name', + ], + }, + actions: [ + { + group: 'threshold_met', + id: actionId2, + params: { + documents: [{ message: 'Transaction Name: {{context.transactionName}}' }], + }, + frequency: { + notify_when: 'onActionGroupChange', + throttle: null, + summary: false, + }, + }, + ], + }); + expect(createdRule.id).to.not.eql(undefined); + ruleId2 = createdRule.id; + }); + + it('checks if rule is active', async () => { + const executionStatus = await waitForRuleStatus({ + id: ruleId2, + expectedStatus: 'active', + supertest, + }); + expect(executionStatus.status).to.be('active'); + }); + + it('returns correct message', async () => { + const resp = await waitForDocumentInIndex<{ message: string }>({ + es, + indexName: ALERT_ACTION_INDEX_NAME2, + }); + + expect(resp.hits.hits[0]._source?.message).eql(`Transaction Name: tx-node`); + }); + + it('indexes alert document with all group-by fields', async () => { + const resp = await waitForAlertInIndex({ + es, + indexName: APM_ALERTS_INDEX, + ruleId: ruleId2, + }); + + expect(resp.hits.hits[0]._source).property('service.name', 'opbeans-node'); + expect(resp.hits.hits[0]._source).property('service.environment', 'production'); + expect(resp.hits.hits[0]._source).property('transaction.type', 'request'); + expect(resp.hits.hits[0]._source).property('transaction.name', 'tx-node'); + }); + + it('shows the correct alert count for each service on service inventory', async () => { + const serviceInventoryAlertCounts = await fetchServiceInventoryAlertCounts(apmApiClient); + expect(serviceInventoryAlertCounts).to.eql({ + 'opbeans-node': 1, + 'opbeans-java': 1, + }); + }); + + it('shows the correct alert count in opbeans-java service', async () => { + const serviceTabAlertCount = await fetchServiceTabAlertCount({ + apmApiClient, + serviceName: 'opbeans-java', + }); + expect(serviceTabAlertCount).to.be(1); + }); + + it('shows the correct alert count in opbeans-node service', async () => { + const serviceTabAlertCount = await fetchServiceTabAlertCount({ + apmApiClient, + serviceName: 'opbeans-node', + }); + expect(serviceTabAlertCount).to.be(1); + }); + }); }); } diff --git a/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts index 61caf5cd8c0f6..af0568f93ad4c 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/transaction_error_rate.spec.ts @@ -33,13 +33,16 @@ export default function ApiTest({ getService }: FtrProviderContext) { const synthtraceEsClient = getService('synthtraceEsClient'); registry.when('transaction error rate alert', { config: 'basic', archives: [] }, () => { - let ruleId: string; + let ruleId1: string; + let ruleId2: string; let alertId: string; let startedAt: string; - let actionId: string | undefined; + let actionId1: string | undefined; + let actionId2: string | undefined; const APM_ALERTS_INDEX = '.alerts-observability.apm.alerts-default'; - const ALERT_ACTION_INDEX_NAME = 'alert-action-transaction-error-rate'; + const ALERT_ACTION_INDEX_NAME1 = 'alert-action-transaction-error-rate1'; + const ALERT_ACTION_INDEX_NAME2 = 'alert-action-transaction-error-rate2'; before(async () => { const opbeansJava = apm @@ -66,6 +69,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { .transaction({ transactionName: 'tx-node' }) .timestamp(timestamp) .duration(400) + .failure(), + opbeansNode + .transaction({ transactionName: 'tx-node' }) + .timestamp(timestamp) + .duration(800) .success(), ]; }); @@ -74,12 +82,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { after(async () => { await synthtraceEsClient.clean(); - await supertest.delete(`/api/alerting/rule/${ruleId}`).set('kbn-xsrf', 'foo'); - await supertest.delete(`/api/actions/connector/${actionId}`).set('kbn-xsrf', 'foo'); - await esDeleteAllIndices([ALERT_ACTION_INDEX_NAME]); + await supertest.delete(`/api/alerting/rule/${ruleId1}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/actions/connector/${actionId1}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/alerting/rule/${ruleId2}`).set('kbn-xsrf', 'foo'); + await supertest.delete(`/api/actions/connector/${actionId2}`).set('kbn-xsrf', 'foo'); + await esDeleteAllIndices([ALERT_ACTION_INDEX_NAME1, ALERT_ACTION_INDEX_NAME2]); + await es.deleteByQuery({ + index: APM_ALERTS_INDEX, + query: { term: { 'kibana.alert.rule.uuid': ruleId1 } }, + }); await es.deleteByQuery({ index: APM_ALERTS_INDEX, - query: { term: { 'kibana.alert.rule.uuid': ruleId } }, + query: { term: { 'kibana.alert.rule.uuid': ruleId2 } }, }); await es.deleteByQuery({ index: '.kibana-event-log-*', @@ -87,17 +101,17 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - describe('create alert with transaction.name group by', () => { + describe('create alert without filter query', () => { before(async () => { - actionId = await createIndexConnector({ + actionId1 = await createIndexConnector({ supertest, - name: 'Transation error rate API test', - indexName: ALERT_ACTION_INDEX_NAME, + name: 'Transation error rate without filter query', + indexName: ALERT_ACTION_INDEX_NAME1, }); const createdRule = await createApmRule({ supertest, ruleTypeId: ApmRuleType.TransactionErrorRate, - name: 'Apm error rate duration', + name: 'Apm transaction error rate without filter query', params: { threshold: 50, windowSize: 5, @@ -105,6 +119,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { transactionType: 'request', serviceName: 'opbeans-java', environment: 'production', + kqlFilter: '', groupBy: [ 'service.name', 'service.environment', @@ -115,7 +130,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { actions: [ { group: 'threshold_met', - id: actionId, + id: actionId1, params: { documents: [ { @@ -133,12 +148,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { ], }); expect(createdRule.id).to.not.eql(undefined); - ruleId = createdRule.id; + ruleId1 = createdRule.id; }); it('checks if rule is active', async () => { const executionStatus = await waitForRuleStatus({ - id: ruleId, + id: ruleId1, expectedStatus: 'active', supertest, }); @@ -149,7 +164,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const resp = await waitForAlertInIndex({ es, indexName: APM_ALERTS_INDEX, - ruleId, + ruleId: ruleId1, }); alertId = (resp.hits.hits[0]._source as any)['kibana.alert.uuid']; startedAt = (resp.hits.hits[0]._source as any)['kibana.alert.start']; @@ -164,7 +179,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const rangeFrom = moment(startedAt).subtract('5', 'minute').toISOString(); const resp = await waitForDocumentInIndex<{ message: string }>({ es, - indexName: ALERT_ACTION_INDEX_NAME, + indexName: ALERT_ACTION_INDEX_NAME1, }); expect(resp.hits.hits[0]._source?.message).eql(`Transaction Name: tx-java @@ -195,5 +210,116 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(serviceTabAlertCount).to.be(0); }); }); + + describe('create alert with filter query', () => { + before(async () => { + actionId2 = await createIndexConnector({ + supertest, + name: 'Transation error rate without filter query', + indexName: ALERT_ACTION_INDEX_NAME2, + }); + const createdRule = await createApmRule({ + supertest, + ruleTypeId: ApmRuleType.TransactionErrorRate, + name: 'Apm transaction error rate without filter query', + params: { + threshold: 50, + windowSize: 5, + windowUnit: 'm', + transactionType: undefined, + serviceName: undefined, + environment: 'ENVIRONMENT_ALL', + kqlFilter: + 'service.name: opbeans-node and transaction.type: request and service.environment: production', + groupBy: [ + 'service.name', + 'service.environment', + 'transaction.type', + 'transaction.name', + ], + }, + actions: [ + { + group: 'threshold_met', + id: actionId2, + params: { + documents: [ + { + message: `Transaction Name: {{context.transactionName}} +- Alert URL: {{context.alertDetailsUrl}}`, + }, + ], + }, + frequency: { + notify_when: 'onActionGroupChange', + throttle: null, + summary: false, + }, + }, + ], + }); + expect(createdRule.id).to.not.eql(undefined); + ruleId2 = createdRule.id; + }); + + it('checks if rule is active', async () => { + const executionStatus = await waitForRuleStatus({ + id: ruleId2, + expectedStatus: 'active', + supertest, + }); + expect(executionStatus.status).to.be('active'); + }); + + it('indexes alert document with all group-by fields', async () => { + const resp = await waitForAlertInIndex({ + es, + indexName: APM_ALERTS_INDEX, + ruleId: ruleId2, + }); + alertId = (resp.hits.hits[0]._source as any)['kibana.alert.uuid']; + startedAt = (resp.hits.hits[0]._source as any)['kibana.alert.start']; + + expect(resp.hits.hits[0]._source).property('service.name', 'opbeans-node'); + expect(resp.hits.hits[0]._source).property('service.environment', 'production'); + expect(resp.hits.hits[0]._source).property('transaction.type', 'request'); + expect(resp.hits.hits[0]._source).property('transaction.name', 'tx-node'); + }); + + it('returns correct message', async () => { + const rangeFrom = moment(startedAt).subtract('5', 'minute').toISOString(); + const resp = await waitForDocumentInIndex<{ message: string }>({ + es, + indexName: ALERT_ACTION_INDEX_NAME2, + }); + + expect(resp.hits.hits[0]._source?.message).eql(`Transaction Name: tx-node +- Alert URL: http://mockedpublicbaseurl/app/observability/alerts?_a=(kuery:%27kibana.alert.uuid:%20%22${alertId}%22%27%2CrangeFrom:%27${rangeFrom}%27%2CrangeTo:now%2Cstatus:all)`); + }); + + it('shows the correct alert count for each service on service inventory', async () => { + const serviceInventoryAlertCounts = await fetchServiceInventoryAlertCounts(apmApiClient); + expect(serviceInventoryAlertCounts).to.eql({ + 'opbeans-node': 1, + 'opbeans-java': 1, + }); + }); + + it('shows the correct alert count in opbeans-java service', async () => { + const serviceTabAlertCount = await fetchServiceTabAlertCount({ + apmApiClient, + serviceName: 'opbeans-java', + }); + expect(serviceTabAlertCount).to.be(1); + }); + + it('shows the correct alert count in opbeans-node service', async () => { + const serviceTabAlertCount = await fetchServiceTabAlertCount({ + apmApiClient, + serviceName: 'opbeans-node', + }); + expect(serviceTabAlertCount).to.be(1); + }); + }); }); } From e09de7dda4fff2407553dd9bd14e9a078f3d30c3 Mon Sep 17 00:00:00 2001 From: Kevin Logan <56395104+kevinlog@users.noreply.github.com> Date: Tue, 15 Aug 2023 13:31:10 -0400 Subject: [PATCH 09/10] [Security Solution] Relax Endpoint metadata not found logging level (#163209) ## Summary This PR cleans up an error that we threw every time we called the Endpoint metadata service and did not find the relevant Endpoint ID. This happens when we look at Alerts and look up the Endpoint ID to see if it is a deployed Endpoint. It is a valid result that that we do not find the Endpoint and therefore disable actions such as Response Actions and Endpoint Exceptions. Before we were throwing errors in Kibana logs which was confusing users. With this change, we move the log to `debug` and respond with a "Not Found". Log in debug with this PR: image More information in this ticket: https://github.com/elastic/security-team/issues/6931 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/endpoint/routes/error_handler.ts | 16 ++++++++++++++-- .../metadata/endpoint_metadata_service.ts | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/error_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/error_handler.ts index 9b6de8ac0b6e0..f7ffa856d6f6c 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/error_handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/error_handler.ts @@ -8,7 +8,7 @@ import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { CustomHttpRequestError } from '../../utils/custom_http_request_error'; import { NotFoundError } from '../errors'; -import { EndpointHostUnEnrolledError } from '../services/metadata'; +import { EndpointHostUnEnrolledError, EndpointHostNotFoundError } from '../services/metadata'; /** * Default Endpoint Routes error handler @@ -21,7 +21,15 @@ export const errorHandler = ( res: KibanaResponseFactory, error: E ): IKibanaResponse => { - logger.error(error); + const shouldLogToDebug = () => { + return error instanceof EndpointHostNotFoundError; + }; + + if (shouldLogToDebug()) { + logger.debug(error.message); + } else { + logger.error(error); + } if (error instanceof CustomHttpRequestError) { return res.customError({ @@ -38,6 +46,10 @@ export const errorHandler = ( return res.badRequest({ body: error }); } + if (error instanceof EndpointHostNotFoundError) { + return res.notFound({ body: error }); + } + // Kibana CORE will take care of `500` errors when the handler `throw`'s, including logging the error throw error; }; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts b/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts index d5a973593f225..748e2c1058036 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts @@ -170,7 +170,7 @@ export class EndpointMetadataService { fleetAgent = await this.getFleetAgent(fleetServices.agent, fleetAgentId); } catch (error) { if (error instanceof FleetAgentNotFoundError) { - this.logger?.warn(`agent with id ${fleetAgentId} not found`); + this.logger?.debug(`agent with id ${fleetAgentId} not found`); } else { throw error; } From f9c9722c6f568d5e730f0b2826382ca0f5508e1e Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Tue, 15 Aug 2023 19:50:54 +0200 Subject: [PATCH 10/10] [Security Solution][Serverless] Reusing Cypress tests for Serverless infrastructure (#162698) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Patryk Kopycinski Co-authored-by: Georgii Gorbachev --- .buildkite/ftr_configs.yml | 1 + .buildkite/pipelines/pull_request/base.yml | 57 ++- .../pull_request/security_solution.yml | 13 +- .../scripts/steps/functional/response_ops.sh | 2 +- .../steps/functional/response_ops_cases.sh | 2 +- .../steps/functional/security_serverless.sh | 2 +- .../security_serverless_defend_workflows.sh | 13 + .../functional/security_serverless_explore.sh | 13 + .../security_serverless_investigations.sh | 13 + .../steps/functional/security_solution.sh | 2 +- .../functional/security_solution_burn.sh | 2 +- .../functional/security_solution_explore.sh | 2 +- .../security_solution_investigations.sh | 2 +- .github/CODEOWNERS | 49 ++- x-pack/plugins/osquery/package.json | 4 +- ...ts_detection_callouts_index_outdated.cy.ts | 193 ---------- ...t_rules_install_update_authorization.cy.ts | 123 ------ ..._rules_install_update_error_handling.cy.ts | 142 ------- ...built_rules_install_update_workflows.cy.ts | 262 ------------- .../prebuilt_rules_notifications.cy.ts | 183 --------- .../rule_actions/rule_actions.cy.ts | 72 ---- .../bulk_edit_rules_actions.cy.ts | 221 ----------- .../bulk_edit_rules_data_view.cy.ts | 242 ------------ .../endpoint_exceptions.cy.ts | 121 ------ .../auto_populate_with_alert_data.cy.ts | 194 ---------- .../add_edit_exception_data_view.cy.ts | 178 --------- .../manage_lists.cy.ts | 140 ------- ..._details_left_panel_correlations_tab.cy.ts | 87 ----- .../alert_details_right_panel.cy.ts | 231 ----------- ...ert_details_right_panel_overview_tab.cy.ts | 351 ----------------- .../timelines/unsaved_timeline.cy.ts | 167 -------- x-pack/plugins/security_solution/package.json | 16 +- .../scripts/run_cypress/parallel.ts | 10 +- .../cypress/tasks/login.ts | 6 +- .../plugins/threat_intelligence/package.json | 8 +- .../cypress/.eslintrc.json | 0 .../cypress/.gitignore | 0 .../cypress/README.md | 38 +- .../cypress/cypress.config.ts | 7 + .../cypress/cypress_ci.config.ts | 7 + .../cypress/cypress_ci_serverless.config.ts | 41 ++ .../cypress/cypress_serverless.config.ts | 38 ++ .../cypress/data/detection_engine.ts | 2 +- .../data_sources/create_runtime_field.cy.ts | 4 +- .../cypress/e2e/data_sources/sourcerer.cy.ts | 39 +- .../e2e/detection_alerts/alert_tags.cy.ts | 4 +- .../e2e/detection_alerts/alerts_charts.cy.ts | 4 +- ...ts_detection_callouts_index_outdated.cy.ts | 199 ++++++++++ .../detection_alerts/cti_enrichments.cy.ts | 4 +- .../e2e/detection_alerts/enrichments.cy.ts | 4 +- .../missing_privileges_callout.cy.ts | 6 +- .../ransomware_detection.cy.ts | 4 +- .../ransomware_prevention.cy.ts | 4 +- ...t_rules_install_update_authorization.cy.ts | 133 +++++++ ..._rules_install_update_error_handling.cy.ts | 151 ++++++++ ...built_rules_install_update_workflows.cy.ts | 270 +++++++++++++ .../prebuilt_rules_management.cy.ts | 4 +- .../prebuilt_rules_notifications.cy.ts | 192 ++++++++++ .../rule_actions/rule_actions.cy.ts | 78 ++++ .../rule_creation/custom_query_rule.cy.ts | 4 +- .../custom_query_rule_data_view.cy.ts | 4 +- .../custom_saved_query_rule.cy.ts | 4 +- .../event_correlation_rule.cy.ts | 8 +- .../rule_creation/indicator_match_rule.cy.ts | 4 +- .../rule_creation/machine_learning_rule.cy.ts | 4 +- .../rule_creation/new_terms_rule.cy.ts | 4 +- .../rule_creation/override.cy.ts | 4 +- .../rule_creation/threshold_rule.cy.ts | 4 +- .../authorization/all_rules_read_only.cy.ts | 6 +- .../maintenance_window_callout.cy.ts | 7 +- .../related_integrations.cy.ts | 4 +- .../bulk_actions/bulk_duplicate_rules.cy.ts | 4 +- .../bulk_actions/bulk_edit_rules.cy.ts | 4 +- .../bulk_edit_rules_actions.cy.ts | 226 +++++++++++ .../bulk_edit_rules_data_view.cy.ts | 255 +++++++++++++ .../import_export/export_rule.cy.ts | 3 +- .../import_export/import_rules.cy.ts | 4 +- .../rule_actions/snoozing/rule_snoozing.cy.ts | 6 +- .../rules_table_auto_refresh.cy.ts | 4 +- .../rules_table/rules_table_filtering.cy.ts | 4 +- .../rules_table/rules_table_links.cy.ts | 4 +- .../rules_table_persistent_state.cy.ts | 4 +- .../rules_table/rules_table_selection.cy.ts | 5 +- .../rules_table/rules_table_sorting.cy.ts | 4 +- .../value_lists/value_lists.cy.ts | 19 +- .../entity_analytics_management_page.cy.ts | 7 +- .../endpoint_exceptions.cy.ts | 127 +++++++ .../auto_populate_with_alert_data.cy.ts | 198 ++++++++++ .../closing_all_matching_alerts.cy.ts | 0 .../exceptions/entry/flyout_validation.cy.ts | 3 +- .../entry/multiple_conditions.cy.ts | 3 +- .../e2e/exceptions/entry/use_value_list.cy.ts | 4 +- .../add_edit_endpoint_exception.cy.ts | 3 +- .../add_edit_exception.cy.ts | 3 +- .../add_edit_exception_data_view.cy.ts | 183 +++++++++ .../rule_details_flow/read_only_view.cy.ts | 5 +- .../list_detail_page/list_details.cy.ts | 3 +- .../manage_exceptions.cy.ts | 3 +- .../duplicate_lists.cy.ts | 3 +- .../filter_table.cy.ts | 4 +- .../import_lists.cy.ts | 3 +- .../manage_lists.cy.ts | 146 +++++++ .../read_only.cy.ts | 5 +- .../explore/cases/attach_alert_to_case.cy.ts | 9 +- .../e2e/explore/cases/attach_timeline.cy.ts | 33 +- .../e2e/explore/cases/connector_options.cy.ts | 3 +- .../e2e/explore/cases/connectors.cy.ts | 3 +- .../cypress/e2e/explore/cases/creation.cy.ts | 7 +- .../e2e/explore/cases/privileges.cy.ts | 3 +- .../dashboards/enable_risk_score.cy.ts | 3 +- .../explore/dashboards/entity_analytics.cy.ts | 6 +- .../dashboards/upgrade_risk_score.cy.ts | 3 +- .../e2e/explore/filters/pinned_filters.cy.ts | 7 +- .../e2e/explore/guided_onboarding/tour.cy.ts | 79 ++-- .../e2e/explore/host_details/risk_tab.cy.ts | 3 +- .../e2e/explore/hosts/events_viewer.cy.ts | 3 +- .../e2e/explore/hosts/host_risk_tab.cy.ts | 3 +- .../e2e/explore/hosts/hosts_risk_column.cy.ts | 3 +- .../e2e/explore/network/hover_actions.cy.ts | 4 +- .../e2e/explore/network/overflow_items.cy.ts | 3 +- .../e2e/explore/overview/overview.cy.ts | 5 +- .../e2e/explore/pagination/pagination.cy.ts | 3 +- .../e2e/explore/users/user_details.cy.ts | 0 .../e2e/explore/users/users_tabs.cy.ts | 0 .../cypress/e2e/header/navigation.cy.ts | 5 +- .../cypress/e2e/header/search_bar.cy.ts | 3 +- .../cypress/e2e/inspect/inspect_button.cy.ts | 10 +- .../alerts/alert_table_action_column.cy.ts | 3 +- .../alerts/alert_table_controls.cy.ts | 0 .../alerts/alerts_cell_actions.cy.ts | 3 +- .../alerts/alerts_details.cy.ts | 4 +- .../alerts/building_block_alerts.cy.ts | 65 ++-- .../alerts/changing_alert_status.cy.ts | 5 +- .../alerts/detection_page_filters.cy.ts | 11 +- .../alerts/event_rendered_view.cy.ts | 0 ...etails_left_panel_analyzer_graph_tab.cy.ts | 52 +-- ..._details_left_panel_correlations_tab.cy.ts | 93 +++++ ...lert_details_left_panel_entities_tab.cy.ts | 55 +-- ...details_left_panel_investigation_tab.cy.ts | 41 +- ...rt_details_left_panel_prevalence_tab.cy.ts | 3 +- ...lert_details_left_panel_response_tab.cy.ts | 0 ..._details_left_panel_session_view_tab.cy.ts | 55 +-- ...s_left_panel_threat_intelligence_tab.cy.ts | 49 ++- ...t_details_preview_panel_rule_preview.cy.ts | 75 ++-- .../alert_details_right_panel.cy.ts | 239 ++++++++++++ .../alert_details_right_panel_json_tab.cy.ts | 39 +- ...ert_details_right_panel_overview_tab.cy.ts | 359 ++++++++++++++++++ .../alert_details_right_panel_table_tab.cy.ts | 77 ++-- .../alert_details_url_sync.cy.ts | 3 +- .../alerts/investigate_in_timeline.cy.ts | 3 +- .../investigations/alerts/navigation.cy.ts | 3 +- .../e2e/investigations/alerts/resolver.cy.ts | 3 +- .../dasbhoards/detection_response.cy.ts | 4 +- .../timeline_templates/creation.cy.ts | 3 +- .../timeline_templates/export.cy.ts | 3 +- .../timelines/bulk_add_to_timeline.cy.ts | 3 +- .../timelines/correlation_tab.cy.ts | 3 +- .../investigations/timelines/creation.cy.ts | 95 ++--- .../timelines/data_providers.cy.ts | 3 +- .../e2e/investigations/timelines/export.cy.ts | 3 +- .../timelines/fields_browser.cy.ts | 3 +- .../timelines/flyout_button.cy.ts | 17 +- .../timelines/full_screen.cy.ts | 3 +- .../investigations/timelines/inspect.cy.ts | 3 +- .../timelines/local_storage.cy.ts | 5 +- .../investigations/timelines/notes_tab.cy.ts | 3 +- .../timelines/open_timeline.cy.ts | 51 +-- .../investigations/timelines/overview.cy.tsx | 3 +- .../investigations/timelines/pagination.cy.ts | 5 +- .../investigations/timelines/query_tab.cy.ts | 5 +- .../timelines/row_renderers.cy.ts | 11 +- .../timelines/search_or_filter.cy.ts | 3 +- .../timelines/toggle_column.cy.ts | 3 +- .../timelines/unsaved_timeline.cy.ts | 200 ++++++++++ .../cypress/e2e/ml/ml_conditional_links.cy.ts | 3 +- .../cypress/e2e/overview/cti_link_panel.cy.ts | 3 +- .../cypress/e2e/urls/compatibility.cy.ts | 10 +- .../cypress/e2e/urls/not_found.cy.ts | 4 +- .../cypress/e2e/urls/state.cy.ts | 4 +- .../cypress/fixtures/7_15_timeline.ndjson | 0 .../cypress/fixtures/7_16_case.ndjson | 0 .../fixtures/7_16_exception_list.ndjson | 0 .../cypress/fixtures/7_16_rules.ndjson | 0 .../cypress/fixtures/cidr_list.txt | 0 .../cypress/fixtures/ip_list.txt | 0 .../fixtures/related_integrations.ndjson | 0 .../cypress/fixtures/value_list.txt | 0 .../cypress/helpers/common.ts | 0 .../cypress/helpers/rules.ts | 6 +- .../cypress/objects/case.ts | 0 .../cypress/objects/connector.ts | 0 .../cypress/objects/exception.ts | 0 .../cypress/objects/filter.ts | 0 .../cypress/objects/rule.ts | 4 +- .../cypress/objects/timeline.ts | 2 +- .../cypress/objects/types.ts | 0 .../cypress/reporter_config.json | 0 .../cypress/screens/alerts.ts | 0 .../cypress/screens/alerts_details.ts | 0 .../cypress/screens/alerts_detection_rules.ts | 0 .../cypress/screens/all_cases.ts | 0 .../cypress/screens/case_details.ts | 0 .../cypress/screens/common.ts | 0 .../cypress/screens/common/callouts.ts | 0 .../cypress/screens/common/controls.ts | 0 .../cypress/screens/common/data_grid.ts | 0 .../cypress/screens/common/filter_group.ts | 0 .../cypress/screens/common/page.ts | 0 .../cypress/screens/common/rule_actions.ts | 0 .../cypress/screens/configure_cases.ts | 0 .../cypress/screens/create_new_case.ts | 0 .../cypress/screens/create_new_rule.ts | 0 .../cypress/screens/create_runtime_field.ts | 0 .../cypress/screens/dashboards/common.ts | 0 .../cypress/screens/date_picker.ts | 0 .../cypress/screens/detection_response.ts | 0 .../cypress/screens/edit_connector.ts | 0 .../cypress/screens/edit_rule.ts | 0 .../cypress/screens/entity_analytics.ts | 0 .../screens/entity_analytics_management.ts | 0 .../cypress/screens/exceptions.ts | 0 .../alert_details_left_panel.ts | 7 +- ...t_details_left_panel_analyzer_graph_tab.ts | 4 +- ...ert_details_left_panel_correlations_tab.ts | 6 +- .../alert_details_left_panel_entities_tab.ts | 4 +- ...rt_details_left_panel_investigation_tab.ts | 4 +- ...alert_details_left_panel_prevalence_tab.ts | 4 +- .../alert_details_left_panel_response_tab.ts | 4 +- ...ert_details_left_panel_session_view_tab.ts | 4 +- ...ails_left_panel_threat_intelligence_tab.ts | 2 +- ...lert_details_preview_panel_rule_preview.ts | 2 +- .../alert_details_right_panel.ts | 6 +- .../alert_details_right_panel_json_tab.ts | 2 +- .../alert_details_right_panel_overview_tab.ts | 4 +- .../alert_details_right_panel_table_tab.ts | 2 +- .../screens/expandable_flyout/common.ts | 0 .../cypress/screens/fields_browser.ts | 0 .../cypress/screens/guided_onboarding.ts | 0 .../cypress/screens/hosts/all_hosts.ts | 0 .../cypress/screens/hosts/authentications.ts | 0 .../cypress/screens/hosts/events.ts | 0 .../cypress/screens/hosts/host_risk.ts | 0 .../cypress/screens/hosts/main.ts | 0 .../screens/hosts/uncommon_processes.ts | 0 .../cypress/screens/inspect.ts | 0 .../cypress/screens/integrations.ts | 0 .../cypress/screens/kibana_navigation.ts | 0 .../cypress/screens/lists.ts | 0 .../cypress/screens/loading.ts | 0 .../cypress/screens/network/dns.ts | 0 .../cypress/screens/network/flows.ts | 0 .../cypress/screens/network/http.ts | 0 .../cypress/screens/network/tls.ts | 0 .../cypress/screens/overview.ts | 0 .../cypress/screens/rule_details.ts | 0 .../cypress/screens/rule_snoozing.ts | 0 .../cypress/screens/rules_bulk_actions.ts | 0 .../cypress/screens/saved_objects.ts | 0 .../cypress/screens/search_bar.ts | 0 .../cypress/screens/security_header.ts | 0 .../cypress/screens/security_main.ts | 0 .../cypress/screens/shared.ts | 0 .../cypress/screens/sourcerer.ts | 0 .../cypress/screens/table_pagination.ts | 0 .../cypress/screens/templates.ts | 0 .../cypress/screens/timeline.ts | 0 .../cypress/screens/timelines.ts | 0 .../cypress/screens/users/all_users.ts | 0 .../cypress/screens/users/user_anomalies.ts | 0 .../screens/users/user_authentications.ts | 0 .../cypress/screens/users/user_events.ts | 0 .../cypress/screens/users/user_risk_score.ts | 0 .../cypress/support/commands.js | 0 .../cypress/support/e2e.js | 0 .../cypress/support/es_archiver.ts | 18 +- .../cypress/support/index.d.ts | 0 .../security_solution_cypress/cypress/tags.ts | 12 + .../cypress/tasks/alerts.ts | 4 +- .../cypress/tasks/alerts_details.ts | 0 .../cypress/tasks/alerts_detection_rules.ts | 0 .../cypress/tasks/all_cases.ts | 3 - .../cypress/tasks/api_calls/cases.ts | 2 +- .../cypress/tasks/api_calls/connectors.ts | 2 +- .../cypress/tasks/api_calls/elasticsearch.ts | 6 +- .../cypress/tasks/api_calls/exceptions.ts | 12 +- .../cypress/tasks/api_calls/fleet.ts | 15 +- .../api_calls/kibana_advanced_settings.ts | 2 +- .../cypress/tasks/api_calls/notes.ts | 2 +- .../cypress/tasks/api_calls/prebuilt_rules.ts | 35 +- .../cypress/tasks/api_calls/risk_engine.ts | 4 +- .../tasks/api_calls/risk_scores/index.ts | 2 +- .../tasks/api_calls/risk_scores/indices.ts | 6 +- .../api_calls/risk_scores/ingest_pipelines.ts | 4 +- .../api_calls/risk_scores/saved_objects.ts | 6 +- .../api_calls/risk_scores/stored_scripts.ts | 4 +- .../cypress/tasks/api_calls/rules.ts | 23 +- .../cypress/tasks/api_calls/saved_queries.ts | 0 .../cypress/tasks/api_calls/timelines.ts | 10 +- .../cypress/tasks/api_calls/tour.ts | 6 +- .../cypress/tasks/case_details.ts | 0 .../cypress/tasks/common.ts | 18 +- .../cypress/tasks/common/callouts.ts | 0 .../cypress/tasks/common/event_table.ts | 0 .../cypress/tasks/common/filter_group.ts | 0 .../cypress/tasks/common/rule_actions.ts | 0 .../cypress/tasks/configure_cases.ts | 0 .../cypress/tasks/create_new_case.ts | 0 .../cypress/tasks/create_new_rule.ts | 18 +- .../cypress/tasks/create_runtime_field.ts | 0 .../cypress/tasks/dashboards/common.ts | 0 .../cypress/tasks/date_picker.ts | 0 .../cypress/tasks/edit_rule.ts | 0 .../cypress/tasks/entity_analytics.ts | 0 .../cypress/tasks/exceptions.ts | 0 .../cypress/tasks/exceptions_table.ts | 0 .../alert_details_left_panel.ts | 0 ...t_details_left_panel_analyzer_graph_tab.ts | 0 ...ert_details_left_panel_correlations_tab.ts | 0 .../alert_details_left_panel_entities_tab.ts | 0 ...rt_details_left_panel_investigation_tab.ts | 0 ...alert_details_left_panel_prevalence_tab.ts | 0 .../alert_details_left_panel_response_tab.ts | 0 ...ails_left_panel_threat_intelligence_tab.ts | 0 ...lert_details_preview_panel_rule_preview.ts | 0 .../alert_details_right_panel.ts | 0 .../alert_details_right_panel_json_tab.ts | 0 .../alert_details_right_panel_overview_tab.ts | 2 +- .../alert_details_right_panel_table_tab.ts | 0 .../cypress/tasks/expandable_flyout/common.ts | 0 .../cypress/tasks/fields_browser.ts | 0 .../cypress/tasks/guided_onboarding.ts | 0 .../cypress/tasks/host_risk.ts | 0 .../cypress/tasks/hosts/all_hosts.ts | 0 .../cypress/tasks/hosts/events.ts | 0 .../cypress/tasks/hosts/main.ts | 0 .../cypress/tasks/hosts/uncommon_processes.ts | 0 .../cypress/tasks/inspect.ts | 0 .../cypress/tasks/integrations.ts | 0 .../cypress/tasks/kibana_navigation.ts | 0 .../cypress/tasks/lists.ts | 11 +- .../cypress/tasks/login.ts | 41 +- .../cypress/tasks/network/flows.ts | 0 .../cypress/tasks/overview.ts | 0 .../cypress/tasks/prebuilt_rules.ts | 2 +- .../cypress/tasks/privileges.ts | 8 +- .../cypress/tasks/risk_scores/common.ts | 0 .../cypress/tasks/risk_scores/index.ts | 0 .../cypress/tasks/risk_scores/indices.ts | 0 .../tasks/risk_scores/ingest_pipelines.ts | 0 .../tasks/risk_scores/saved_objects.ts | 0 .../tasks/risk_scores/stored_scripts.ts | 0 .../cypress/tasks/risk_scores/transforms.ts | 30 +- .../cypress/tasks/rule_details.ts | 0 .../cypress/tasks/rule_filters.ts | 0 .../cypress/tasks/rule_snoozing.ts | 0 .../cypress/tasks/rules_bulk_actions.ts | 0 .../cypress/tasks/saved_objects.ts | 0 .../cypress/tasks/search_bar.ts | 0 .../cypress/tasks/security_header.ts | 0 .../cypress/tasks/security_main.ts | 0 .../cypress/tasks/sourcerer.ts | 4 +- .../cypress/tasks/table_pagination.ts | 0 .../cypress/tasks/templates.ts | 0 .../cypress/tasks/timeline.ts | 11 +- .../cypress/tasks/timelines.ts | 0 .../cypress/tsconfig.json | 3 +- .../cypress/urls/ml_conditional_links.ts | 0 .../cypress/urls/navigation.ts | 0 .../cypress/urls/risk_score.ts | 0 .../cypress/urls/routes.ts | 0 .../cypress/urls/state.ts | 0 .../security_solution_cypress/package.json | 26 ++ .../serverless_config.ts | 38 ++ x-pack/test/tsconfig.json | 4 +- 374 files changed, 4337 insertions(+), 3684 deletions(-) create mode 100644 .buildkite/scripts/steps/functional/security_serverless_defend_workflows.sh create mode 100644 .buildkite/scripts/steps/functional/security_serverless_explore.sh create mode 100644 .buildkite/scripts/steps/functional/security_serverless_investigations.sh delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts delete mode 100644 x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/.eslintrc.json (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/.gitignore (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/README.md (77%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/cypress.config.ts (82%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/cypress_ci.config.ts (83%) create mode 100644 x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/data/detection_engine.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/data_sources/create_runtime_field.cy.ts (94%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/data_sources/sourcerer.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_alerts/alert_tags.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_alerts/alerts_charts.cy.ts (94%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_alerts/cti_enrichments.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_alerts/enrichments.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_alerts/ransomware_detection.cy.ts (94%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts (94%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_management.cy.ts (98%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts (99%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts (99%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/machine_learning_rule.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/override.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/maintenance_windows/maintenance_window_callout.cy.ts (83%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts (99%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/rule_management/rules_table/rules_table_sorting.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/detection_response/value_lists/value_lists.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts (96%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/entry/flyout_validation.cy.ts (99%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/entry/use_value_list.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts (98%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/filter_table.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts (96%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts (88%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/cases/attach_timeline.cy.ts (77%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/cases/connector_options.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/cases/connectors.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/cases/creation.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/cases/privileges.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/dashboards/entity_analytics.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/filters/pinned_filters.cy.ts (83%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/guided_onboarding/tour.cy.ts (57%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/host_details/risk_tab.cy.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/hosts/events_viewer.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/hosts/host_risk_tab.cy.ts (94%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts (90%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/network/hover_actions.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/network/overflow_items.cy.ts (94%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/overview/overview.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/pagination/pagination.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/users/user_details.cy.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/explore/users/users_tabs.cy.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/header/navigation.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/header/search_bar.cy.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/inspect/inspect_button.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/alert_table_action_column.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/alert_table_controls.cy.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/alerts_details.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts (50%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/event_rendered_view.cy.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts (57%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts (54%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts (61%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts (51%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts (60%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts (53%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts (57%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts (50%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/navigation.cy.ts (94%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/alerts/resolver.cy.ts (92%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timeline_templates/creation.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timeline_templates/export.cy.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/bulk_add_to_timeline.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/correlation_tab.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/creation.cy.ts (58%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/data_providers.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/export.cy.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/fields_browser.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/flyout_button.cy.ts (86%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/full_screen.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/inspect.cy.ts (89%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/local_storage.cy.ts (88%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/notes_tab.cy.ts (97%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/open_timeline.cy.ts (67%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/overview.cy.tsx (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/pagination.cy.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/query_tab.cy.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/row_renderers.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/search_or_filter.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/investigations/timelines/toggle_column.cy.ts (92%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/ml/ml_conditional_links.cy.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/overview/cti_link_panel.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/urls/compatibility.cy.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/urls/not_found.cy.ts (95%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/e2e/urls/state.cy.ts (99%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/7_15_timeline.ndjson (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/7_16_case.ndjson (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/7_16_exception_list.ndjson (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/7_16_rules.ndjson (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/cidr_list.txt (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/ip_list.txt (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/related_integrations.ndjson (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/fixtures/value_list.txt (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/helpers/common.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/helpers/rules.ts (90%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/objects/case.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/objects/connector.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/objects/exception.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/objects/filter.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/objects/rule.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/objects/timeline.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/objects/types.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/reporter_config.json (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/alerts.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/alerts_details.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/alerts_detection_rules.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/all_cases.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/case_details.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/common.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/common/callouts.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/common/controls.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/common/data_grid.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/common/filter_group.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/common/page.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/common/rule_actions.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/configure_cases.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/create_new_case.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/create_new_rule.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/create_runtime_field.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/dashboards/common.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/date_picker.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/detection_response.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/edit_connector.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/edit_rule.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/entity_analytics.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/entity_analytics_management.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/exceptions.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel.ts (81%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts (71%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts (86%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts (82%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_investigation_tab.ts (72%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts (90%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts (71%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts (71%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts (89%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_right_panel.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts (80%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts (94%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/expandable_flyout/common.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/fields_browser.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/guided_onboarding.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/hosts/all_hosts.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/hosts/authentications.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/hosts/events.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/hosts/host_risk.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/hosts/main.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/hosts/uncommon_processes.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/inspect.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/integrations.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/kibana_navigation.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/lists.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/loading.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/network/dns.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/network/flows.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/network/http.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/network/tls.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/overview.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/rule_details.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/rule_snoozing.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/rules_bulk_actions.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/saved_objects.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/search_bar.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/security_header.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/security_main.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/shared.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/sourcerer.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/table_pagination.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/templates.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/timeline.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/timelines.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/users/all_users.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/users/user_anomalies.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/users/user_authentications.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/users/user_events.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/screens/users/user_risk_score.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/support/commands.js (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/support/e2e.js (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/support/es_archiver.ts (68%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/support/index.d.ts (100%) create mode 100644 x-pack/test/security_solution_cypress/cypress/tags.ts rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/alerts.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/alerts_details.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/alerts_detection_rules.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/all_cases.ts (87%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/cases.ts (88%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/connectors.ts (87%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/elasticsearch.ts (86%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/exceptions.ts (84%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/fleet.ts (74%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/kibana_advanced_settings.ts (90%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/notes.ts (84%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/prebuilt_rules.ts (83%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/risk_engine.ts (85%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/risk_scores/index.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/risk_scores/indices.ts (81%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/risk_scores/ingest_pipelines.ts (79%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/risk_scores/saved_objects.ts (83%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/risk_scores/stored_scripts.ts (81%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/rules.ts (77%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/saved_queries.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/timelines.ts (86%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/api_calls/tour.ts (77%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/case_details.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/common.ts (94%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/common/callouts.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/common/event_table.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/common/filter_group.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/common/rule_actions.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/configure_cases.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/create_new_case.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/create_new_rule.ts (99%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/create_runtime_field.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/dashboards/common.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/date_picker.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/edit_rule.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/entity_analytics.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/exceptions.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/exceptions_table.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel_entities_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel_investigation_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel_prevalence_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel_response_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_preview_panel_rule_preview.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_right_panel.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_right_panel_json_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_right_panel_overview_tab.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/expandable_flyout/common.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/fields_browser.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/guided_onboarding.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/host_risk.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/hosts/all_hosts.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/hosts/events.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/hosts/main.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/hosts/uncommon_processes.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/inspect.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/integrations.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/kibana_navigation.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/lists.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/login.ts (88%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/network/flows.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/overview.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/prebuilt_rules.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/privileges.ts (93%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/risk_scores/common.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/risk_scores/index.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/risk_scores/indices.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/risk_scores/ingest_pipelines.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/risk_scores/saved_objects.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/risk_scores/stored_scripts.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/risk_scores/transforms.ts (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/rule_details.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/rule_filters.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/rule_snoozing.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/rules_bulk_actions.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/saved_objects.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/search_bar.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/security_header.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/security_main.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/sourcerer.ts (96%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/table_pagination.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/templates.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/timeline.ts (98%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tasks/timelines.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/tsconfig.json (91%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/urls/ml_conditional_links.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/urls/navigation.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/urls/risk_score.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/urls/routes.ts (100%) rename x-pack/{plugins/security_solution => test/security_solution_cypress}/cypress/urls/state.ts (100%) create mode 100644 x-pack/test/security_solution_cypress/package.json create mode 100644 x-pack/test/security_solution_cypress/serverless_config.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 720e9c0eb6234..ca6914bcf2ac0 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -46,6 +46,7 @@ disabled: - x-pack/plugins/apm/ftr_e2e/ftr_config.ts - x-pack/test_serverless/functional/test_suites/observability/cypress/config_headless.ts - x-pack/test_serverless/functional/test_suites/observability/cypress/config_runner.ts + - x-pack/test/security_solution_cypress/serverless_config.ts - x-pack/plugins/profiling/e2e/ftr_config_open.ts - x-pack/plugins/profiling/e2e/ftr_config_runner.ts - x-pack/plugins/profiling/e2e/ftr_config.ts diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index cfae5749f8013..aeb15233a85ae 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -94,13 +94,14 @@ steps: automatic: - exit_status: '-1' limit: 3 - + - command: .buildkite/scripts/steps/functional/security_serverless.sh label: 'Serverless Security Cypress Tests' agents: queue: n2-4-spot depends_on: build timeout_in_minutes: 40 + parallelism: 10 soft_fail: - exit_status: 10 retry: @@ -110,8 +111,60 @@ steps: - exit_status: '*' limit: 1 artifact_paths: - - "target/kibana-security-serverless/**/*" + - "target/kibana-security-solution/**/*" + - command: .buildkite/scripts/steps/functional/security_serverless_defend_workflows.sh + label: 'Serverless Security Defend Workflows Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 40 + soft_fail: + - exit_status: 10 + retry: + automatic: + - exit_status: '-1' + limit: 3 + - exit_status: '*' + limit: 1 + artifact_paths: + - "target/kibana-security-solution/**/*" + + - command: .buildkite/scripts/steps/functional/security_serverless_investigations.sh + label: 'Serverless Security Investigations Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 40 + parallelism: 4 + soft_fail: + - exit_status: 10 + retry: + automatic: + - exit_status: '-1' + limit: 3 + - exit_status: '*' + limit: 1 + artifact_paths: + - "target/kibana-security-solution/**/*" + + - command: .buildkite/scripts/steps/functional/security_serverless_explore.sh + label: 'Serverless Security Explore Cypress Tests' + agents: + queue: n2-4-spot + depends_on: build + timeout_in_minutes: 40 + parallelism: 2 + soft_fail: + - exit_status: 10 + retry: + automatic: + - exit_status: '-1' + limit: 3 + - exit_status: '*' + limit: 1 + artifact_paths: + - "target/kibana-security-solution/**/*" - command: .buildkite/scripts/steps/lint.sh label: 'Linting' diff --git a/.buildkite/pipelines/pull_request/security_solution.yml b/.buildkite/pipelines/pull_request/security_solution.yml index 9444c821d5db1..2b73e9482b156 100644 --- a/.buildkite/pipelines/pull_request/security_solution.yml +++ b/.buildkite/pipelines/pull_request/security_solution.yml @@ -11,15 +11,4 @@ steps: - exit_status: '*' limit: 1 artifact_paths: - - "target/kibana-security-solution/**/*" - - - command: .buildkite/scripts/steps/functional/security_solution_burn.sh - label: 'Security Solution Cypress tests, burning changed specs' - agents: - queue: n2-4-spot - depends_on: build - timeout_in_minutes: 120 - parallelism: 1 - soft_fail: true - artifact_paths: - - "target/kibana-security-solution/**/*" + - "target/kibana-security-solution/**/*" \ No newline at end of file diff --git a/.buildkite/scripts/steps/functional/response_ops.sh b/.buildkite/scripts/steps/functional/response_ops.sh index 6e61ac3b65ed9..ad603752c1239 100755 --- a/.buildkite/scripts/steps/functional/response_ops.sh +++ b/.buildkite/scripts/steps/functional/response_ops.sh @@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} echo "--- Response Ops Cypress Tests on Security Solution" -yarn --cwd x-pack/plugins/security_solution cypress:run:respops +yarn --cwd x-pack/test/security_solution_cypress cypress:run:respops:ess diff --git a/.buildkite/scripts/steps/functional/response_ops_cases.sh b/.buildkite/scripts/steps/functional/response_ops_cases.sh index 07a736d0c2342..6d4cac8ef4472 100755 --- a/.buildkite/scripts/steps/functional/response_ops_cases.sh +++ b/.buildkite/scripts/steps/functional/response_ops_cases.sh @@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} echo "--- Response Ops Cases Cypress Tests on Security Solution" -yarn --cwd x-pack/plugins/security_solution cypress:run:cases +yarn --cwd x-pack/test/security_solution_cypress cypress:run:cases:ess diff --git a/.buildkite/scripts/steps/functional/security_serverless.sh b/.buildkite/scripts/steps/functional/security_serverless.sh index 6271c8b2e823e..bd156deb583f0 100644 --- a/.buildkite/scripts/steps/functional/security_serverless.sh +++ b/.buildkite/scripts/steps/functional/security_serverless.sh @@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} echo "--- Security Serverless Cypress" -yarn --cwd x-pack/test_serverless/functional/test_suites/security/cypress cypress:run +yarn --cwd x-pack/test/security_solution_cypress cypress:run:serverless diff --git a/.buildkite/scripts/steps/functional/security_serverless_defend_workflows.sh b/.buildkite/scripts/steps/functional/security_serverless_defend_workflows.sh new file mode 100644 index 0000000000000..323f1fc2224f1 --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_serverless_defend_workflows.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/steps/functional/common_cypress.sh + +export JOB=kibana-serverless-security-cypress +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- Security Defend Workflows Serverless Cypress" + +yarn --cwd x-pack/test_serverless/functional/test_suites/security/cypress cypress:run \ No newline at end of file diff --git a/.buildkite/scripts/steps/functional/security_serverless_explore.sh b/.buildkite/scripts/steps/functional/security_serverless_explore.sh new file mode 100644 index 0000000000000..d443e25cf82ad --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_serverless_explore.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/steps/functional/common_cypress.sh + +export JOB=kibana-security-solution-chrome +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- Explore Cypress Tests on Serverless" + +yarn --cwd x-pack/test/security_solution_cypress cypress:explore:run:serverless diff --git a/.buildkite/scripts/steps/functional/security_serverless_investigations.sh b/.buildkite/scripts/steps/functional/security_serverless_investigations.sh new file mode 100644 index 0000000000000..57989361049b5 --- /dev/null +++ b/.buildkite/scripts/steps/functional/security_serverless_investigations.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/steps/functional/common.sh +source .buildkite/scripts/steps/functional/common_cypress.sh + +export JOB=kibana-security-solution-chrome +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} + +echo "--- Investigations Cypress Tests on Serverless" + +yarn --cwd x-pack/test/security_solution_cypress cypress:investigations:run:serverless diff --git a/.buildkite/scripts/steps/functional/security_solution.sh b/.buildkite/scripts/steps/functional/security_solution.sh index 5890b463f7735..fdddc8573cff1 100755 --- a/.buildkite/scripts/steps/functional/security_solution.sh +++ b/.buildkite/scripts/steps/functional/security_solution.sh @@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} echo "--- Security Solution Cypress tests (Chrome)" -yarn --cwd x-pack/plugins/security_solution cypress:run +yarn --cwd x-pack/test/security_solution_cypress cypress:run:ess diff --git a/.buildkite/scripts/steps/functional/security_solution_burn.sh b/.buildkite/scripts/steps/functional/security_solution_burn.sh index f8b809dbbdac1..755c5c6cd049d 100755 --- a/.buildkite/scripts/steps/functional/security_solution_burn.sh +++ b/.buildkite/scripts/steps/functional/security_solution_burn.sh @@ -12,4 +12,4 @@ buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" 'fals echo "--- Security Solution Cypress tests, burning changed specs (Chrome)" -yarn --cwd x-pack/plugins/security_solution cypress:changed-specs-only +yarn --cwd x-pack/test/security_solution_cypress cypress:changed-specs-only:ess diff --git a/.buildkite/scripts/steps/functional/security_solution_explore.sh b/.buildkite/scripts/steps/functional/security_solution_explore.sh index 6a13b09d15167..ff373dd8238e1 100644 --- a/.buildkite/scripts/steps/functional/security_solution_explore.sh +++ b/.buildkite/scripts/steps/functional/security_solution_explore.sh @@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} echo "--- Explore Cypress Tests on Security Solution" -yarn --cwd x-pack/plugins/security_solution cypress:explore:run +yarn --cwd x-pack/test/security_solution_cypress cypress:explore:run:ess diff --git a/.buildkite/scripts/steps/functional/security_solution_investigations.sh b/.buildkite/scripts/steps/functional/security_solution_investigations.sh index e5685ac9dcb51..2ba771a0d658d 100644 --- a/.buildkite/scripts/steps/functional/security_solution_investigations.sh +++ b/.buildkite/scripts/steps/functional/security_solution_investigations.sh @@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} echo "--- Investigations Cypress Tests on Security Solution" -yarn --cwd x-pack/plugins/security_solution cypress:investigations:run +yarn --cwd x-pack/test/security_solution_cypress cypress:investigations:run:ess diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7197ed867b5e0..89e4a2c008727 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1087,7 +1087,7 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/common/search_strategy/timeline @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/common/types/timeline @elastic/security-threat-hunting-investigations -/x-pack/plugins/security_solution/cypress/e2e/investigations @elastic/security-threat-hunting-investigations +/x-pack/test/security_solution_cypress/cypress/e2e/investigations @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/common/components/alerts_viewer @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_action @elastic/security-threat-hunting-investigations @@ -1111,12 +1111,11 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/common/search_strategy/security_solution/network @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/common/search_strategy/security_solution/user @elastic/security-threat-hunting-explore -/x-pack/plugins/security_solution/cypress/e2e/explore @elastic/security-threat-hunting-explore -/x-pack/plugins/security_solution/cypress/screens/hosts @elastic/security-threat-hunting-explore -/x-pack/plugins/security_solution/cypress/screens/network @elastic/security-threat-hunting-explore -/x-pack/plugins/security_solution/cypress/tasks/hosts @elastic/security-threat-hunting-explore -/x-pack/plugins/security_solution/cypress/tasks/network @elastic/security-threat-hunting-explore -/x-pack/plugins/security_solution/cypress/upgrade_e2e/threat_hunting/cases @elastic/security-threat-hunting-explore +/x-pack/test/security_solution_cypress/cypress/e2e/explore @elastic/security-threat-hunting-explore +/x-pack/test/security_solution_cypress/cypress/screens/hosts @elastic/security-threat-hunting-explore +/x-pack/test/security_solution_cypress/cypress/screens/network @elastic/security-threat-hunting-explore +/x-pack/test/security_solution_cypress/cypress/tasks/hosts @elastic/security-threat-hunting-explore +/x-pack/test/security_solution_cypress/cypress/tasks/network @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/common/components/charts @elastic/security-threat-hunting-explore @@ -1168,8 +1167,8 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/common/detection_engine/rule_management @elastic/security-detection-rule-management /x-pack/plugins/security_solution/common/detection_engine/rule_monitoring @elastic/security-detection-rule-management -/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules @elastic/security-detection-rule-management -/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management @elastic/security-detection-rule-management +/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules @elastic/security-detection-rule-management +/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management @elastic/security-detection-rule-management /x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules @elastic/security-detection-rule-management /x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/rule_management @elastic/security-detection-rule-management @@ -1216,12 +1215,12 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/server/lib/detection_engine/routes/index @elastic/security-detection-engine /x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals @elastic/security-detection-engine -/x-pack/plugins/security_solution/cypress/e2e/data_sources @elastic/security-detection-engine -/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation @elastic/security-detection-engine -/x-pack/plugins/security_solution/cypress/e2e/detection_response/value_lists @elastic/security-detection-engine -/x-pack/plugins/security_solution/cypress/e2e/entity_analytics @elastic/security-detection-engine -/x-pack/plugins/security_solution/cypress/e2e/exceptions @elastic/security-detection-engine -/x-pack/plugins/security_solution/cypress/e2e/overview @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/data_sources @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/exceptions @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/overview @elastic/security-detection-engine /x-pack/plugins/security_solution/common/detection_engine/rule_exceptions @elastic/security-detection-engine @@ -1240,14 +1239,14 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/public/common/components/threat_match @elastic/security-detection-engine ## Security Solution cross teams ownership -/x-pack/plugins/security_solution/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/plugins/security_solution/cypress/helpers @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/plugins/security_solution/cypress/e2e/detection_rules @elastic/security-detection-rule-management @elastic/security-detection-engine -/x-pack/plugins/security_solution/cypress/objects @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/plugins/security_solution/cypress/plugins @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/plugins/security_solution/cypress/screens/common @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/plugins/security_solution/cypress/support @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/plugins/security_solution/cypress/urls @elastic/security-threat-hunting-investigations @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/helpers @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/e2e/detection_rules @elastic/security-detection-rule-management @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/objects @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/plugins @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/screens/common @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/support @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/urls @elastic/security-threat-hunting-investigations @elastic/security-detection-engine /x-pack/plugins/security_solution/common/ecs @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/common/test @elastic/security-detection-rule-management @elastic/security-detection-engine @@ -1283,9 +1282,7 @@ x-pack/plugins/security_solution/server/usage/ @elastic/security-data-analytics x-pack/plugins/security_solution/server/lib/telemetry/ @elastic/security-data-analytics ## Security Solution sub teams - security-engineering-productivity -x-pack/plugins/security_solution/cypress/ccs_e2e @elastic/security-engineering-productivity -x-pack/plugins/security_solution/cypress/upgrade_e2e @elastic/security-engineering-productivity -x-pack/plugins/security_solution/cypress/README.md @elastic/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 ## Security Solution sub teams - adaptive-workload-protection diff --git a/x-pack/plugins/osquery/package.json b/x-pack/plugins/osquery/package.json index 13ec9d29f13a7..91b9cf67d361c 100644 --- a/x-pack/plugins/osquery/package.json +++ b/x-pack/plugins/osquery/package.json @@ -5,8 +5,8 @@ "private": true, "license": "Elastic License 2.0", "scripts": { - "cypress:open": "node ../security_solution/scripts/start_cypress_parallel open --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/osquery_cypress/cli_config", - "cypress:run": "node ../security_solution/scripts/start_cypress_parallel run --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/osquery_cypress/cli_config --concurrency 1", + "cypress:open": "node ../security_solution/scripts/start_cypress_parallel open --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../x-pack/test/osquery_cypress/cli_config", + "cypress:run": "node ../security_solution/scripts/start_cypress_parallel run --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../x-pack/test/osquery_cypress/cli_config --concurrency 1", "nyc": "../../../node_modules/.bin/nyc report --reporter=text-summary" } } diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts deleted file mode 100644 index a091af3cc1417..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts +++ /dev/null @@ -1,193 +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 { ROLES } from '../../../common/test'; -import { DETECTIONS_RULE_MANAGEMENT_URL, ALERTS_URL } from '../../urls/navigation'; -import { getNewRule } from '../../objects/rule'; -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'; - -const loadPageAsPlatformEngineerUser = (url: string) => { - login(ROLES.soc_manager); - waitForPageWithoutDateRange(url, ROLES.soc_manager); - waitForPageTitleToBeShown(); -}; - -const waitForPageTitleToBeShown = () => { - cy.get(PAGE_TITLE).should('be.visible'); -}; - -describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => { - 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. - login(); - visitWithoutDateRange(ALERTS_URL); - waitForPageTitleToBeShown(); - }); - - context( - 'The users index_mapping_outdated is "true" and their admin callouts should show up', - () => { - beforeEach(() => { - // Index mapping outdated is forced to return true as being outdated so that we get the - // need admin callouts being shown. - cy.intercept('GET', '/api/detection_engine/index', (req) => { - req.reply((res) => { - res.send(200, { - index_mapping_outdated: true, - name: '.alerts-security.alerts-default', - }); - }); - }); - }); - - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(ALERTS_URL); - }); - - it('We show the need admin primary callout', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show 1 primary callout of need admin', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createRule(getNewRule({ rule_id: 'rule_testing' })); - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show 1 primary callout', () => { - waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); - }); - }); - } - ); - - context( - 'The users index_mapping_outdated is "false" and their admin callouts should not show up ', - () => { - beforeEach(() => { - // Index mapping outdated is forced to return true as being outdated so that we get the - // need admin callouts being shown. - cy.intercept('GET', '/api/detection_engine/index', { - index_mapping_outdated: false, - name: '.alerts-security.alerts-default', - }); - }); - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(ALERTS_URL); - }); - - it('We show the need admin primary callout', () => { - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show 1 primary callout of need admin', () => { - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createRule(getNewRule({ rule_id: 'rule_testing' })); - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show 1 primary callout', () => { - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - } - ); - - context( - 'The users index_mapping_outdated is "null" and their admin callouts should not show up ', - () => { - beforeEach(() => { - // Index mapping outdated is forced to return true as being outdated so that we get the - // need admin callouts being shown. - cy.intercept('GET', '/api/detection_engine/index', { - index_mapping_outdated: null, - name: '.alerts-security.alerts-default', - }); - }); - context('On Detections home page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(ALERTS_URL); - }); - - it('We show the need admin primary callout', () => { - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rules Management page', () => { - beforeEach(() => { - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - }); - - it('We show 1 primary callout of need admin', () => { - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - - context('On Rule Details page', () => { - beforeEach(() => { - createRule(getNewRule({ rule_id: 'rule_testing' })); - loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); - waitForPageTitleToBeShown(); - goToRuleDetails(); - }); - - afterEach(() => { - deleteCustomRule(); - }); - - it('We show 1 primary callout', () => { - getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); - }); - }); - } - ); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts deleted file mode 100644 index 202fb6766fc6f..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts +++ /dev/null @@ -1,123 +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 { APP_PATH, RULES_ADD_PATH, RULES_UPDATES } from '../../../../common/constants'; -import { createRuleAssetSavedObject } from '../../../helpers/rules'; -import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules'; -import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules'; -import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common'; -import { login, waitForPageWithoutDateRange } from '../../../tasks/login'; -import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; -import { ROLES } from '../../../../common/test'; -import { - ADD_ELASTIC_RULES_BTN, - getInstallSingleRuleButtonByRuleId, - getUpgradeSingleRuleButtonByRuleId, - INSTALL_ALL_RULES_BUTTON, - RULES_UPDATES_TAB, - RULE_CHECKBOX, - UPGRADE_ALL_RULES_BUTTON, -} from '../../../screens/alerts_detection_rules'; - -const RULE_1_ID = 'rule_1'; -const RULE_2_ID = 'rule_2'; -const OUTDATED_RULE_1 = createRuleAssetSavedObject({ - name: 'Outdated rule 1', - rule_id: RULE_1_ID, - version: 1, -}); -const UPDATED_RULE_1 = createRuleAssetSavedObject({ - name: 'Updated rule 1', - rule_id: RULE_1_ID, - version: 2, -}); -const OUTDATED_RULE_2 = createRuleAssetSavedObject({ - name: 'Outdated rule 2', - rule_id: RULE_2_ID, - version: 1, -}); -const UPDATED_RULE_2 = createRuleAssetSavedObject({ - name: 'Updated rule 2', - rule_id: RULE_2_ID, - version: 2, -}); - -const loadPageAsReadOnlyUser = (url: string) => { - login(ROLES.reader); - waitForPageWithoutDateRange(url, ROLES.reader); -}; - -describe('Detection rules, Prebuilt Rules Installation and Update - Authorization/RBAC', () => { - beforeEach(() => { - login(); - resetRulesTableState(); - deleteAlertsAndRules(); - cy.task('esArchiverResetKibana'); - waitForRulesTableToBeLoaded(); - createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); - }); - - describe('User with read privileges on Security Solution', () => { - const RULE_1 = createRuleAssetSavedObject({ - name: 'Test rule 1', - rule_id: 'rule_1', - }); - const RULE_2 = createRuleAssetSavedObject({ - name: 'Test rule 2', - rule_id: 'rule_2', - }); - beforeEach(() => { - // Now login with read-only user in preparation for test - createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false }); - loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - }); - - it('should not be able to install prebuilt rules', () => { - // Check that Add Elastic Rules button is disabled - cy.get(ADD_ELASTIC_RULES_BTN).should('be.disabled'); - - // Navigate to Add Elastic Rules page anyways via URL - // and assert that rules cannot be selected and all - // installation buttons are disabled - cy.visit(`${APP_PATH}${RULES_ADD_PATH}`); - cy.get(INSTALL_ALL_RULES_BUTTON).should('be.disabled'); - cy.get(getInstallSingleRuleButtonByRuleId(RULE_1['security-rule'].rule_id)).should( - 'not.exist' - ); - cy.get(RULE_CHECKBOX).should('not.exist'); - }); - }); - - describe('User with read privileges on Security Solution', () => { - beforeEach(() => { - /* Create a second version of the rule, making it available for update */ - createAndInstallMockedPrebuiltRules({ - rules: [UPDATED_RULE_1, UPDATED_RULE_2], - installToKibana: false, - }); - // Now login with read-only user in preparation for test - loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - }); - - it('should not be able to upgrade prebuilt rules', () => { - // Check that Rule Update tab is not shown - cy.get(RULES_UPDATES_TAB).should('not.exist'); - - // Navigate to Rule Update tab anyways via URL - // and assert that rules cannot be selected and all - // upgrade buttons are disabled - cy.visit(`${APP_PATH}${RULES_UPDATES}`); - cy.get(UPGRADE_ALL_RULES_BUTTON).should('be.disabled'); - cy.get(getUpgradeSingleRuleButtonByRuleId(OUTDATED_RULE_1['security-rule'].rule_id)).should( - 'not.exist' - ); - cy.get(RULE_CHECKBOX).should('not.exist'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts deleted file mode 100644 index 9016816589610..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts +++ /dev/null @@ -1,142 +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 { createRuleAssetSavedObject } from '../../../helpers/rules'; -import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules'; -import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules'; -import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; -import { - addElasticRulesButtonClick, - assertRuleAvailableForInstallAndInstallOne, - assertRuleAvailableForInstallAndInstallSelected, - assertRuleAvailableForInstallAndInstallAllInPage, - assertRuleAvailableForInstallAndInstallAll, - assertRuleUpgradeAvailableAndUpgradeOne, - assertRuleUpgradeAvailableAndUpgradeSelected, - assertRuleUpgradeAvailableAndUpgradeAllInPage, - assertRuleUpgradeAvailableAndUpgradeAll, - ruleUpdatesTabClick, -} from '../../../tasks/prebuilt_rules'; - -describe('Detection rules, Prebuilt Rules Installation and Update - Error handling', () => { - beforeEach(() => { - login(); - resetRulesTableState(); - deleteAlertsAndRules(); - cy.task('esArchiverResetKibana'); - - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - }); - - describe('Installation of prebuilt rules - Should fail gracefully with toast error message when', () => { - const RULE_1 = createRuleAssetSavedObject({ - name: 'Test rule 1', - rule_id: 'rule_1', - }); - const RULE_2 = createRuleAssetSavedObject({ - name: 'Test rule 2', - rule_id: 'rule_2', - }); - beforeEach(() => { - createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false }); - waitForRulesTableToBeLoaded(); - }); - - it('installing prebuilt rules one by one', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1], didRequestFail: true }); - }); - - it('installing multiple selected prebuilt rules by selecting them individually', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallSelected({ - rules: [RULE_1, RULE_2], - didRequestFail: true, - }); - }); - - it('installing multiple selected prebuilt rules by selecting all in page', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallAllInPage({ - rules: [RULE_1, RULE_2], - didRequestFail: true, - }); - }); - - it('installing all available rules at once', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallAll({ rules: [RULE_1, RULE_2], didRequestFail: true }); - }); - }); - - describe('Update of prebuilt rules - Should fail gracefully with toast error message when', () => { - const RULE_1_ID = 'rule_1'; - const RULE_2_ID = 'rule_2'; - const OUTDATED_RULE_1 = createRuleAssetSavedObject({ - name: 'Outdated rule 1', - rule_id: RULE_1_ID, - version: 1, - }); - const UPDATED_RULE_1 = createRuleAssetSavedObject({ - name: 'Updated rule 1', - rule_id: RULE_1_ID, - version: 2, - }); - const OUTDATED_RULE_2 = createRuleAssetSavedObject({ - name: 'Outdated rule 2', - rule_id: RULE_2_ID, - version: 1, - }); - const UPDATED_RULE_2 = createRuleAssetSavedObject({ - name: 'Updated rule 2', - rule_id: RULE_2_ID, - version: 2, - }); - beforeEach(() => { - /* Create a new rule and install it */ - createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); - /* Create a second version of the rule, making it available for update */ - createAndInstallMockedPrebuiltRules({ - rules: [UPDATED_RULE_1, UPDATED_RULE_2], - installToKibana: false, - }); - waitForRulesTableToBeLoaded(); - reload(); - }); - - it('upgrading prebuilt rules one by one', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1], didRequestFail: true }); - }); - - it('upgrading multiple selected prebuilt rules by selecting them individually', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeSelected({ - rules: [OUTDATED_RULE_1, OUTDATED_RULE_2], - didRequestFail: true, - }); - }); - - it('upgrading multiple selected prebuilt rules by selecting all in page', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeAllInPage({ - rules: [OUTDATED_RULE_1, OUTDATED_RULE_2], - didRequestFail: true, - }); - }); - - it('upgrading all rules with available upgrades at once', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeAll({ - rules: [OUTDATED_RULE_1, OUTDATED_RULE_2], - didRequestFail: true, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts deleted file mode 100644 index f148e973300dd..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts +++ /dev/null @@ -1,262 +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 { BulkInstallPackageInfo } from '@kbn/fleet-plugin/common'; -import type { Rule } from '../../../../public/detection_engine/rule_management/logic/types'; -import { createRuleAssetSavedObject } from '../../../helpers/rules'; -import { - GO_BACK_TO_RULES_TABLE_BUTTON, - INSTALL_ALL_RULES_BUTTON, - INSTALL_SELECTED_RULES_BUTTON, - NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE, - NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE, - RULES_UPDATES_TAB, - RULE_CHECKBOX, - SELECT_ALL_RULES_ON_PAGE_CHECKBOX, - TOASTER, -} from '../../../screens/alerts_detection_rules'; -import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules'; -import { - getRuleAssets, - createAndInstallMockedPrebuiltRules, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; -import { - addElasticRulesButtonClick, - assertRuleAvailableForInstallAndInstallOne, - assertRuleAvailableForInstallAndInstallSelected, - assertRuleAvailableForInstallAndInstallAllInPage, - assertRuleAvailableForInstallAndInstallAll, - assertRuleUpgradeAvailableAndUpgradeOne, - assertRuleUpgradeAvailableAndUpgradeSelected, - assertRuleUpgradeAvailableAndUpgradeAllInPage, - assertRuleUpgradeAvailableAndUpgradeAll, - ruleUpdatesTabClick, -} from '../../../tasks/prebuilt_rules'; - -describe('Detection rules, Prebuilt Rules Installation and Update workflow', () => { - beforeEach(() => { - login(); - resetRulesTableState(); - deleteAlertsAndRules(); - cy.task('esArchiverResetKibana'); - - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - }); - - describe('Installation of prebuilt rules package via Fleet', () => { - beforeEach(() => { - cy.intercept('POST', '/api/fleet/epm/packages/_bulk*').as('installPackageBulk'); - cy.intercept('POST', '/api/fleet/epm/packages/security_detection_engine/*').as( - 'installPackage' - ); - waitForRulesTableToBeLoaded(); - }); - - it('should install package from Fleet in the background', () => { - /* Assert that the package in installed from Fleet */ - cy.wait('@installPackageBulk', { - timeout: 60000, - }).then(({ response: bulkResponse }) => { - cy.wrap(bulkResponse?.statusCode).should('eql', 200); - - const packages = bulkResponse?.body.items.map( - ({ name, result }: BulkInstallPackageInfo) => ({ - name, - }) - ); - - const packagesBulkInstalled = packages.map(({ name }: { name: string }) => name); - - // Under normal flow the package is installed via the Fleet bulk install API. - // However, for testing purposes the package can be installed via the Fleet individual install API, - // so we need to intercept and wait for that request as well. - if (!packagesBulkInstalled.includes('security_detection_engine')) { - // Should happen only during testing when the `xpack.securitySolution.prebuiltRulesPackageVersion` flag is set - cy.wait('@installPackage').then(({ response }) => { - cy.wrap(response?.statusCode).should('eql', 200); - cy.wrap(response?.body) - .should('have.property', 'items') - .should('have.length.greaterThan', 0); - }); - } else { - // Normal flow, install via the Fleet bulk install API - expect(packages.length).to.have.greaterThan(0); - // At least one of the packages installed should be the security_detection_engine package - expect(packages).to.satisfy((pckgs: BulkInstallPackageInfo[]) => - pckgs.some((pkg) => pkg.name === 'security_detection_engine') - ); - } - }); - }); - - it('should install rules from the Fleet package when user clicks on CTA', () => { - const getRulesAndAssertNumberInstalled = () => { - getRuleAssets().then((response) => { - const ruleIds = response.body.hits.hits.map( - (hit: { _source: { ['security-rule']: Rule } }) => hit._source['security-rule'].rule_id - ); - - const numberOfRulesToInstall = new Set(ruleIds).size; - addElasticRulesButtonClick(); - - cy.get(INSTALL_ALL_RULES_BUTTON).should('be.enabled').click(); - cy.get(TOASTER) - .should('be.visible') - .should('have.text', `${numberOfRulesToInstall} rules installed successfully.`); - }); - }; - /* Retrieve how many rules were installed from the Fleet package */ - /* See comments in test above for more details */ - cy.wait('@installPackageBulk', { - timeout: 60000, - }).then(({ response: bulkResponse }) => { - cy.wrap(bulkResponse?.statusCode).should('eql', 200); - - const packagesBulkInstalled = bulkResponse?.body.items.map( - ({ name }: { name: string }) => name - ); - - if (!packagesBulkInstalled.includes('security_detection_engine')) { - cy.wait('@installPackage').then(() => { - getRulesAndAssertNumberInstalled(); - }); - } else { - getRulesAndAssertNumberInstalled(); - } - }); - }); - }); - - describe('Installation of prebuilt rules', () => { - const RULE_1 = createRuleAssetSavedObject({ - name: 'Test rule 1', - rule_id: 'rule_1', - }); - const RULE_2 = createRuleAssetSavedObject({ - name: 'Test rule 2', - rule_id: 'rule_2', - }); - beforeEach(() => { - createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false }); - waitForRulesTableToBeLoaded(); - cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform').as( - 'installPrebuiltRules' - ); - }); - - it('should install prebuilt rules one by one', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1] }); - }); - - it('should install multiple selected prebuilt rules by selecting them individually', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallSelected({ rules: [RULE_1, RULE_2] }); - }); - - it('should install multiple selected prebuilt rules by selecting all in page', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallAllInPage({ rules: [RULE_1, RULE_2] }); - }); - - it('should install all available rules at once', () => { - addElasticRulesButtonClick(); - assertRuleAvailableForInstallAndInstallAll({ rules: [RULE_1, RULE_2] }); - }); - - it('should display an empty screen when all available prebuilt rules have been installed', () => { - addElasticRulesButtonClick(); - cy.get(INSTALL_ALL_RULES_BUTTON).click(); - cy.get(TOASTER).should('be.visible').should('have.text', `2 rules installed successfully.`); - cy.get(RULE_CHECKBOX).should('not.exist'); - cy.get(NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE).should('exist'); - cy.get(GO_BACK_TO_RULES_TABLE_BUTTON).should('exist'); - }); - - it('should fail gracefully with toast error message when request to install rules fails', () => { - /* Stub request to force rules installation to fail */ - cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform', { - statusCode: 500, - }).as('installPrebuiltRules'); - addElasticRulesButtonClick(); - cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click(); - cy.get(INSTALL_SELECTED_RULES_BUTTON).click(); - cy.wait('@installPrebuiltRules'); - cy.get(TOASTER).should('be.visible').should('have.text', 'Rule installation failed'); - }); - }); - - describe('Upgrade of prebuilt rules', () => { - const RULE_1_ID = 'rule_1'; - const RULE_2_ID = 'rule_2'; - const OUTDATED_RULE_1 = createRuleAssetSavedObject({ - name: 'Outdated rule 1', - rule_id: RULE_1_ID, - version: 1, - }); - const UPDATED_RULE_1 = createRuleAssetSavedObject({ - name: 'Updated rule 1', - rule_id: RULE_1_ID, - version: 2, - }); - const OUTDATED_RULE_2 = createRuleAssetSavedObject({ - name: 'Outdated rule 2', - rule_id: RULE_2_ID, - version: 1, - }); - const UPDATED_RULE_2 = createRuleAssetSavedObject({ - name: 'Updated rule 2', - rule_id: RULE_2_ID, - version: 2, - }); - beforeEach(() => { - cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/upgrade/_perform').as( - 'updatePrebuiltRules' - ); - /* Create a new rule and install it */ - createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); - /* Create a second version of the rule, making it available for update */ - createAndInstallMockedPrebuiltRules({ - rules: [UPDATED_RULE_1, UPDATED_RULE_2], - installToKibana: false, - }); - waitForRulesTableToBeLoaded(); - reload(); - }); - - it('should upgrade prebuilt rules one by one', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1] }); - }); - - it('should upgrade multiple selected prebuilt rules by selecting them individually', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeSelected({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); - }); - - it('should upgrade multiple selected prebuilt rules by selecting all in page', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeAllInPage({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); - }); - - it('should upgrade all rules with available upgrades at once', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); - cy.get(RULES_UPDATES_TAB).should('not.exist'); - }); - - it('should display an empty screen when all rules with available updates have been upgraded', () => { - ruleUpdatesTabClick(); - assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); - cy.get(RULES_UPDATES_TAB).should('not.exist'); - cy.get(NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE).should('exist'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts deleted file mode 100644 index 9fb1dcf16cbfe..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts +++ /dev/null @@ -1,183 +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 { createRuleAssetSavedObject } from '../../../helpers/rules'; -import { ADD_ELASTIC_RULES_BTN, RULES_UPDATES_TAB } from '../../../screens/alerts_detection_rules'; -import { - deleteFirstRule, - waitForRulesTableToBeLoaded, -} from '../../../tasks/alerts_detection_rules'; -import { - installAllPrebuiltRulesRequest, - createAndInstallMockedPrebuiltRules, -} from '../../../tasks/api_calls/prebuilt_rules'; -import { - resetRulesTableState, - deleteAlertsAndRules, - reload, - deletePrebuiltRulesAssets, -} from '../../../tasks/common'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; - -const RULE_1 = createRuleAssetSavedObject({ - name: 'Test rule 1', - rule_id: 'rule_1', -}); - -describe('Detection rules, Prebuilt Rules Installation and Update Notifications', () => { - beforeEach(() => { - login(); - /* Make sure persisted rules table state is cleared */ - resetRulesTableState(); - deleteAlertsAndRules(); - deletePrebuiltRulesAssets(); - }); - - describe('No notifications', () => { - it('should NOT display install or update notifications when no prebuilt assets and no rules are installed', () => { - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - // TODO: test plan asserts "should NOT see a CTA to install prebuilt rules" - // but current behavior is to always show the CTA, even with no prebuilt rule assets installed - // Update that behaviour and then update this test. - cy.get(RULES_UPDATES_TAB).should('not.exist'); - }); - - it('should NOT display install or update notifications when latest rules are installed', () => { - createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: true }); - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - - /* Assert that there are no installation or update notifications */ - /* Add Elastic Rules button should not contain a number badge */ - /* and Rule Upgrade tab should not be displayed */ - cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', 'Add Elastic rules'); - cy.get(RULES_UPDATES_TAB).should('not.exist'); - }); - }); - - describe('Notifications', () => { - beforeEach(() => { - createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: false }); - }); - - describe('Rules installation notification when no rules have been installed', () => { - beforeEach(() => { - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - }); - - it('should notify user about prebuilt rules available for installation', () => { - cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible'); - cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`); - cy.get(RULES_UPDATES_TAB).should('not.exist'); - }); - }); - - describe('Rule installation notification when at least one rule already installed', () => { - beforeEach(() => { - installAllPrebuiltRulesRequest().then(() => { - /* Create new rule assets with a different rule_id as the one that was */ - /* installed before in order to trigger the installation notification */ - const RULE_2 = createRuleAssetSavedObject({ - name: 'Test rule 2', - rule_id: 'rule_2', - }); - const RULE_3 = createRuleAssetSavedObject({ - name: 'Test rule 3', - rule_id: 'rule_3', - }); - - createAndInstallMockedPrebuiltRules({ rules: [RULE_2, RULE_3], installToKibana: false }); - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - }); - }); - - it('should notify user about prebuilt rules available for installation', () => { - const numberOfAvailableRules = 2; - cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible'); - cy.get(ADD_ELASTIC_RULES_BTN).should( - 'have.text', - `Add Elastic rules${numberOfAvailableRules}` - ); - cy.get(RULES_UPDATES_TAB).should('not.exist'); - }); - - it('should notify user a rule is again available for installation if it is deleted', () => { - /* Install available rules, assert that the notification is gone */ - /* then delete one rule and assert that the notification is back */ - installAllPrebuiltRulesRequest().then(() => { - reload(); - deleteFirstRule(); - cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible'); - cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`); - }); - }); - }); - - describe('Rule update notification', () => { - beforeEach(() => { - installAllPrebuiltRulesRequest().then(() => { - /* Create new rule asset with the same rule_id as the one that was installed */ - /* but with a higher version, in order to trigger the update notification */ - const UPDATED_RULE = createRuleAssetSavedObject({ - name: 'Test rule 1.1 (updated)', - rule_id: 'rule_1', - version: 2, - }); - createAndInstallMockedPrebuiltRules({ rules: [UPDATED_RULE], installToKibana: false }); - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - reload(); - }); - }); - - it('should notify user about prebuilt rules package available for update', () => { - // No rules available for installation - cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules`); - // But 1 rule available for update - cy.get(RULES_UPDATES_TAB).should('be.visible'); - cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`); - }); - }); - - describe('Rule installation available and rule update available notifications', () => { - beforeEach(() => { - installAllPrebuiltRulesRequest().then(() => { - /* Create new rule assets with a different rule_id as the one that was */ - /* installed before in order to trigger the installation notification */ - const RULE_2 = createRuleAssetSavedObject({ - name: 'Test rule 2', - rule_id: 'rule_2', - }); - /* Create new rule asset with the same rule_id as the one that was installed */ - /* but with a higher version, in order to trigger the update notification */ - const UPDATED_RULE = createRuleAssetSavedObject({ - name: 'Test rule 1.1 (updated)', - rule_id: 'rule_1', - version: 2, - }); - createAndInstallMockedPrebuiltRules({ - rules: [RULE_2, UPDATED_RULE], - installToKibana: false, - }); - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - }); - }); - - it('should notify user about prebuilt rules available for installation and for upgrade', () => { - // 1 rule available for installation - cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`); - // 1 rule available for update - cy.get(RULES_UPDATES_TAB).should('be.visible'); - cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts deleted file mode 100644 index 58bf0726918c0..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts +++ /dev/null @@ -1,72 +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 { getIndexConnector } from '../../../objects/connector'; -import { getSimpleCustomQueryRule } from '../../../objects/rule'; - -import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -import { deleteIndex, waitForNewDocumentToBeIndexed } from '../../../tasks/api_calls/elasticsearch'; -import { - cleanKibana, - deleteAlertsAndRules, - deleteConnectors, - deleteDataView, -} from '../../../tasks/common'; -import { - createAndEnableRule, - fillAboutRuleAndContinue, - fillDefineCustomRuleAndContinue, - fillRuleAction, - fillScheduleRuleAndContinue, -} from '../../../tasks/create_new_rule'; -import { login, visit } from '../../../tasks/login'; - -import { RULE_CREATION } from '../../../urls/navigation'; - -describe('Rule actions during detection rule creation', () => { - const indexConnector = getIndexConnector(); - - before(() => { - cleanKibana(); - }); - - beforeEach(() => { - login(); - deleteAlertsAndRules(); - deleteConnectors(); - deleteIndex(indexConnector.index); - deleteDataView(indexConnector.index); - }); - - const rule = getSimpleCustomQueryRule(); - const actions = { connectors: [indexConnector] }; - const index = actions.connectors[0].index; - const initialNumberOfDocuments = 0; - const expectedJson = JSON.parse(actions.connectors[0].document); - - it('Indexes a new document after the index action is triggered ', function () { - visit(RULE_CREATION); - fillDefineCustomRuleAndContinue(rule); - fillAboutRuleAndContinue(rule); - fillScheduleRuleAndContinue(rule); - fillRuleAction(actions); - createAndEnableRule(); - goToRuleDetails(); - - /* When the rule is executed, the action is triggered. We wait for the new document to be indexed */ - waitForNewDocumentToBeIndexed(index, initialNumberOfDocuments); - - /* We assert that the new indexed document is the one set on the index action */ - cy.request({ - method: 'GET', - url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_search`, - headers: { 'kbn-xsrf': 'cypress-creds' }, - }).then((response) => { - expect(response.body.hits.hits[0]._source).to.deep.equal(expectedJson); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts deleted file mode 100644 index 386d0be97d2a8..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts +++ /dev/null @@ -1,221 +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 { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types'; -import { ROLES } from '../../../../../../common/test'; - -import { - RULES_BULK_EDIT_ACTIONS_INFO, - RULES_BULK_EDIT_ACTIONS_WARNING, - ADD_RULE_ACTIONS_MENU_ITEM, -} from '../../../../../screens/rules_bulk_actions'; -import { actionFormSelector } from '../../../../../screens/common/rule_actions'; - -import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common'; -import type { RuleActionCustomFrequency } from '../../../../../tasks/common/rule_actions'; -import { - addSlackRuleAction, - assertSlackRuleAction, - addEmailConnectorAndRuleAction, - assertEmailRuleAction, - assertSelectedCustomFrequencyOption, - assertSelectedPerRuleRunFrequencyOption, - assertSelectedSummaryOfAlertsOption, - pickCustomFrequencyOption, - pickPerRuleRunFrequencyOption, - pickSummaryOfAlertsOption, -} from '../../../../../tasks/common/rule_actions'; -import { - waitForRulesTableToBeLoaded, - selectNumberOfRules, - goToEditRuleActionsSettingsOf, -} from '../../../../../tasks/alerts_detection_rules'; -import { - waitForBulkEditActionToFinish, - submitBulkEditForm, - checkOverwriteRuleActionsCheckbox, - openBulkEditRuleActionsForm, - openBulkActionsMenu, -} from '../../../../../tasks/rules_bulk_actions'; -import { login, visitWithoutDateRange } from '../../../../../tasks/login'; - -import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation'; - -import { createRule } from '../../../../../tasks/api_calls/rules'; -import { createSlackConnector } from '../../../../../tasks/api_calls/connectors'; - -import { - getEqlRule, - getNewThreatIndicatorRule, - getNewRule, - getNewThresholdRule, - getMachineLearningRule, - getNewTermsRule, -} from '../../../../../objects/rule'; -import { excessivelyInstallAllPrebuiltRules } from '../../../../../tasks/api_calls/prebuilt_rules'; - -const ruleNameToAssert = 'Custom rule name with actions'; -const expectedNumberOfCustomRulesToBeEdited = 7; -// 7 custom rules of different types + 3 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 expectedExistingSlackMessage = 'Existing slack action'; -const expectedSlackMessage = 'Slack action test message'; - -// TODO: Fix flakiness and unskip https://github.com/elastic/kibana/issues/154721 -describe.skip('Detection rules, bulk edit of rule actions', () => { - before(() => { - cleanKibana(); - login(); - }); - - beforeEach(() => { - deleteAlertsAndRules(); - deleteConnectors(); - cy.task('esArchiverResetKibana'); - - createSlackConnector().then(({ body }) => { - const actions: RuleActionArray = [ - { - id: body.id, - action_type_id: '.slack', - group: 'default', - params: { - message: expectedExistingSlackMessage, - }, - frequency: { - summary: true, - throttle: null, - notifyWhen: 'onActiveAlert', - }, - }, - ]; - - createRule(getNewRule({ name: ruleNameToAssert, rule_id: '1', max_signals: 500, actions })); - }); - - createRule(getEqlRule({ rule_id: '2' })); - createRule(getMachineLearningRule({ rule_id: '3' })); - createRule(getNewThreatIndicatorRule({ rule_id: '4' })); - createRule(getNewThresholdRule({ rule_id: '5' })); - createRule(getNewTermsRule({ rule_id: '6' })); - createRule(getNewRule({ saved_id: 'mocked', rule_id: '7' })); - - createSlackConnector(); - }); - - 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); - waitForRulesTableToBeLoaded(); - - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); - - openBulkActionsMenu(); - - cy.get(ADD_RULE_ACTIONS_MENU_ITEM).should('be.disabled'); - }); - }); - - context('All actions privileges', () => { - beforeEach(() => { - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - waitForRulesTableToBeLoaded(); - }); - - it('Add a rule action to rules (existing connector)', () => { - const expectedActionFrequency: RuleActionCustomFrequency = { - throttle: 1, - throttleUnit: 'd', - }; - - excessivelyInstallAllPrebuiltRules(); - - // select both custom and prebuilt rules - selectNumberOfRules(expectedNumberOfRulesToBeEdited); - openBulkEditRuleActionsForm(); - - // ensure rule actions info callout displayed on the form - cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible'); - - addSlackRuleAction(expectedSlackMessage); - pickSummaryOfAlertsOption(); - pickCustomFrequencyOption(expectedActionFrequency); - - submitBulkEditForm(); - waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited }); - - // check if rule has been updated - goToEditRuleActionsSettingsOf(ruleNameToAssert); - - assertSelectedSummaryOfAlertsOption(); - assertSelectedCustomFrequencyOption(expectedActionFrequency, 1); - assertSlackRuleAction(expectedExistingSlackMessage, 0); - assertSlackRuleAction(expectedSlackMessage, 1); - // ensure there is no third action - cy.get(actionFormSelector(2)).should('not.exist'); - }); - - it('Overwrite rule actions in rules', () => { - excessivelyInstallAllPrebuiltRules(); - - // select both custom and prebuilt rules - selectNumberOfRules(expectedNumberOfRulesToBeEdited); - openBulkEditRuleActionsForm(); - - addSlackRuleAction(expectedSlackMessage); - pickSummaryOfAlertsOption(); - pickPerRuleRunFrequencyOption(); - - // check overwrite box, ensure warning is displayed - checkOverwriteRuleActionsCheckbox(); - cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains( - `You're about to overwrite rule actions for ${expectedNumberOfRulesToBeEdited} selected rules` - ); - - submitBulkEditForm(); - waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited }); - - // check if rule has been updated - goToEditRuleActionsSettingsOf(ruleNameToAssert); - - assertSelectedSummaryOfAlertsOption(); - assertSelectedPerRuleRunFrequencyOption(); - assertSlackRuleAction(expectedSlackMessage); - // ensure existing action was overwritten - cy.get(actionFormSelector(1)).should('not.exist'); - }); - - it('Add a rule action to rules (new connector)', () => { - const expectedActionFrequency: RuleActionCustomFrequency = { - throttle: 2, - throttleUnit: 'h', - }; - const expectedEmail = 'test@example.com'; - const expectedSubject = 'Subject'; - - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); - openBulkEditRuleActionsForm(); - - addEmailConnectorAndRuleAction(expectedEmail, expectedSubject); - pickSummaryOfAlertsOption(); - pickCustomFrequencyOption(expectedActionFrequency); - - submitBulkEditForm(); - waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited }); - - // check if rule has been updated - goToEditRuleActionsSettingsOf(ruleNameToAssert); - - assertSelectedSummaryOfAlertsOption(); - assertSelectedCustomFrequencyOption(expectedActionFrequency, 1); - assertEmailRuleAction(expectedEmail, expectedSubject); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts deleted file mode 100644 index 16fd49767fcc4..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts +++ /dev/null @@ -1,242 +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 { - RULES_BULK_EDIT_DATA_VIEWS_WARNING, - RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX, -} from '../../../../../screens/rules_bulk_actions'; - -import { DATA_VIEW_DETAILS, INDEX_PATTERNS_DETAILS } from '../../../../../screens/rule_details'; - -import { - waitForRulesTableToBeLoaded, - goToRuleDetails, - selectNumberOfRules, - goToTheRuleDetailsOf, -} from '../../../../../tasks/alerts_detection_rules'; - -import { - typeIndexPatterns, - waitForBulkEditActionToFinish, - submitBulkEditForm, - checkOverwriteDataViewCheckbox, - checkOverwriteIndexPatternsCheckbox, - openBulkEditAddIndexPatternsForm, - openBulkEditDeleteIndexPatternsForm, -} from '../../../../../tasks/rules_bulk_actions'; - -import { - hasIndexPatterns, - getDetails, - assertDetailsNotExist, -} from '../../../../../tasks/rule_details'; -import { login, visitWithoutDateRange } from '../../../../../tasks/login'; - -import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation'; -import { createRule } from '../../../../../tasks/api_calls/rules'; -import { cleanKibana, deleteAlertsAndRules, postDataView } from '../../../../../tasks/common'; - -import { - getEqlRule, - getNewThreatIndicatorRule, - getNewRule, - getNewThresholdRule, - getNewTermsRule, -} from '../../../../../objects/rule'; - -const DATA_VIEW_ID = 'auditbeat'; - -const expectedIndexPatterns = ['index-1-*', 'index-2-*']; - -const expectedNumberOfCustomRulesToBeEdited = 6; - -describe('Bulk editing index patterns of rules with a data view only', () => { - before(() => { - cleanKibana(); - }); - - beforeEach(() => { - deleteAlertsAndRules(); - cy.task('esArchiverResetKibana'); - login(); - - postDataView(DATA_VIEW_ID); - - createRule(getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '1' })); - createRule(getEqlRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '2' })); - createRule( - getNewThreatIndicatorRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '3' }) - ); - createRule(getNewThresholdRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '4' })); - createRule(getNewTermsRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '5' })); - createRule( - getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, saved_id: 'mocked', rule_id: '6' }) - ); - - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - - waitForRulesTableToBeLoaded(); - }); - - it('Add index patterns to custom rules with configured data view: all rules are skipped', () => { - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); - - openBulkEditAddIndexPatternsForm(); - typeIndexPatterns(expectedIndexPatterns); - submitBulkEditForm(); - - waitForBulkEditActionToFinish({ - skippedCount: expectedNumberOfCustomRulesToBeEdited, - showDataViewsWarning: true, - }); - - // check if rule still has data view and index patterns field does not exist - goToRuleDetails(); - getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); - assertDetailsNotExist(INDEX_PATTERNS_DETAILS); - }); - - it('Add index patterns to custom rules with configured data view when data view checkbox is checked: rules are updated', () => { - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); - - openBulkEditAddIndexPatternsForm(); - typeIndexPatterns(expectedIndexPatterns); - - // click on data view overwrite checkbox, ensure warning is displayed - cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('not.exist'); - checkOverwriteDataViewCheckbox(); - cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('be.visible'); - - submitBulkEditForm(); - - waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited }); - - // check if rule has been updated with index patterns and data view does not exist - goToRuleDetails(); - hasIndexPatterns(expectedIndexPatterns.join('')); - assertDetailsNotExist(DATA_VIEW_DETAILS); - }); - - it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is NOT checked:: rules are skipped', () => { - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); - - openBulkEditAddIndexPatternsForm(); - typeIndexPatterns(expectedIndexPatterns); - checkOverwriteIndexPatternsCheckbox(); - submitBulkEditForm(); - - waitForBulkEditActionToFinish({ - skippedCount: expectedNumberOfCustomRulesToBeEdited, - showDataViewsWarning: true, - }); - - // check if rule still has data view and index patterns field does not exist - goToRuleDetails(); - getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); - assertDetailsNotExist(INDEX_PATTERNS_DETAILS); - }); - - it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is checked: rules are updated', () => { - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); - - openBulkEditAddIndexPatternsForm(); - typeIndexPatterns(expectedIndexPatterns); - checkOverwriteIndexPatternsCheckbox(); - checkOverwriteDataViewCheckbox(); - - submitBulkEditForm(); - - waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited }); - - // check if rule has been overwritten with index patterns and data view does not exist - goToRuleDetails(); - hasIndexPatterns(expectedIndexPatterns.join('')); - assertDetailsNotExist(DATA_VIEW_DETAILS); - }); - - it('Delete index patterns in custom rules with configured data view: rules are skipped', () => { - selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); - - openBulkEditDeleteIndexPatternsForm(); - typeIndexPatterns(expectedIndexPatterns); - - // in delete form data view checkbox is absent - cy.get(RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX).should('not.exist'); - - submitBulkEditForm(); - - waitForBulkEditActionToFinish({ - skippedCount: expectedNumberOfCustomRulesToBeEdited, - showDataViewsWarning: true, - }); - - // check if rule still has data view and index patterns field does not exist - goToRuleDetails(); - getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); - }); -}); - -describe('Bulk editing index patterns of rules with index patterns and rules with a data view', () => { - const customRulesNumber = 2; - - before(() => { - cleanKibana(); - }); - - beforeEach(() => { - login(); - deleteAlertsAndRules(); - cy.task('esArchiverResetKibana'); - - postDataView(DATA_VIEW_ID); - - createRule( - getNewRule({ name: 'with dataview', index: [], data_view_id: DATA_VIEW_ID, rule_id: '1' }) - ); - createRule(getNewRule({ name: 'no data view', index: ['test-index-1-*'], rule_id: '2' })); - - visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); - - waitForRulesTableToBeLoaded(); - }); - - it('Add index patterns to custom rules: one rule is updated, one rule is skipped', () => { - selectNumberOfRules(customRulesNumber); - - openBulkEditAddIndexPatternsForm(); - typeIndexPatterns(expectedIndexPatterns); - submitBulkEditForm(); - - waitForBulkEditActionToFinish({ - updatedCount: 1, - skippedCount: 1, - showDataViewsWarning: true, - }); - - // check if rule still has data view and index patterns field does not exist - goToTheRuleDetailsOf('with dataview'); - getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); - assertDetailsNotExist(INDEX_PATTERNS_DETAILS); - }); - - it('Add index patterns to custom rules when overwrite data view checkbox is checked: all rules are updated', () => { - selectNumberOfRules(customRulesNumber); - - openBulkEditAddIndexPatternsForm(); - typeIndexPatterns(expectedIndexPatterns); - checkOverwriteDataViewCheckbox(); - submitBulkEditForm(); - - waitForBulkEditActionToFinish({ - updatedCount: 2, - }); - - // check if rule still has data view and index patterns field does not exist - goToRuleDetails(); - assertDetailsNotExist(DATA_VIEW_DETAILS); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts deleted file mode 100644 index 7fcf303b96118..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts +++ /dev/null @@ -1,121 +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 { deleteAlertsAndRules } from '../../../tasks/common'; -import { - expandFirstAlert, - goToClosedAlertsOnRuleDetailsPage, - openAddEndpointExceptionFromAlertActionButton, - openAddEndpointExceptionFromFirstAlert, - waitForAlerts, -} from '../../../tasks/alerts'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { getEndpointRule } from '../../../objects/rule'; -import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -import { createRule } from '../../../tasks/api_calls/rules'; -import { - waitForAlertsToPopulate, - waitForTheRuleToBeExecuted, -} from '../../../tasks/create_new_rule'; -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; -import { - addExceptionEntryFieldValueAndSelectSuggestion, - addExceptionEntryFieldValueValue, - addExceptionFlyoutItemName, - editExceptionFlyoutItemName, - selectCloseSingleAlerts, - submitNewExceptionItem, - validateExceptionConditionField, -} from '../../../tasks/exceptions'; -import { ALERTS_COUNT } from '../../../screens/alerts'; -import { - ADD_AND_BTN, - EXCEPTION_CARD_ITEM_CONDITIONS, - EXCEPTION_CARD_ITEM_NAME, - EXCEPTION_ITEM_VIEWER_CONTAINER, -} from '../../../screens/exceptions'; -import { goToEndpointExceptionsTab } from '../../../tasks/rule_details'; - -describe('Endpoint Exceptions workflows from Alert', () => { - const ITEM_NAME = 'Sample Exception List Item'; - const ITEM_NAME_EDIT = 'Sample Exception List Item'; - const ADDITIONAL_ENTRY = 'host.hostname'; - - beforeEach(() => { - cy.task('esArchiverUnload', 'endpoint'); - cy.task('esArchiverResetKibana'); - login(); - deleteAlertsAndRules(); - cy.task('esArchiverLoad', 'endpoint'); - createRule(getEndpointRule()); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(); - }); - - after(() => { - cy.task('esArchiverUnload', 'endpoint'); - }); - - it('Should be able to create and close single Endpoint exception from overflow menu', () => { - // The Endpoint will populated with predefined fields - openAddEndpointExceptionFromFirstAlert(); - - // As the endpoint.alerts-* is used to trigger the alert the - // file.Ext.code_signature will be auto-populated - validateExceptionConditionField('file.Ext.code_signature'); - - selectCloseSingleAlerts(); - addExceptionFlyoutItemName(ITEM_NAME); - submitNewExceptionItem(); - - // Instead of immediately checking if the Opened Alert has moved to the closed tab, - // use the waitForAlerts method to create a buffer, allowing the alerts some time to - // be moved to the Closed Alert tab. - waitForAlerts(); - - // Closed alert should appear in table - goToClosedAlertsOnRuleDetailsPage(); - cy.get(ALERTS_COUNT).should('exist'); - }); - - it('Should be able to create Endpoint exception from Alerts take action button, and change multiple exception items without resetting to initial auto-prefilled entries', () => { - // Open first Alert Summary - expandFirstAlert(); - - // The Endpoint should populated with predefined fields - openAddEndpointExceptionFromAlertActionButton(); - - // As the endpoint.alerts-* is used to trigger the alert the - // file.Ext.code_signature will be auto-populated - validateExceptionConditionField('file.Ext.code_signature'); - addExceptionFlyoutItemName(ITEM_NAME); - - cy.get(ADD_AND_BTN).click(); - // edit conditions - addExceptionEntryFieldValueAndSelectSuggestion(ADDITIONAL_ENTRY, 6); - addExceptionEntryFieldValueValue('foo', 4); - - // Change the name again - editExceptionFlyoutItemName(ITEM_NAME_EDIT); - - // validate the condition is still "agent.name" or got rest after the name is changed - validateExceptionConditionField(ADDITIONAL_ENTRY); - - selectCloseSingleAlerts(); - submitNewExceptionItem(); - - // Endpoint Exception will move to Endpoint List under Exception tab of rule - goToEndpointExceptionsTab(); - - // new exception item displays - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT); - cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', ADDITIONAL_ENTRY); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts deleted file mode 100644 index 6bbdec283d976..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts +++ /dev/null @@ -1,194 +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 { LOADING_INDICATOR } from '../../../../screens/security_header'; -import { getEndpointRule } from '../../../../objects/rule'; -import { createRule } from '../../../../tasks/api_calls/rules'; -import { goToRuleDetails } from '../../../../tasks/alerts_detection_rules'; -import { - addExceptionFromFirstAlert, - expandFirstAlert, - openAddRuleExceptionFromAlertActionButton, -} from '../../../../tasks/alerts'; -import { - addExceptionEntryFieldValue, - addExceptionEntryFieldValueValue, - addExceptionFlyoutItemName, - submitNewExceptionItem, - validateExceptionConditionField, - validateExceptionCommentCountAndText, - editExceptionFlyoutItemName, - validateHighlightedFieldsPopulatedAsExceptionConditions, - validateEmptyExceptionConditionField, -} from '../../../../tasks/exceptions'; -import { login, visitWithoutDateRange } from '../../../../tasks/login'; -import { goToExceptionsTab } from '../../../../tasks/rule_details'; - -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation'; -import { deleteAlertsAndRules } from '../../../../tasks/common'; -import { - ADD_AND_BTN, - ENTRY_DELETE_BTN, - EXCEPTION_CARD_ITEM_CONDITIONS, - EXCEPTION_CARD_ITEM_NAME, - EXCEPTION_ITEM_VIEWER_CONTAINER, -} from '../../../../screens/exceptions'; -import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; - -describe('Auto populate exception with Alert data', () => { - const ITEM_NAME = 'Sample Exception Item'; - const ITEM_NAME_EDIT = 'Sample Exception Item Edit'; - const ADDITIONAL_ENTRY = 'host.hostname'; - - beforeEach(() => { - cy.task('esArchiverUnload', 'endpoint'); - cy.task('esArchiverResetKibana'); - cy.task('esArchiverLoad', 'endpoint'); - login(); - createRule(getEndpointRule()); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - waitForAlertsToPopulate(); - }); - after(() => { - cy.task('esArchiverUnload', 'endpoint'); - deleteAlertsAndRules(); - }); - afterEach(() => { - cy.task('esArchiverUnload', 'endpoint'); - }); - - it('Should create a Rule exception item from alert actions overflow menu and auto populate the conditions using alert Highlighted fields', () => { - cy.get(LOADING_INDICATOR).should('not.exist'); - addExceptionFromFirstAlert(); - - const highlightedFieldsBasedOnAlertDoc = [ - 'host.name', - 'agent.id', - 'user.name', - 'process.executable', - 'file.path', - ]; - - /** - * Validate the highlighted fields are auto populated, these - * fields are based on the alert document that should be generated - * when the endpoint rule runs - */ - validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc); - - /** - * Validate that the comments are opened by default with one comment added - * showing a text contains information about the pre-filled conditions - */ - validateExceptionCommentCountAndText( - 1, - 'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):' - ); - - addExceptionFlyoutItemName(ITEM_NAME); - submitNewExceptionItem(); - }); - it('Should create a Rule exception from Alerts take action button and change multiple exception items without resetting to initial auto-prefilled entries', () => { - cy.get(LOADING_INDICATOR).should('not.exist'); - - // Open first Alert Summary - expandFirstAlert(); - - // The Rule exception should populated with highlighted fields - openAddRuleExceptionFromAlertActionButton(); - - const highlightedFieldsBasedOnAlertDoc = [ - 'host.name', - 'agent.id', - 'user.name', - 'process.executable', - 'file.path', - ]; - - /** - * Validate the highlighted fields are auto populated, these - * fields are based on the alert document that should be generated - * when the endpoint rule runs - */ - validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc); - - /** - * Validate that the comments are opened by default with one comment added - * showing a text contains information about the pre-filled conditions - */ - validateExceptionCommentCountAndText( - 1, - 'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):' - ); - - addExceptionFlyoutItemName(ITEM_NAME); - - cy.get(ADD_AND_BTN).click(); - - // edit conditions - addExceptionEntryFieldValue(ADDITIONAL_ENTRY, 5); - addExceptionEntryFieldValueValue('foo', 5); - - // Change the name again - editExceptionFlyoutItemName(ITEM_NAME_EDIT); - - // validate the condition is still 'host.hostname' or got rest after the name is changed - validateExceptionConditionField(ADDITIONAL_ENTRY); - - submitNewExceptionItem(); - - goToExceptionsTab(); - - // new exception item displays - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT); - cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', 'host.hostname'); - }); - it('Should delete all prefilled exception entries when creating a Rule exception from Alerts take action button without resetting to initial auto-prefilled entries', () => { - cy.get(LOADING_INDICATOR).should('not.exist'); - - // Open first Alert Summary - expandFirstAlert(); - - // The Rule exception should populated with highlighted fields - openAddRuleExceptionFromAlertActionButton(); - - const highlightedFieldsBasedOnAlertDoc = [ - 'host.name', - 'agent.id', - 'user.name', - 'process.executable', - 'file.path', - ]; - - /** - * Validate the highlighted fields are auto populated, these - * fields are based on the alert document that should be generated - * when the endpoint rule runs - */ - validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc); - - /** - * Delete all the highlighted fields to see if any condition - * will prefuilled again. - */ - const highlightedFieldsCount = highlightedFieldsBasedOnAlertDoc.length - 1; - highlightedFieldsBasedOnAlertDoc.forEach((_, index) => - cy - .get(ENTRY_DELETE_BTN) - .eq(highlightedFieldsCount - index) - .click() - ); - - /** - * Validate that there are no highlighted fields are auto populated - * after the deletion - */ - validateEmptyExceptionConditionField(); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts deleted file mode 100644 index 963ef64dfc150..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts +++ /dev/null @@ -1,178 +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 { getNewRule } from '../../../objects/rule'; -import { ALERTS_COUNT, EMPTY_ALERT_TABLE } from '../../../screens/alerts'; -import { createRule } from '../../../tasks/api_calls/rules'; -import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -import { - goToClosedAlertsOnRuleDetailsPage, - goToOpenedAlertsOnRuleDetailsPage, -} from '../../../tasks/alerts'; -import { - editException, - editExceptionFlyoutItemName, - submitEditedExceptionItem, -} from '../../../tasks/exceptions'; -import { login, visitWithoutDateRange } from '../../../tasks/login'; -import { - addFirstExceptionFromRuleDetails, - goToAlertsTab, - goToExceptionsTab, - openEditException, - removeException, - waitForTheRuleToBeExecuted, -} from '../../../tasks/rule_details'; - -import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; -import { postDataView, deleteAlertsAndRules } from '../../../tasks/common'; -import { - NO_EXCEPTIONS_EXIST_PROMPT, - EXCEPTION_ITEM_VIEWER_CONTAINER, - EXCEPTION_CARD_ITEM_NAME, - EXCEPTION_CARD_ITEM_CONDITIONS, - EXCEPTION_ITEM_CONTAINER, - VALUES_INPUT, - FIELD_INPUT_PARENT, -} from '../../../screens/exceptions'; -import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; - -describe('Add exception using data views from rule details', () => { - const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; - const ITEM_NAME = 'Sample Exception List Item'; - - before(() => { - cy.task('esArchiverResetKibana'); - cy.task('esArchiverLoad', 'exceptions'); - login(); - postDataView('exceptions-*'); - }); - - after(() => { - cy.task('esArchiverUnload', 'exceptions'); - }); - - beforeEach(() => { - deleteAlertsAndRules(); - createRule( - getNewRule({ - query: 'agent.name:*', - data_view_id: 'exceptions-*', - interval: '10s', - rule_id: 'rule_testing', - }) - ); - login(); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - waitForAlertsToPopulate(); - }); - - afterEach(() => { - cy.task('esArchiverUnload', 'exceptions_2'); - }); - - it('Creates an exception item and close all matching alerts', () => { - goToExceptionsTab(); - // when no exceptions exist, empty component shows with action to add exception - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); - - // clicks prompt button to add first exception that will also select to close - // all matching alerts - addFirstExceptionFromRuleDetails( - { - field: 'agent.name', - operator: 'is', - values: ['foo'], - }, - ITEM_NAME - ); - - // new exception item displays - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - // Alerts table should now be empty from having added exception and closed - // matching alert - goToAlertsTab(); - cy.get(EMPTY_ALERT_TABLE).should('exist'); - - // Closed alert should appear in table - goToClosedAlertsOnRuleDetailsPage(); - cy.get(ALERTS_COUNT).should('exist'); - cy.get(ALERTS_COUNT).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`); - - // Remove the exception and load an event that would have matched that exception - // to show that said exception now starts to show up again - goToExceptionsTab(); - - // when removing exception and again, no more exist, empty screen shows again - removeException(); - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); - - // load more docs - cy.task('esArchiverLoad', 'exceptions_2'); - - // now that there are no more exceptions, the docs should match and populate alerts - goToAlertsTab(); - goToOpenedAlertsOnRuleDetailsPage(); - waitForTheRuleToBeExecuted(); - waitForAlertsToPopulate(); - - cy.get(ALERTS_COUNT).should('exist'); - cy.get(ALERTS_COUNT).should('have.text', '2 alerts'); - }); - - it('Edits an exception item', () => { - const NEW_ITEM_NAME = 'Exception item-EDITED'; - const ITEM_FIELD = 'unique_value.test'; - const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; - - goToExceptionsTab(); - // add item to edit - addFirstExceptionFromRuleDetails( - { - field: ITEM_FIELD, - operator: 'is', - values: ['foo'], - }, - ITEM_NAME - ); - - // displays existing exception items - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); - cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME); - cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' unique_value.testIS foo'); - - // open edit exception modal - openEditException(); - - // edit exception item name - editExceptionFlyoutItemName(NEW_ITEM_NAME); - - // check that the existing item's field is being populated - cy.get(EXCEPTION_ITEM_CONTAINER) - .eq(0) - .find(FIELD_INPUT_PARENT) - .eq(0) - .should('have.text', ITEM_FIELD); - cy.get(VALUES_INPUT).should('have.text', 'foo'); - - // edit conditions - editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); - - // submit - submitEditedExceptionItem(); - - // new exception item displays - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - - // check that updates stuck - cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME); - cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.nameIS foo'); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts deleted file mode 100644 index 6a0300f270b79..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts +++ /dev/null @@ -1,140 +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 { getExceptionList, expectedExportedExceptionList } from '../../../../objects/exception'; -import { getNewRule } from '../../../../objects/rule'; - -import { createRule } from '../../../../tasks/api_calls/rules'; -import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../../../tasks/login'; - -import { EXCEPTIONS_URL } from '../../../../urls/navigation'; -import { - deleteExceptionListWithoutRuleReferenceByListId, - deleteExceptionListWithRuleReferenceByListId, - exportExceptionList, - waitForExceptionsTableToBeLoaded, - createSharedExceptionList, - linkRulesToExceptionList, - assertNumberLinkedRules, -} from '../../../../tasks/exceptions_table'; -import { - EXCEPTIONS_LIST_MANAGEMENT_NAME, - EXCEPTIONS_TABLE_SHOWING_LISTS, -} from '../../../../screens/exceptions'; -import { createExceptionList } from '../../../../tasks/api_calls/exceptions'; - -import { TOASTER } from '../../../../screens/alerts_detection_rules'; - -const EXCEPTION_LIST_NAME = 'My test list'; -const EXCEPTION_LIST_TO_DUPLICATE_NAME = 'A test list 2'; - -const getExceptionList1 = () => ({ - ...getExceptionList(), - name: EXCEPTION_LIST_NAME, - list_id: 'exception_list_1', -}); - -const getExceptionList2 = () => ({ - ...getExceptionList(), - name: EXCEPTION_LIST_TO_DUPLICATE_NAME, - list_id: 'exception_list_2', -}); - -describe('Manage lists from "Shared Exception Lists" page', () => { - describe('Create/Export/Delete List', () => { - before(() => { - createRule(getNewRule({ name: 'Another rule' })); - - // Create exception list associated with a rule - createExceptionList(getExceptionList2(), getExceptionList2().list_id).then((response) => - createRule( - getNewRule({ - exceptions_list: [ - { - id: response.body.id, - list_id: getExceptionList2().list_id, - type: getExceptionList2().type, - namespace_type: getExceptionList2().namespace_type, - }, - ], - }) - ) - ); - - // Create exception list not used by any rules - createExceptionList(getExceptionList1(), getExceptionList1().list_id).as( - 'exceptionListResponse' - ); - }); - - beforeEach(() => { - login(); - visitWithoutDateRange(EXCEPTIONS_URL); - waitForExceptionsTableToBeLoaded(); - }); - - it('Export exception list', function () { - cy.intercept(/(\/api\/exception_lists\/_export)/).as('export'); - - exportExceptionList(getExceptionList1().list_id); - - cy.wait('@export').then(({ response }) => { - cy.wrap(response?.body).should( - 'eql', - expectedExportedExceptionList(this.exceptionListResponse) - ); - - cy.get(TOASTER).should( - 'have.text', - `Exception list "${EXCEPTION_LIST_NAME}" exported successfully` - ); - }); - }); - - it('Link rules to shared exception list', function () { - assertNumberLinkedRules(getExceptionList2().list_id, '1'); - linkRulesToExceptionList(getExceptionList2().list_id, 1); - assertNumberLinkedRules(getExceptionList2().list_id, '2'); - }); - - it('Create exception list', function () { - createSharedExceptionList( - { name: 'Newly created list', description: 'This is my list.' }, - true - ); - - // After creation - directed to list detail page - cy.get(EXCEPTIONS_LIST_MANAGEMENT_NAME).should('have.text', 'Newly created list'); - }); - - it('Delete exception list without rule reference', () => { - // Using cy.contains because we do not care about the exact text, - // just checking number of lists shown - cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '4'); - - deleteExceptionListWithoutRuleReferenceByListId(getExceptionList1().list_id); - - // Using cy.contains because we do not care about the exact text, - // just checking number of lists shown - cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); - }); - - it('Deletes exception list with rule reference', () => { - waitForPageWithoutDateRange(EXCEPTIONS_URL); - waitForExceptionsTableToBeLoaded(); - - // Using cy.contains because we do not care about the exact text, - // just checking number of lists shown - cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); - - deleteExceptionListWithRuleReferenceByListId(getExceptionList2().list_id); - - // Using cy.contains because we do not care about the exact text, - // just checking number of lists shown - cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2'); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts deleted file mode 100644 index 0b02939f5ca4f..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts +++ /dev/null @@ -1,87 +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 { createRule } from '../../../../tasks/api_calls/rules'; -import { getNewRule } from '../../../../objects/rule'; -import { - CORRELATIONS_ANCESTRY_SECTION, - CORRELATIONS_ANCESTRY_TABLE, - CORRELATIONS_CASES_SECTION, - CORRELATIONS_SESSION_SECTION, - CORRELATIONS_SOURCE_SECTION, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON, -} from '../../../../screens/expandable_flyout/alert_details_left_panel_correlations_tab'; -import { - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP, -} from '../../../../screens/expandable_flyout/alert_details_left_panel'; -import { - expandCorrelationsSection, - openCorrelationsTab, -} from '../../../../tasks/expandable_flyout/alert_details_left_panel_correlations_tab'; -import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; -import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; -import { - createNewCaseFromExpandableFlyout, - expandFirstAlertExpandableFlyout, -} from '../../../../tasks/expandable_flyout/common'; -import { cleanKibana } from '../../../../tasks/common'; -import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; -import { login, visit } from '../../../../tasks/login'; -import { ALERTS_URL } from '../../../../urls/navigation'; - -describe('Expandable flyout left panel correlations', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - expandDocumentDetailsExpandableFlyoutLeftSection(); - createNewCaseFromExpandableFlyout(); - openInsightsTab(); - openCorrelationsTab(); - }); - - it('should render correlations details correctly', () => { - cy.log('link the alert to a new case'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).scrollIntoView(); - - cy.log('should render the Insights header'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).should('be.visible').and('have.text', 'Insights'); - - cy.log('should render the inner tab switch'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); - - cy.log('should render correlations tab activator / button'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON) - .should('be.visible') - .and('have.text', 'Correlations'); - - cy.log('should render all the correlations sections'); - - cy.get(CORRELATIONS_ANCESTRY_SECTION) - .should('be.visible') - .and('have.text', '1 alert related by ancestry'); - - cy.get(CORRELATIONS_SOURCE_SECTION) - .should('be.visible') - .and('have.text', '0 alerts related by source event'); - - cy.get(CORRELATIONS_SESSION_SECTION) - .should('be.visible') - .and('have.text', '1 alert related by session'); - - cy.get(CORRELATIONS_CASES_SECTION).should('be.visible').and('have.text', '1 related case'); - - expandCorrelationsSection(CORRELATIONS_ANCESTRY_SECTION); - - cy.get(CORRELATIONS_ANCESTRY_TABLE).should('be.visible'); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts deleted file mode 100644 index a166a72148fd3..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts +++ /dev/null @@ -1,231 +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 { upperFirst } from 'lodash'; -import { - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_CREATE_BUTTON, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_DESCRIPTION_INPUT, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_NAME_INPUT, - EXISTING_CASE_SELECT_BUTTON, - VIEW_CASE_TOASTER_LINK, -} from '../../../../screens/expandable_flyout/common'; -import { - createNewCaseFromCases, - expandFirstAlertExpandableFlyout, - navigateToAlertsPage, - navigateToCasesPage, -} from '../../../../tasks/expandable_flyout/common'; -import { ALERT_CHECKBOX } from '../../../../screens/alerts'; -import { CASE_DETAILS_PAGE_TITLE } from '../../../../screens/case_details'; -import { - DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON, - DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON, - DOCUMENT_DETAILS_FLYOUT_FOOTER, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE, - DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE, - DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE, - DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY, - DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION, - DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED, - DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND, - DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON, - DOCUMENT_DETAILS_FLYOUT_HEADER_CHAT_BUTTON, - DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE, - DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE, - DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY, - DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE, - DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS, - DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE, - DOCUMENT_DETAILS_FLYOUT_JSON_TAB, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB, - DOCUMENT_DETAILS_FLYOUT_TABLE_TAB, -} from '../../../../screens/expandable_flyout/alert_details_right_panel'; -import { - collapseDocumentDetailsExpandableFlyoutLeftSection, - expandDocumentDetailsExpandableFlyoutLeftSection, - openJsonTab, - openTableTab, - openTakeActionButton, - openTakeActionButtonAndSelectItem, - selectTakeActionItem, -} from '../../../../tasks/expandable_flyout/alert_details_right_panel'; -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'; - -describe('Alert details expandable flyout right panel', () => { - const rule = getNewRule(); - - beforeEach(() => { - cleanKibana(); - login(); - createRule(rule); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - }); - - it('should display header and footer basics', () => { - expandFirstAlertExpandableFlyout(); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('be.visible').and('have.text', rule.name); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_CHAT_BUTTON).should('be.visible'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS).should('be.visible'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE) - .should('be.visible') - .and('have.text', rule.risk_score); - - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE) - .should('be.visible') - .and('have.text', upperFirst(rule.severity)); - - cy.log('Verify all 3 tabs are visible'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB).should('be.visible').and('have.text', 'Overview'); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB).should('be.visible').and('have.text', 'Table'); - cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB).should('be.visible').and('have.text', 'JSON'); - - cy.log('Verify the expand/collapse button is visible and functionality works'); - - expandDocumentDetailsExpandableFlyoutLeftSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON) - .should('be.visible') - .and('have.text', 'Collapse details'); - - collapseDocumentDetailsExpandableFlyoutLeftSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON) - .should('be.visible') - .and('have.text', 'Expand details'); - - cy.log('Verify the take action button is visible on all tabs'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); - - openTableTab(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); - - openJsonTab(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); - }); - - // TODO this will change when add to existing case is improved - // https://github.com/elastic/security-team/issues/6298 - it('should add to existing case', () => { - navigateToCasesPage(); - createNewCaseFromCases(); - - cy.get(CASE_DETAILS_PAGE_TITLE).should('be.visible').and('have.text', 'case'); - navigateToAlertsPage(); - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE); - - cy.get(EXISTING_CASE_SELECT_BUTTON).should('be.visible').contains('Select').click(); - cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case'); - }); - - // TODO this will change when add to new case is improved - // https://github.com/elastic/security-team/issues/6298 - it('should add to new case', () => { - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE); - - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_NAME_INPUT).type('case'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_DESCRIPTION_INPUT).type( - 'case description' - ); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_CREATE_BUTTON).click(); - - cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case'); - }); - - it('should mark as acknowledged', () => { - cy.get(ALERT_CHECKBOX).should('have.length', 2); - - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED); - - // TODO figure out how to verify the toasts pops up - // cy.get(KIBANA_TOAST) - // .should('be.visible') - // .and('have.text', 'Successfully marked 1 alert as acknowledged.'); - cy.get(ALERT_CHECKBOX).should('have.length', 1); - }); - - it('should mark as closed', () => { - cy.get(ALERT_CHECKBOX).should('have.length', 2); - - expandFirstAlertExpandableFlyout(); - openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED); - - // TODO figure out how to verify the toasts pops up - // cy.get(KIBANA_TOAST).should('be.visible').and('have.text', 'Successfully closed 1 alert.'); - cy.get(ALERT_CHECKBOX).should('have.length', 1); - }); - - // these actions are now grouped together as we're not really testing their functionality but just the existence of the option in the dropdown - it('should test other action within take action dropdown', () => { - expandFirstAlertExpandableFlyout(); - - cy.log('should add endpoint exception'); - - // TODO figure out why this option is disabled in Cypress but not running the app locally - // https://github.com/elastic/security-team/issues/6300 - openTakeActionButton(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION).should('be.disabled'); - - cy.log('should add rule exception'); - - // TODO this isn't fully testing the add rule exception yet - // https://github.com/elastic/security-team/issues/6301 - selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON) - .should('be.visible') - .click(); - - // cy.log('should isolate host'); - - // TODO figure out why isolate host isn't showing up in the dropdown - // https://github.com/elastic/security-team/issues/6302 - // openTakeActionButton(); - // cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST).should('be.visible'); - - cy.log('should respond'); - - // TODO this will change when respond is improved - // https://github.com/elastic/security-team/issues/6303 - openTakeActionButton(); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND).should('be.disabled'); - - cy.log('should investigate in timeline'); - - selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE); - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION) - .first() - .within(() => - cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY).should('be.visible') - ); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts deleted file mode 100644 index ef8884f560dce..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts +++ /dev/null @@ -1,351 +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 { collapseDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; -import { DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT } from '../../../../screens/expandable_flyout/alert_details_left_panel_investigation_tab'; -import { - createNewCaseFromExpandableFlyout, - expandFirstAlertExpandableFlyout, -} from '../../../../tasks/expandable_flyout/common'; -import { - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_HEADER, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_RULE_PREVIEW_BUTTON, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_HEADER, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_SECTION_EMPTY_RESPONSE, -} from '../../../../screens/expandable_flyout/alert_details_right_panel_overview_tab'; -import { - navigateToCorrelationsDetails, - clickInvestigationGuideButton, - navigateToPrevalenceDetails, - toggleOverviewTabAboutSection, - toggleOverviewTabInsightsSection, - toggleOverviewTabInvestigationSection, - toggleOverviewTabResponseSection, - toggleOverviewTabVisualizationsSection, -} 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 { - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS, - DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS, -} from '../../../../screens/expandable_flyout/alert_details_left_panel_entities_tab'; - -describe('Alert details expandable flyout right panel overview tab', () => { - const rule = getNewRule(); - - beforeEach(() => { - cleanKibana(); - login(); - createRule(rule); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - }); - - describe('about section', () => { - it('should display about section', () => { - cy.log('header and content'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_HEADER) - .should('be.visible') - .and('have.text', 'About'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_CONTENT).should('be.visible'); - - cy.log('description'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE) - .should('be.visible') - .and('contain.text', 'Rule description'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE) - .should('be.visible') - .within(() => { - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_RULE_PREVIEW_BUTTON) - .should('be.visible') - .and('have.text', 'Rule summary'); - }); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS) - .should('be.visible') - .and('have.text', rule.description); - - cy.log('reason'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE) - .should('be.visible') - .and('have.text', 'Alert reason'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS) - .should('be.visible') - .and('contain.text', rule.name); - - cy.log('mitre attack'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE) - .should('be.visible') - // @ts-ignore - .and('contain.text', rule.threat[0].framework); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS) - .should('be.visible') - // @ts-ignore - .and('contain.text', rule.threat[0].technique[0].name) - // @ts-ignore - .and('contain.text', rule.threat[0].tactic.name); - }); - }); - - describe('visualizations section', () => { - it('should display analyzer and session previews', () => { - toggleOverviewTabAboutSection(); - toggleOverviewTabVisualizationsSection(); - - cy.log('analyzer graph preview'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT).should('be.visible'); - - cy.log('session view preview'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT).should('be.visible'); - }); - }); - - describe('investigation section', () => { - it('should display investigation section', () => { - toggleOverviewTabAboutSection(); - - cy.log('header and content'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_HEADER) - .should('be.visible') - .and('have.text', 'Investigation'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_CONTENT).should( - 'be.visible' - ); - - cy.log('investigation guide button'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON) - .should('be.visible') - .and('have.text', 'Investigation guide'); - - cy.log('should navigate to left Investigation tab'); - - clickInvestigationGuideButton(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).should('be.visible'); - - cy.log('highlighted fields'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE) - .should('be.visible') - .and('have.text', 'Highlighted fields'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS).should('be.visible'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL) - .should('be.visible') - .and('contain.text', 'host.name'); - const hostNameCell = - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('siem-kibana'); - cy.get(hostNameCell).should('be.visible').and('have.text', 'siem-kibana'); - - cy.get(hostNameCell).click(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('be.visible'); - - collapseDocumentDetailsExpandableFlyoutLeftSection(); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL) - .should('be.visible') - .and('contain.text', 'user.name'); - const userNameCell = - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('test'); - cy.get(userNameCell).should('be.visible').and('have.text', 'test'); - - cy.get(userNameCell).click(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('be.visible'); - }); - }); - - describe('insights section', () => { - it('should display entities section', () => { - toggleOverviewTabAboutSection(); - toggleOverviewTabInvestigationSection(); - toggleOverviewTabInsightsSection(); - - cy.log('header and content'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER) - .should('be.visible') - .and('have.text', 'Entities'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_CONTENT).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER).should('be.visible'); - - cy.log('should navigate to left panel Entities tab'); - - // TODO: skipping this section as Cypress can't seem to find the element (though it's in the DOM) - // navigateToEntitiesDetails(); - // cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); - }); - - it('should display threat intelligence section', () => { - toggleOverviewTabAboutSection(); - toggleOverviewTabInvestigationSection(); - toggleOverviewTabInsightsSection(); - - cy.log('header and content'); - - cy.get( - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER - ).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER) - .should('be.visible') - .and('have.text', 'Threat Intelligence'); - cy.get( - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT - ).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT) - .should('be.visible') - .within(() => { - // threat match detected - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) - .eq(0) - .should('be.visible') - .and('have.text', '0 threat match detected'); // TODO work on getting proper IoC data to get proper data here - - // field with threat enrichement - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) - .eq(1) - .should('be.visible') - .and('have.text', '0 field enriched with threat intelligence'); // TODO work on getting proper IoC data to get proper data here - }); - - cy.log('should navigate to left panel Threat Intelligence tab'); - - // TODO: skipping this section as Cypress can't seem to find the element (though it's in the DOM) - // navigateToThreatIntelligenceDetails(); - // cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Threat Intelligence sub tab directly - }); - - // TODO: skipping this due to flakiness - it.skip('should display correlations section', () => { - cy.log('link the alert to a new case'); - - createNewCaseFromExpandableFlyout(); - - toggleOverviewTabAboutSection(); - toggleOverviewTabInvestigationSection(); - toggleOverviewTabInsightsSection(); - - cy.log('header and content'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER) - .should('be.visible') - .and('have.text', 'Correlations'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT) - .should('be.visible') - .within(() => { - // TODO the order in which these appear is not deterministic currently, hence this can cause flakiness - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) - .eq(0) - .should('be.visible') - .and('have.text', '1 alert related by ancestry'); - // cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) - // .eq(2) - // .should('be.visible') - // .and('have.text', '1 alert related by the same source event'); // TODO work on getting proper data to display some same source data here - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) - .eq(2) - .should('be.visible') - .and('have.text', '1 alert related by session'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) - .eq(1) - .should('be.visible') - .and('have.text', '1 related case'); - }); - - cy.log('should navigate to left panel Correlations tab'); - - navigateToCorrelationsDetails(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Correlations sub tab directly - }); - - // TODO work on getting proper data to make the prevalence section work here - // we need to generate enough data to have at least one field with prevalence - it.skip('should display prevalence section', () => { - toggleOverviewTabAboutSection(); - toggleOverviewTabInvestigationSection(); - toggleOverviewTabInsightsSection(); - - cy.log('header and content'); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER) - .should('be.visible') - .and('have.text', 'Prevalence'); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT) - .should('be.visible') - .within(() => { - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES) - .should('be.visible') - .and('have.text', 'is uncommon'); - }); - - cy.log('should navigate to left panel Prevalence tab'); - - navigateToPrevalenceDetails(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Prevalence sub tab directly - }); - }); - - describe('response section', () => { - it('should display empty message', () => { - toggleOverviewTabAboutSection(); - toggleOverviewTabInvestigationSection(); - toggleOverviewTabResponseSection(); - - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_SECTION_EMPTY_RESPONSE).should( - 'be.visible' - ); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts deleted file mode 100644 index bc3025914a68a..0000000000000 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts +++ /dev/null @@ -1,167 +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 { Timeline } from '../../../objects/timeline'; -import { - MODAL_CONFIRMATION_BTN, - MODAL_CONFIRMATION_CANCEL_BTN, -} from '../../../screens/alerts_detection_rules'; -import { - ALERTS_PAGE, - APP_LEAVE_CONFIRM_MODAL, - CASES_PAGE, - MANAGE_PAGE, - OBSERVABILITY_ALERTS_PAGE, -} from '../../../screens/kibana_navigation'; -import { TIMELINE_SAVE_MODAL } from '../../../screens/timeline'; -import { cleanKibana } from '../../../tasks/common'; -import { - navigateFromKibanaCollapsibleTo, - openKibanaNavigation, -} from '../../../tasks/kibana_navigation'; -import { login, visit } from '../../../tasks/login'; -import { closeTimelineUsingToggle } from '../../../tasks/security_main'; -import { - addNameAndDescriptionToTimeline, - createNewTimeline, - populateTimeline, - waitForTimelineChanges, -} from '../../../tasks/timeline'; -import { HOSTS_URL, MANAGE_URL } from '../../../urls/navigation'; - -describe('Save Timeline Prompts', () => { - before(() => { - cleanKibana(); - login(); - /* - * When timeline changes are pending, chrome would popup with - * a confirm dialog stating that `you can lose unsaved changed. - * Below changes will disable that. - * - * */ - cy.window().then((win) => { - win.onbeforeunload = null; - }); - }); - - beforeEach(() => { - login(); - visit(HOSTS_URL); - createNewTimeline(); - }); - - it('unchanged & unsaved timeline should NOT prompt when user navigates away', () => { - openKibanaNavigation(); - navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); - cy.url().should('not.contain', HOSTS_URL); - }); - - it('Changed & unsaved timeline should prompt when user navigates away from security solution', () => { - populateTimeline(); - waitForTimelineChanges(); - closeTimelineUsingToggle(); - openKibanaNavigation(); - navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); - cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); - cy.get(MODAL_CONFIRMATION_BTN).click(); - }); - - it('Changed & unsaved timeline should NOT prompt when user navigates away within security solution where timelines are enabled', () => { - populateTimeline(); - - waitForTimelineChanges(); - closeTimelineUsingToggle(); - // navigate to any other page in security solution - openKibanaNavigation(); - cy.get(CASES_PAGE).click(); - cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); - }); - - it('Changed & unsaved timeline should prompt when user navigates away within security solution where timelines are disbaled eg. admin screen', () => { - populateTimeline(); - waitForTimelineChanges(); - openKibanaNavigation(); - cy.get(MANAGE_PAGE).click(); - cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); - cy.get(MODAL_CONFIRMATION_BTN).click(); - }); - - it('Changed & saved timeline should NOT prompt when user navigates away out of security solution', () => { - populateTimeline(); - waitForTimelineChanges(); - closeTimelineUsingToggle(); - openKibanaNavigation(); - navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); - cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); - cy.get(MODAL_CONFIRMATION_CANCEL_BTN).click(); - addNameAndDescriptionToTimeline( - { - title: 'Some Timeline', - description: 'Some Timeline', - } as Timeline, - true - ); - openKibanaNavigation(); - navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); - cy.url().should('not.contain', HOSTS_URL); - }); - - it('Changed & saved timeline should NOT prompt when user navigates within security solution where timelines are disabled', () => { - populateTimeline(); - waitForTimelineChanges(); - closeTimelineUsingToggle(); - openKibanaNavigation(); - cy.get(MANAGE_PAGE).click(); - cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); - cy.get(MODAL_CONFIRMATION_CANCEL_BTN).click(); - addNameAndDescriptionToTimeline( - { - title: 'Some Timeline', - description: 'Some Timeline', - } as Timeline, - true - ); - openKibanaNavigation(); - cy.get(MANAGE_PAGE).click(); - cy.url().should('not.contain', HOSTS_URL); - }); - - it('When user navigates to the page where timeline is present, Time save modal should not exists.', () => { - populateTimeline(); - waitForTimelineChanges(); - closeTimelineUsingToggle(); - openKibanaNavigation(); - cy.get(MANAGE_PAGE).click(); - cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); - cy.get(MODAL_CONFIRMATION_BTN).click(); - - // Navigate back to HOSTS_URL and ensure that - // timeline save modal is NOT present - - openKibanaNavigation(); - cy.get(ALERTS_PAGE).click(); - cy.get(TIMELINE_SAVE_MODAL).should('not.exist'); - }); - - it('Changed and unsaved timeline should NOT prompt when user navigates from the page where timeline is disabled', () => { - populateTimeline(); - waitForTimelineChanges(); - closeTimelineUsingToggle(); - openKibanaNavigation(); - cy.get(MANAGE_PAGE).click(); - cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); - cy.get(MODAL_CONFIRMATION_BTN).click(); - // now we have come from MANAGE_PAGE where timeline is disabled - // to outside app where timeline is not present. - // There should be NO confirmation model in that case. - openKibanaNavigation(); - navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); - // should not be manage page i.e. successfull navigation - cy.get(TIMELINE_SAVE_MODAL).should('not.exist'); - cy.url().should('not.contain', MANAGE_URL); - }); -}); diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json index 7f7b3e6f746e2..16e511dd1e507 100644 --- a/x-pack/plugins/security_solution/package.json +++ b/x-pack/plugins/security_solution/package.json @@ -10,17 +10,11 @@ "cypress": "../../../node_modules/.bin/cypress", "cypress:burn": "yarn cypress:run:reporter --env burn=2 --concurrency=1 --headed", "cypress:changed-specs-only": "yarn cypress:run:reporter --changed-specs-only --env burn=2", - "cypress:open": "TZ=UTC node ./scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config", - "cypress:run": "yarn cypress:run:reporter --spec './cypress/e2e/{,!(investigations,explore)/**/}*.cy.ts'; status=$?; yarn junit:merge && exit $status", - "cypress:run:cases": "yarn cypress:run:reporter --spec './cypress/e2e/explore/cases/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", - "cypress:run:reporter": "TZ=UTC node ./scripts/start_cypress_parallel run --browser chrome --config-file ./cypress/cypress_ci.config.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json", - "cypress:run:respops": "yarn cypress:run:reporter --spec './cypress/e2e/(detection_alerts|detection_rules|exceptions)/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", - "cypress:dw:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress.config.ts ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/cli_config", - "cypress:dw:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json; status=$?; yarn junit:merge && exit $status", - "cypress:dw:endpoint:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress_endpoint.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/endpoint_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json --concurrency 1; status=$?; yarn junit:merge && exit $status", - "cypress:dw:endpoint:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress_endpoint.config.ts ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/endpoint_config", - "cypress:investigations:run": "yarn cypress:run:reporter --spec './cypress/e2e/investigations/**/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", - "cypress:explore:run": "yarn cypress:run:reporter --spec './cypress/e2e/explore/**/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", + "cypress:run:reporter": "TZ=UTC node ./scripts/start_cypress_parallel run --ftr-config-file ../../test/defend_workflows_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=../../test/security_solution_cypress/cypress/reporter_config.json", + "cypress:dw:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress.config.ts ts --ftr-config-file ../../test/defend_workflows_cypress/cli_config", + "cypress:dw:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress.config.ts --ftr-config-file ../../test/defend_workflows_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=../../test/security_solution_cypress/cypress/reporter_config.json; status=$?; yarn junit:merge && exit $status", + "cypress:dw:endpoint:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress_endpoint.config.ts --ftr-config-file ../../test/defend_workflows_cypress/endpoint_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=../../test/security_solution_cypress/cypress/reporter_config.json --concurrency 1; status=$?; yarn junit:merge && exit $status", + "cypress:dw:endpoint:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress_endpoint.config.ts ts --ftr-config-file ../../test/defend_workflows_cypress/endpoint_config", "junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-security-solution/cypress/results/mochawesome*.json > ../../../target/kibana-security-solution/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-security-solution/cypress/results/output.json --reportDir ../../../target/kibana-security-solution/cypress/results && yarn junit:transform && mkdir -p ../../../target/junit && cp ../../../target/kibana-security-solution/cypress/results/*.xml ../../../target/junit/", "test:generate": "node scripts/endpoint/resolver_generator", "mappings:generate": "node scripts/mappings/mappings_generator", diff --git a/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts b/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts index cf2f3897bd5ab..7ea6be3314be8 100644 --- a/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts +++ b/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts @@ -84,8 +84,10 @@ export const cli = () => { ); const isOpen = argv._[0] === 'open'; - const cypressConfigFilePath = require.resolve(`../../${argv.configFile}`) as string; - const cypressConfigFile = await import(require.resolve(`../../${argv.configFile}`)); + const cypressConfigFilePath = require.resolve( + `../../${_.isArray(argv.configFile) ? _.last(argv.configFile) : argv.configFile}` + ) as string; + const cypressConfigFile = await import(cypressConfigFilePath); const spec: string | undefined = argv?.spec as string; let files = retrieveIntegrations(spec ? [spec] : cypressConfigFile?.e2e?.specPattern); @@ -192,7 +194,9 @@ export const cli = () => { const config = await readConfigFile( log, EsVersion.getDefault(), - _.isArray(argv.ftrConfigFile) ? _.last(argv.ftrConfigFile) : argv.ftrConfigFile, + path.resolve( + _.isArray(argv.ftrConfigFile) ? _.last(argv.ftrConfigFile) : argv.ftrConfigFile + ), { servers: { elasticsearch: { diff --git a/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts b/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts index cd60e071b1e00..32188787b9cf2 100644 --- a/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts +++ b/x-pack/plugins/threat_intelligence/cypress/tasks/login.ts @@ -10,12 +10,12 @@ import Url from 'url'; import * as yaml from 'js-yaml'; +import { encode } from '@kbn/rison'; +import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '@kbn/security-solution-plugin/common/constants'; import { LOADING_INDICATOR, LOADING_INDICATOR_HIDDEN, -} from '@kbn/security-solution-plugin/cypress/screens/security_header'; -import { encode } from '@kbn/rison'; -import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '@kbn/security-solution-plugin/common/constants'; +} from '../../../../test/security_solution_cypress/cypress/screens/security_header'; import type { ROLES } from './privileges'; const LOGIN_API_ENDPOINT = '/internal/security/login'; diff --git a/x-pack/plugins/threat_intelligence/package.json b/x-pack/plugins/threat_intelligence/package.json index 32b2d1b415ceb..a887c13c3ba4b 100644 --- a/x-pack/plugins/threat_intelligence/package.json +++ b/x-pack/plugins/threat_intelligence/package.json @@ -5,12 +5,12 @@ "license": "Elastic License 2.0", "scripts": { "cypress": "../../../node_modules/.bin/cypress", - "cypress:open": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/threat_intelligence_cypress/cli_config_parallel", + "cypress:open": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ../../plugins/threat_intelligence/cypress/cypress.config.ts --ftr-config-file ../../test/threat_intelligence_cypress/cli_config_parallel", "cypress:run": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/**/*.cy.ts'; status=$?; yarn junit:merge && exit $status", "cypress:run:spec": "yarn cypress:run:reporter --browser chrome --spec ${SPEC_LIST:-'./cypress/e2e/**/*.cy.ts'}; status=$?; yarn junit:merge && exit $status", - "cypress:run:cases": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/cases/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", - "cypress:run:reporter": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel run --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/threat_intelligence_cypress/cli_config_parallel --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json", - "cypress:run:respops": "yarn cypress:run:reporter --browser chrome --spec ./cypress/e2e/detection_alerts/*.cy.ts,./cypress/e2e/detection_rules/*.cy.ts,./cypress/e2e/exceptions/*.cy.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", + "cypress:run:cases": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/cases/*.cy.ts' --ftr-config-file ../../test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", + "cypress:run:reporter": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel run --config-file ../../plugins/threat_intelligence/cypress/cypress.config.ts --ftr-config-file ../../test/threat_intelligence_cypress/cli_config_parallel --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json", + "cypress:run:respops": "yarn cypress:run:reporter --browser chrome --spec ./cypress/e2e/detection_alerts/*.cy.ts,./cypress/e2e/detection_rules/*.cy.ts,./cypress/e2e/exceptions/*.cy.ts --ftr-config-file ../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", "junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-threat-intelligence/cypress/results/mochawesome*.json > ../../../target/kibana-threat-intelligence/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-threat-intelligence/cypress/results/output.json --reportDir ../../../target/kibana-threat-intelligence/cypress/results && mkdir -p ../../../target/junit && cp ../../../target/kibana-threat-intelligence/cypress/results/*.xml ../../../target/junit/" } } diff --git a/x-pack/plugins/security_solution/cypress/.eslintrc.json b/x-pack/test/security_solution_cypress/cypress/.eslintrc.json similarity index 100% rename from x-pack/plugins/security_solution/cypress/.eslintrc.json rename to x-pack/test/security_solution_cypress/cypress/.eslintrc.json diff --git a/x-pack/plugins/security_solution/cypress/.gitignore b/x-pack/test/security_solution_cypress/cypress/.gitignore similarity index 100% rename from x-pack/plugins/security_solution/cypress/.gitignore rename to x-pack/test/security_solution_cypress/cypress/.gitignore diff --git a/x-pack/plugins/security_solution/cypress/README.md b/x-pack/test/security_solution_cypress/cypress/README.md similarity index 77% rename from x-pack/plugins/security_solution/cypress/README.md rename to x-pack/test/security_solution_cypress/cypress/README.md index 6b3b641e8e59c..9a8ee567ff9a1 100644 --- a/x-pack/plugins/security_solution/cypress/README.md +++ b/x-pack/test/security_solution_cypress/cypress/README.md @@ -38,21 +38,39 @@ of data for your test, [**Running the tests**](#running-the-tests) to know how t Please, before opening a PR with the new test, please make sure that the test fails. If you never see your test fail you don’t know if your test is actually testing the right thing, or testing anything at all. +Note that we use tags in order to select which tests we want to execute: + +```typescript +export const tag = { + SERVERLESS: '@serverless', + ESS: '@ess', + BROKEN_IN_SERVERLESS: '@brokenInServerless', +}; +``` + +Please, before opening a PR with the new test, make sure that the test fails. If you never see your test fail you don’t know if your test is actually testing the right thing, or testing anything at all. + ## Running the tests ### Run them locally -Run the tests with the following yarn scripts: +When running the tests, FTR is used to spawn both a Kibana instance (http://localhost:5620) and an Elasticsearch instance (http://localhost:9220) with a preloaded minimum set of data (see preceding "Test data" section). + +Run the tests with the following yarn scripts from `x-pack/test/security_solution_cypress`: | Script Name | Description | | ----------- | ----------- | | cypress | Runs the default Cypress command | -| cypress:open | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a local kibana and ES instance. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. |C -| cypress:run | Runs all tests in the `e2e` directory excluding `investigations` and `explore` directories in headless mode | -| cypress:run:cases | Runs all tests under `explore/cases` in the `e2e` directory related to the Cases area team in headless mode | -| cypress:run:reporter | Runs all tests with the specified configuration in headless mode and produces a report using `cypress-multi-reporters` | -| cypress:run:respops | Runs all tests related to the Response Ops area team, specifically tests in `detection_alerts`, `detection_rules`, and `exceptions` directories in headless mode | -| cypress:investigations:run | Runs all tests in the `e2e/investigations` directory in headless mode | -| cypress:explore:run | Runs all tests in the `e2e/explore` directory in headless mode | +| cypress:open:ess | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a local kibana and ES instance. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. | +| cypress:open:serverless | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a mocked serverless environment. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. | +| cypress:run:ess | Runs all tests tagged as ESS placed in the `e2e` directory excluding `investigations` and `explore` directories in headless mode | +| cypress:run:cases:ess | Runs all tests under `explore/cases` in the `e2e` directory related to the Cases area team in headless mode | +| cypress:ess | Runs all ESS tests with the specified configuration in headless mode and produces a report using `cypress-multi-reporters` | +| cypress:run:respops:ess | Runs all tests related to the Response Ops area team, specifically tests in `detection_alerts`, `detection_rules`, and `exceptions` directories in headless mode | +| cypress:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e` directory excluding `investigations` and `explore` directories in headless mode | +| cypress:investigations:run:ess | Runs all tests tagged as ESS in the `e2e/investigations` directory in headless mode | +| cypress:explore:run:ess | Runs all tests tagged as ESS in the `e2e/explore` directory in headless mode | +| cypress:investigations:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode | +| cypress:explore:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/explore` directory in headless mode | | junit:merge | Merges individual test reports into a single report and moves the report to the `junit` directory | Please note that all the headless mode commands do not open the Cypress UI and are typically used in CI/CD environments. The scripts that open the Cypress UI are useful for development and debugging. @@ -148,7 +166,7 @@ We use es_archiver to manage the data that our Cypress tests need. 1. Set up a clean instance of kibana and elasticsearch (if this is not possible, try to clean/minimize the data that you are going to archive). 2. With the kibana and elasticsearch instance up and running, create the data that you need for your test. -3. When you are sure that you have all the data you need run the following command from: `x-pack/plugins/security_solution` +3. When you are sure that you have all the data you need run the following command from: `x-pack/test/security_solution_cypress` ```sh node ../../../scripts/es_archiver save --dir ../../test/security_solution_cypress/es_archives --config ../../../test/functional/config.base.js --es-url http://:@: @@ -164,7 +182,7 @@ Note that the command will create the folder if it does not exist. ### Using an archive from within the Cypress tests -Task [cypress/support/es_archiver.ts](https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/cypress/support/es_archiver.ts) provides helpers such as `esArchiverLoad` and `esArchiverUnload` by means of `es_archiver`'s CLI. +Task [cypress/support/es_archiver.ts](https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts) provides helpers such as `esArchiverLoad` and `esArchiverUnload` by means of `es_archiver`'s CLI. ## Development Best Practices diff --git a/x-pack/plugins/security_solution/cypress/cypress.config.ts b/x-pack/test/security_solution_cypress/cypress/cypress.config.ts similarity index 82% rename from x-pack/plugins/security_solution/cypress/cypress.config.ts rename to x-pack/test/security_solution_cypress/cypress/cypress.config.ts index 9dae3a0acf3cf..1d158df535266 100644 --- a/x-pack/plugins/security_solution/cypress/cypress.config.ts +++ b/x-pack/test/security_solution_cypress/cypress/cypress.config.ts @@ -10,6 +10,10 @@ import { esArchiver } from './support/es_archiver'; export default defineCypressConfig({ defaultCommandTimeout: 60000, + env: { + grepFilterSpecs: true, + grepTags: '@ess', + }, execTimeout: 60000, pageLoadTimeout: 60000, responseTimeout: 60000, @@ -25,6 +29,9 @@ export default defineCypressConfig({ experimentalMemoryManagement: true, setupNodeEvents(on, config) { esArchiver(on, config); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('@cypress/grep/src/plugin')(config); + return config; }, }, }); diff --git a/x-pack/plugins/security_solution/cypress/cypress_ci.config.ts b/x-pack/test/security_solution_cypress/cypress/cypress_ci.config.ts similarity index 83% rename from x-pack/plugins/security_solution/cypress/cypress_ci.config.ts rename to x-pack/test/security_solution_cypress/cypress/cypress_ci.config.ts index c3556b8c1d36c..6927775fcce8a 100644 --- a/x-pack/plugins/security_solution/cypress/cypress_ci.config.ts +++ b/x-pack/test/security_solution_cypress/cypress/cypress_ci.config.ts @@ -11,6 +11,10 @@ import { esArchiver } from './support/es_archiver'; // eslint-disable-next-line import/no-default-export export default defineCypressConfig({ defaultCommandTimeout: 150000, + env: { + grepFilterSpecs: true, + grepTags: '@ess', + }, execTimeout: 150000, pageLoadTimeout: 150000, numTestsKeptInMemory: 0, @@ -29,6 +33,9 @@ export default defineCypressConfig({ specPattern: './cypress/e2e/**/*.cy.ts', setupNodeEvents(on, config) { esArchiver(on, config); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('@cypress/grep/src/plugin')(config); + return config; }, }, }); diff --git a/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts b/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts new file mode 100644 index 0000000000000..86ab94768f8e2 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts @@ -0,0 +1,41 @@ +/* + * 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 { defineCypressConfig } from '@kbn/cypress-config'; +import { esArchiver } from './support/es_archiver'; + +// eslint-disable-next-line import/no-default-export +export default defineCypressConfig({ + defaultCommandTimeout: 150000, + env: { + grepFilterSpecs: true, + grepTags: '@serverless --@brokenInServerless', + }, + execTimeout: 150000, + pageLoadTimeout: 150000, + numTestsKeptInMemory: 0, + retries: { + runMode: 1, + }, + screenshotsFolder: '../../../target/kibana-security-solution/cypress/screenshots', + trashAssetsBeforeRuns: false, + video: false, + videosFolder: '../../../../target/kibana-security-solution/cypress/videos', + viewportHeight: 946, + viewportWidth: 1680, + e2e: { + baseUrl: 'http://localhost:5601', + experimentalMemoryManagement: true, + specPattern: './cypress/e2e/**/*.cy.ts', + setupNodeEvents(on, config) { + esArchiver(on, config); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('@cypress/grep/src/plugin')(config); + return config; + }, + }, +}); diff --git a/x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts b/x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts new file mode 100644 index 0000000000000..d0a89bb34a68a --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/cypress_serverless.config.ts @@ -0,0 +1,38 @@ +/* + * 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 { defineCypressConfig } from '@kbn/cypress-config'; +import { esArchiver } from './support/es_archiver'; + +// eslint-disable-next-line import/no-default-export +export default defineCypressConfig({ + defaultCommandTimeout: 60000, + execTimeout: 60000, + pageLoadTimeout: 60000, + responseTimeout: 60000, + screenshotsFolder: '../../../target/kibana-security-solution/cypress/screenshots', + trashAssetsBeforeRuns: false, + video: false, + videosFolder: '../../../target/kibana-security-solution/cypress/videos', + viewportHeight: 946, + viewportWidth: 1680, + numTestsKeptInMemory: 10, + env: { + grepFilterSpecs: true, + grepTags: '@serverless --@brokenInServerless', + }, + e2e: { + experimentalRunAllSpecs: true, + experimentalMemoryManagement: true, + setupNodeEvents(on, config) { + esArchiver(on, config); + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('@cypress/grep/src/plugin')(config); + return config; + }, + }, +}); diff --git a/x-pack/plugins/security_solution/cypress/data/detection_engine.ts b/x-pack/test/security_solution_cypress/cypress/data/detection_engine.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/data/detection_engine.ts rename to x-pack/test/security_solution_cypress/cypress/data/detection_engine.ts index d05ca3c1a1542..a465c338156b5 100644 --- a/x-pack/plugins/security_solution/cypress/data/detection_engine.ts +++ b/x-pack/test/security_solution_cypress/cypress/data/detection_engine.ts @@ -24,7 +24,7 @@ import type { RuleName, RuleReferenceArray, RuleTagArray, -} from '../../common/api/detection_engine'; +} from '@kbn/security-solution-plugin/common/api/detection_engine'; interface RuleFields { defaultIndexPatterns: IndexPatternArray; diff --git a/x-pack/plugins/security_solution/cypress/e2e/data_sources/create_runtime_field.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/create_runtime_field.cy.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/e2e/data_sources/create_runtime_field.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/data_sources/create_runtime_field.cy.ts index bc64948a94ded..3f30d0d73d999 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/data_sources/create_runtime_field.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/create_runtime_field.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { login, visit } from '../../tasks/login'; import { openTimelineUsingToggle } from '../../tasks/security_main'; import { openTimelineFieldsBrowser, populateTimeline } from '../../tasks/timeline'; @@ -25,7 +27,7 @@ import { GET_TIMELINE_HEADER } from '../../screens/timeline'; const alertRunTimeField = 'field.name.alert.page'; const timelineRuntimeField = 'field.name.timeline'; -describe('Create DataView runtime field', () => { +describe('Create DataView runtime field', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { deleteRuntimeField('security-solution-default', alertRunTimeField); deleteRuntimeField('security-solution-default', timelineRuntimeField); diff --git a/x-pack/plugins/security_solution/cypress/e2e/data_sources/sourcerer.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/data_sources/sourcerer.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer.cy.ts index f758128ae74d4..255e20dda250c 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/data_sources/sourcerer.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer.cy.ts @@ -5,6 +5,12 @@ * 2.0. */ +import { + DEFAULT_ALERTS_INDEX, + DEFAULT_INDEX_PATTERN, +} from '@kbn/security-solution-plugin/common/constants'; +import { tag } from '../../tags'; + import { login, loginWithUser, visit, visitWithUser } from '../../tasks/login'; import { HOSTS_URL, TIMELINES_URL } from '../../urls/navigation'; @@ -30,7 +36,6 @@ import { postDataView } from '../../tasks/common'; import { openTimelineUsingToggle } from '../../tasks/security_main'; import { createUsersAndRoles, secReadCasesAll, secReadCasesAllUser } from '../../tasks/privileges'; import { TOASTER } from '../../screens/configure_cases'; -import { DEFAULT_ALERTS_INDEX, DEFAULT_INDEX_PATTERN } from '../../../common/constants'; import { SOURCERER } from '../../screens/sourcerer'; import { createTimeline } from '../../tasks/api_calls/timelines'; import { getTimeline, getTimelineModifiedSourcerer } from '../../objects/timeline'; @@ -46,7 +51,7 @@ describe('Sourcerer', () => { cy.task('esArchiverResetKibana'); dataViews.forEach((dataView: string) => postDataView(dataView)); }); - describe('permissions', () => { + describe('permissions', { tags: tag.ESS }, () => { before(() => { createUsersAndRoles(usersToCreate, rolesToCreate); }); @@ -57,7 +62,7 @@ describe('Sourcerer', () => { }); }); - describe('Default scope', () => { + describe('Default scope', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { cy.clearLocalStorage(); login(); @@ -117,20 +122,24 @@ describe('Sourcerer', () => { cy.get(SOURCERER.saveButton).should('be.disabled'); }); - it('adds a pattern to the default index and correctly filters out auditbeat-*', () => { - openSourcerer(); - isSourcererSelection(`auditbeat-*`); - isNotSourcererSelection('*beat*'); - addIndexToDefault('*beat*'); - isHostsStatValue('1'); - openSourcerer(); - openAdvancedSettings(); - isSourcererSelection(`auditbeat-*`); - isSourcererSelection('*beat*'); - }); + it( + 'adds a pattern to the default index and correctly filters out auditbeat-*', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + openSourcerer(); + isSourcererSelection(`auditbeat-*`); + isNotSourcererSelection('*beat*'); + addIndexToDefault('*beat*'); + isHostsStatValue('1'); + openSourcerer(); + openAdvancedSettings(); + isSourcererSelection(`auditbeat-*`); + isSourcererSelection('*beat*'); + } + ); }); }); -describe('Timeline scope', () => { +describe('Timeline scope', { tags: tag.BROKEN_IN_SERVERLESS }, () => { beforeEach(() => { cy.clearLocalStorage(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alert_tags.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alert_tags.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alert_tags.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alert_tags.cy.ts index b749604ef58e4..940e01b0b9ced 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alert_tags.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alert_tags.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { getNewRule } from '../../objects/rule'; import { clickAlertTag, @@ -24,7 +26,7 @@ import { UNSELECTED_ALERT_TAG, } from '../../screens/alerts'; -describe('Alert tagging', () => { +describe('Alert tagging', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverResetKibana'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alerts_charts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_charts.cy.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alerts_charts.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_charts.cy.ts index 1b88322326736..e2ce8ab68f4b1 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/alerts_charts.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_charts.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { getNewRule } from '../../objects/rule'; import { ALERTS_COUNT } from '../../screens/alerts'; import { @@ -24,7 +26,7 @@ import { } from '../../screens/search_bar'; import { TOASTER } from '../../screens/alerts_detection_rules'; -describe('Histogram legend hover actions', () => { +describe('Histogram legend hover actions', { tags: [tag.ESS, tag.SERVERLESS] }, () => { const ruleConfigs = getNewRule(); before(() => { 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 new file mode 100644 index 0000000000000..59aa3a5abe793 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts @@ -0,0 +1,199 @@ +/* + * 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 { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../tags'; + +import { DETECTIONS_RULE_MANAGEMENT_URL, ALERTS_URL } from '../../urls/navigation'; +import { getNewRule } from '../../objects/rule'; +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'; + +const loadPageAsPlatformEngineerUser = (url: string) => { + login(ROLES.soc_manager); + waitForPageWithoutDateRange(url, ROLES.soc_manager); + waitForPageTitleToBeShown(); +}; + +const waitForPageTitleToBeShown = () => { + cy.get(PAGE_TITLE).should('be.visible'); +}; + +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. + login(); + visitWithoutDateRange(ALERTS_URL); + waitForPageTitleToBeShown(); + }); + + context( + 'The users index_mapping_outdated is "true" and their admin callouts should show up', + () => { + beforeEach(() => { + // Index mapping outdated is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', (req) => { + req.reply((res) => { + res.send(200, { + index_mapping_outdated: true, + name: '.alerts-security.alerts-default', + }); + }); + }); + }); + + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(ALERTS_URL); + }); + + it('We show the need admin primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createRule(getNewRule({ rule_id: 'rule_testing' })); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary'); + }); + }); + } + ); + + context( + 'The users index_mapping_outdated is "false" and their admin callouts should not show up ', + () => { + beforeEach(() => { + // Index mapping outdated is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: false, + name: '.alerts-security.alerts-default', + }); + }); + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(ALERTS_URL); + }); + + it('We show the need admin primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createRule(getNewRule({ rule_id: 'rule_testing' })); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + } + ); + + context( + 'The users index_mapping_outdated is "null" and their admin callouts should not show up ', + () => { + beforeEach(() => { + // Index mapping outdated is forced to return true as being outdated so that we get the + // need admin callouts being shown. + cy.intercept('GET', '/api/detection_engine/index', { + index_mapping_outdated: null, + name: '.alerts-security.alerts-default', + }); + }); + context('On Detections home page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(ALERTS_URL); + }); + + it('We show the need admin primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rules Management page', () => { + beforeEach(() => { + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + }); + + it('We show 1 primary callout of need admin', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + + context('On Rule Details page', () => { + beforeEach(() => { + createRule(getNewRule({ rule_id: 'rule_testing' })); + loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL); + waitForPageTitleToBeShown(); + goToRuleDetails(); + }); + + afterEach(() => { + deleteCustomRule(); + }); + + it('We show 1 primary callout', () => { + getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist'); + }); + }); + } + ); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/cti_enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/cti_enrichments.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/detection_alerts/cti_enrichments.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/cti_enrichments.cy.ts index 0a626f2fff8d4..35a328cb7aabe 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/cti_enrichments.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/cti_enrichments.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { disableExpandableFlyout } from '../../tasks/api_calls/kibana_advanced_settings'; import { getNewThreatIndicatorRule, indicatorRuleMatchingDoc } from '../../objects/rule'; import { cleanKibana } from '../../tasks/common'; @@ -28,7 +30,7 @@ import { openJsonView, openThreatIndicatorDetails } from '../../tasks/alerts_det import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation'; import { addsFieldsToTimeline } from '../../tasks/rule_details'; -describe('CTI Enrichment', () => { +describe('CTI Enrichment', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'threat_indicator'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/detection_alerts/enrichments.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts index 95481b23174f1..07a5ceb837c48 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/enrichments.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { getNewRule } from '../../objects/rule'; import { HOST_RISK_HEADER_COLIMN, @@ -30,7 +32,7 @@ import { login, visit } from '../../tasks/login'; import { ALERTS_URL } from '../../urls/navigation'; -describe('Enrichment', () => { +describe('Enrichment', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'risk_users'); diff --git a/x-pack/plugins/security_solution/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 similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts index 21b125336e7c6..4ca60eebad297 100644 --- a/x-pack/plugins/security_solution/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 @@ -5,7 +5,9 @@ * 2.0. */ -import { ROLES } from '../../../common/test'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../tags'; + import { DETECTIONS_RULE_MANAGEMENT_URL, ALERTS_URL } from '../../urls/navigation'; import { getNewRule } from '../../objects/rule'; import { PAGE_TITLE } from '../../screens/common/page'; @@ -36,7 +38,7 @@ const waitForPageTitleToBeShown = () => { cy.get(PAGE_TITLE).should('be.visible'); }; -describe('Detections > Callouts', () => { +describe('Detections > Callouts', { tags: tag.ESS }, () => { const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges'; before(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/ransomware_detection.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_detection.cy.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/e2e/detection_alerts/ransomware_detection.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_detection.cy.ts index 1f9dd2fe5cc47..5d2b91416e85c 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/ransomware_detection.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_detection.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; import { login, visit } from '../../tasks/login'; @@ -14,7 +16,7 @@ import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timelin import { selectAlertsHistogram } from '../../tasks/alerts'; import { createTimeline } from '../../tasks/timelines'; -describe('Ransomware Detection Alerts', () => { +describe('Ransomware Detection Alerts', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cy.task('esArchiverLoad', 'ransomware_detection'); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts index bd3e36f962d00..d289e9061db80 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; import { login, visit } from '../../tasks/login'; @@ -14,7 +16,7 @@ import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timelin import { selectAlertsHistogram } from '../../tasks/alerts'; import { createTimeline } from '../../tasks/timelines'; -describe('Ransomware Prevention Alerts', () => { +describe('Ransomware Prevention Alerts', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cy.task('esArchiverLoad', 'ransomware_prevention'); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts new file mode 100644 index 0000000000000..8f97d240488e5 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_authorization.cy.ts @@ -0,0 +1,133 @@ +/* + * 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 { + APP_PATH, + RULES_ADD_PATH, + RULES_UPDATES, +} from '@kbn/security-solution-plugin/common/constants'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../tags'; + +import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules'; +import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules'; +import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common'; +import { login, waitForPageWithoutDateRange } from '../../../tasks/login'; +import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; +import { + ADD_ELASTIC_RULES_BTN, + getInstallSingleRuleButtonByRuleId, + getUpgradeSingleRuleButtonByRuleId, + INSTALL_ALL_RULES_BUTTON, + RULES_UPDATES_TAB, + RULE_CHECKBOX, + UPGRADE_ALL_RULES_BUTTON, +} from '../../../screens/alerts_detection_rules'; + +const RULE_1_ID = 'rule_1'; +const RULE_2_ID = 'rule_2'; +const OUTDATED_RULE_1 = createRuleAssetSavedObject({ + name: 'Outdated rule 1', + rule_id: RULE_1_ID, + version: 1, +}); +const UPDATED_RULE_1 = createRuleAssetSavedObject({ + name: 'Updated rule 1', + rule_id: RULE_1_ID, + version: 2, +}); +const OUTDATED_RULE_2 = createRuleAssetSavedObject({ + name: 'Outdated rule 2', + rule_id: RULE_2_ID, + version: 1, +}); +const UPDATED_RULE_2 = createRuleAssetSavedObject({ + name: 'Updated rule 2', + rule_id: RULE_2_ID, + version: 2, +}); + +const loadPageAsReadOnlyUser = (url: string) => { + login(ROLES.reader); + waitForPageWithoutDateRange(url, ROLES.reader); +}; + +describe( + 'Detection rules, Prebuilt Rules Installation and Update - Authorization/RBAC', + { tags: tag.ESS }, + () => { + beforeEach(() => { + login(); + resetRulesTableState(); + deleteAlertsAndRules(); + cy.task('esArchiverResetKibana'); + waitForRulesTableToBeLoaded(); + createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); + }); + + describe('User with read privileges on Security Solution', () => { + const RULE_1 = createRuleAssetSavedObject({ + name: 'Test rule 1', + rule_id: 'rule_1', + }); + const RULE_2 = createRuleAssetSavedObject({ + name: 'Test rule 2', + rule_id: 'rule_2', + }); + beforeEach(() => { + // Now login with read-only user in preparation for test + createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false }); + loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + }); + + it('should not be able to install prebuilt rules', () => { + // Check that Add Elastic Rules button is disabled + cy.get(ADD_ELASTIC_RULES_BTN).should('be.disabled'); + + // Navigate to Add Elastic Rules page anyways via URL + // and assert that rules cannot be selected and all + // installation buttons are disabled + cy.visit(`${APP_PATH}${RULES_ADD_PATH}`); + cy.get(INSTALL_ALL_RULES_BUTTON).should('be.disabled'); + cy.get(getInstallSingleRuleButtonByRuleId(RULE_1['security-rule'].rule_id)).should( + 'not.exist' + ); + cy.get(RULE_CHECKBOX).should('not.exist'); + }); + }); + + describe('User with read privileges on Security Solution', () => { + beforeEach(() => { + /* Create a second version of the rule, making it available for update */ + createAndInstallMockedPrebuiltRules({ + rules: [UPDATED_RULE_1, UPDATED_RULE_2], + installToKibana: false, + }); + // Now login with read-only user in preparation for test + loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + }); + + it('should not be able to upgrade prebuilt rules', () => { + // Check that Rule Update tab is not shown + cy.get(RULES_UPDATES_TAB).should('not.exist'); + + // Navigate to Rule Update tab anyways via URL + // and assert that rules cannot be selected and all + // upgrade buttons are disabled + cy.visit(`${APP_PATH}${RULES_UPDATES}`); + cy.get(UPGRADE_ALL_RULES_BUTTON).should('be.disabled'); + cy.get(getUpgradeSingleRuleButtonByRuleId(OUTDATED_RULE_1['security-rule'].rule_id)).should( + 'not.exist' + ); + cy.get(RULE_CHECKBOX).should('not.exist'); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts new file mode 100644 index 0000000000000..a5be1d78c537a --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_error_handling.cy.ts @@ -0,0 +1,151 @@ +/* + * 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 { tag } from '../../../tags'; + +import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules'; +import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules'; +import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; +import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; +import { + addElasticRulesButtonClick, + assertRuleAvailableForInstallAndInstallOne, + assertRuleAvailableForInstallAndInstallSelected, + assertRuleAvailableForInstallAndInstallAllInPage, + assertRuleAvailableForInstallAndInstallAll, + assertRuleUpgradeAvailableAndUpgradeOne, + assertRuleUpgradeAvailableAndUpgradeSelected, + assertRuleUpgradeAvailableAndUpgradeAllInPage, + assertRuleUpgradeAvailableAndUpgradeAll, + ruleUpdatesTabClick, +} from '../../../tasks/prebuilt_rules'; + +describe( + 'Detection rules, Prebuilt Rules Installation and Update - Error handling', + { tags: tag.ESS }, + () => { + beforeEach(() => { + login(); + resetRulesTableState(); + deleteAlertsAndRules(); + cy.task('esArchiverResetKibana'); + + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + }); + + describe('Installation of prebuilt rules - Should fail gracefully with toast error message when', () => { + const RULE_1 = createRuleAssetSavedObject({ + name: 'Test rule 1', + rule_id: 'rule_1', + }); + const RULE_2 = createRuleAssetSavedObject({ + name: 'Test rule 2', + rule_id: 'rule_2', + }); + beforeEach(() => { + createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false }); + waitForRulesTableToBeLoaded(); + }); + + it('installing prebuilt rules one by one', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1], didRequestFail: true }); + }); + + it('installing multiple selected prebuilt rules by selecting them individually', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallSelected({ + rules: [RULE_1, RULE_2], + didRequestFail: true, + }); + }); + + it('installing multiple selected prebuilt rules by selecting all in page', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallAllInPage({ + rules: [RULE_1, RULE_2], + didRequestFail: true, + }); + }); + + it('installing all available rules at once', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallAll({ + rules: [RULE_1, RULE_2], + didRequestFail: true, + }); + }); + }); + + describe('Update of prebuilt rules - Should fail gracefully with toast error message when', () => { + const RULE_1_ID = 'rule_1'; + const RULE_2_ID = 'rule_2'; + const OUTDATED_RULE_1 = createRuleAssetSavedObject({ + name: 'Outdated rule 1', + rule_id: RULE_1_ID, + version: 1, + }); + const UPDATED_RULE_1 = createRuleAssetSavedObject({ + name: 'Updated rule 1', + rule_id: RULE_1_ID, + version: 2, + }); + const OUTDATED_RULE_2 = createRuleAssetSavedObject({ + name: 'Outdated rule 2', + rule_id: RULE_2_ID, + version: 1, + }); + const UPDATED_RULE_2 = createRuleAssetSavedObject({ + name: 'Updated rule 2', + rule_id: RULE_2_ID, + version: 2, + }); + beforeEach(() => { + /* Create a new rule and install it */ + createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); + /* Create a second version of the rule, making it available for update */ + createAndInstallMockedPrebuiltRules({ + rules: [UPDATED_RULE_1, UPDATED_RULE_2], + installToKibana: false, + }); + waitForRulesTableToBeLoaded(); + reload(); + }); + + it('upgrading prebuilt rules one by one', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1], didRequestFail: true }); + }); + + it('upgrading multiple selected prebuilt rules by selecting them individually', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeSelected({ + rules: [OUTDATED_RULE_1, OUTDATED_RULE_2], + didRequestFail: true, + }); + }); + + it('upgrading multiple selected prebuilt rules by selecting all in page', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeAllInPage({ + rules: [OUTDATED_RULE_1, OUTDATED_RULE_2], + didRequestFail: true, + }); + }); + + it('upgrading all rules with available upgrades at once', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeAll({ + rules: [OUTDATED_RULE_1, OUTDATED_RULE_2], + didRequestFail: true, + }); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts new file mode 100644 index 0000000000000..8863dbf2f1239 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_install_update_workflows.cy.ts @@ -0,0 +1,270 @@ +/* + * 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 { BulkInstallPackageInfo } from '@kbn/fleet-plugin/common'; +import type { Rule } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types'; +import { tag } from '../../../tags'; +import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { + GO_BACK_TO_RULES_TABLE_BUTTON, + INSTALL_ALL_RULES_BUTTON, + INSTALL_SELECTED_RULES_BUTTON, + NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE, + NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE, + RULES_UPDATES_TAB, + RULE_CHECKBOX, + SELECT_ALL_RULES_ON_PAGE_CHECKBOX, + TOASTER, +} from '../../../screens/alerts_detection_rules'; +import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules'; +import { + getRuleAssets, + createAndInstallMockedPrebuiltRules, +} from '../../../tasks/api_calls/prebuilt_rules'; +import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; +import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; +import { + addElasticRulesButtonClick, + assertRuleAvailableForInstallAndInstallOne, + assertRuleAvailableForInstallAndInstallSelected, + assertRuleAvailableForInstallAndInstallAllInPage, + assertRuleAvailableForInstallAndInstallAll, + assertRuleUpgradeAvailableAndUpgradeOne, + assertRuleUpgradeAvailableAndUpgradeSelected, + assertRuleUpgradeAvailableAndUpgradeAllInPage, + assertRuleUpgradeAvailableAndUpgradeAll, + ruleUpdatesTabClick, +} from '../../../tasks/prebuilt_rules'; + +describe( + 'Detection rules, Prebuilt Rules Installation and Update workflow', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + login(); + resetRulesTableState(); + deleteAlertsAndRules(); + cy.task('esArchiverResetKibana'); + + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + }); + + describe('Installation of prebuilt rules package via Fleet', () => { + beforeEach(() => { + cy.intercept('POST', '/api/fleet/epm/packages/_bulk*').as('installPackageBulk'); + cy.intercept('POST', '/api/fleet/epm/packages/security_detection_engine/*').as( + 'installPackage' + ); + waitForRulesTableToBeLoaded(); + }); + + it('should install package from Fleet in the background', () => { + /* Assert that the package in installed from Fleet */ + cy.wait('@installPackageBulk', { + timeout: 60000, + }).then(({ response: bulkResponse }) => { + cy.wrap(bulkResponse?.statusCode).should('eql', 200); + + const packages = bulkResponse?.body.items.map( + ({ name, result }: BulkInstallPackageInfo) => ({ + name, + }) + ); + + const packagesBulkInstalled = packages.map(({ name }: { name: string }) => name); + + // Under normal flow the package is installed via the Fleet bulk install API. + // However, for testing purposes the package can be installed via the Fleet individual install API, + // so we need to intercept and wait for that request as well. + if (!packagesBulkInstalled.includes('security_detection_engine')) { + // Should happen only during testing when the `xpack.securitySolution.prebuiltRulesPackageVersion` flag is set + cy.wait('@installPackage').then(({ response }) => { + cy.wrap(response?.statusCode).should('eql', 200); + cy.wrap(response?.body) + .should('have.property', 'items') + .should('have.length.greaterThan', 0); + }); + } else { + // Normal flow, install via the Fleet bulk install API + expect(packages.length).to.have.greaterThan(0); + // At least one of the packages installed should be the security_detection_engine package + expect(packages).to.satisfy((pckgs: BulkInstallPackageInfo[]) => + pckgs.some((pkg) => pkg.name === 'security_detection_engine') + ); + } + }); + }); + + it('should install rules from the Fleet package when user clicks on CTA', () => { + const getRulesAndAssertNumberInstalled = () => { + getRuleAssets().then((response) => { + const ruleIds = response.body.hits.hits.map( + (hit: { _source: { ['security-rule']: Rule } }) => + hit._source['security-rule'].rule_id + ); + + const numberOfRulesToInstall = new Set(ruleIds).size; + addElasticRulesButtonClick(); + + cy.get(INSTALL_ALL_RULES_BUTTON).should('be.enabled').click(); + cy.get(TOASTER) + .should('be.visible') + .should('have.text', `${numberOfRulesToInstall} rules installed successfully.`); + }); + }; + /* Retrieve how many rules were installed from the Fleet package */ + /* See comments in test above for more details */ + cy.wait('@installPackageBulk', { + timeout: 60000, + }).then(({ response: bulkResponse }) => { + cy.wrap(bulkResponse?.statusCode).should('eql', 200); + + const packagesBulkInstalled = bulkResponse?.body.items.map( + ({ name }: { name: string }) => name + ); + + if (!packagesBulkInstalled.includes('security_detection_engine')) { + cy.wait('@installPackage').then(() => { + getRulesAndAssertNumberInstalled(); + }); + } else { + getRulesAndAssertNumberInstalled(); + } + }); + }); + }); + + describe('Installation of prebuilt rules', () => { + const RULE_1 = createRuleAssetSavedObject({ + name: 'Test rule 1', + rule_id: 'rule_1', + }); + const RULE_2 = createRuleAssetSavedObject({ + name: 'Test rule 2', + rule_id: 'rule_2', + }); + beforeEach(() => { + createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false }); + waitForRulesTableToBeLoaded(); + cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform').as( + 'installPrebuiltRules' + ); + }); + + it('should install prebuilt rules one by one', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1] }); + }); + + it('should install multiple selected prebuilt rules by selecting them individually', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallSelected({ rules: [RULE_1, RULE_2] }); + }); + + it('should install multiple selected prebuilt rules by selecting all in page', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallAllInPage({ rules: [RULE_1, RULE_2] }); + }); + + it('should install all available rules at once', () => { + addElasticRulesButtonClick(); + assertRuleAvailableForInstallAndInstallAll({ rules: [RULE_1, RULE_2] }); + }); + + it('should display an empty screen when all available prebuilt rules have been installed', () => { + addElasticRulesButtonClick(); + cy.get(INSTALL_ALL_RULES_BUTTON).click(); + cy.get(TOASTER).should('be.visible').should('have.text', `2 rules installed successfully.`); + cy.get(RULE_CHECKBOX).should('not.exist'); + cy.get(NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE).should('exist'); + cy.get(GO_BACK_TO_RULES_TABLE_BUTTON).should('exist'); + }); + + it('should fail gracefully with toast error message when request to install rules fails', () => { + /* Stub request to force rules installation to fail */ + cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform', { + statusCode: 500, + }).as('installPrebuiltRules'); + addElasticRulesButtonClick(); + cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click(); + cy.get(INSTALL_SELECTED_RULES_BUTTON).click(); + cy.wait('@installPrebuiltRules'); + cy.get(TOASTER).should('be.visible').should('have.text', 'Rule installation failed'); + }); + }); + + describe('Upgrade of prebuilt rules', () => { + const RULE_1_ID = 'rule_1'; + const RULE_2_ID = 'rule_2'; + const OUTDATED_RULE_1 = createRuleAssetSavedObject({ + name: 'Outdated rule 1', + rule_id: RULE_1_ID, + version: 1, + }); + const UPDATED_RULE_1 = createRuleAssetSavedObject({ + name: 'Updated rule 1', + rule_id: RULE_1_ID, + version: 2, + }); + const OUTDATED_RULE_2 = createRuleAssetSavedObject({ + name: 'Outdated rule 2', + rule_id: RULE_2_ID, + version: 1, + }); + const UPDATED_RULE_2 = createRuleAssetSavedObject({ + name: 'Updated rule 2', + rule_id: RULE_2_ID, + version: 2, + }); + beforeEach(() => { + cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/upgrade/_perform').as( + 'updatePrebuiltRules' + ); + /* Create a new rule and install it */ + createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); + /* Create a second version of the rule, making it available for update */ + createAndInstallMockedPrebuiltRules({ + rules: [UPDATED_RULE_1, UPDATED_RULE_2], + installToKibana: false, + }); + waitForRulesTableToBeLoaded(); + reload(); + }); + + it('should upgrade prebuilt rules one by one', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1] }); + }); + + it('should upgrade multiple selected prebuilt rules by selecting them individually', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeSelected({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); + }); + + it('should upgrade multiple selected prebuilt rules by selecting all in page', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeAllInPage({ + rules: [OUTDATED_RULE_1, OUTDATED_RULE_2], + }); + }); + + it('should upgrade all rules with available upgrades at once', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); + cy.get(RULES_UPDATES_TAB).should('not.exist'); + }); + + it('should display an empty screen when all rules with available updates have been upgraded', () => { + ruleUpdatesTabClick(); + assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] }); + cy.get(RULES_UPDATES_TAB).should('not.exist'); + cy.get(NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE).should('exist'); + }); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_management.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_management.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_management.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_management.cy.ts index 07478b229e21c..128f8d27b5da2 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_management.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_management.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { createRuleAssetSavedObject } from '../../../helpers/rules'; import { COLLAPSED_ACTION_BTN, @@ -49,7 +51,7 @@ const rules = Array.from(Array(5)).map((_, i) => { }); }); -describe('Prebuilt rules', () => { +describe('Prebuilt rules', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts new file mode 100644 index 0000000000000..abeaee0820558 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules/prebuilt_rules_notifications.cy.ts @@ -0,0 +1,192 @@ +/* + * 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 { tag } from '../../../tags'; + +import { createRuleAssetSavedObject } from '../../../helpers/rules'; +import { ADD_ELASTIC_RULES_BTN, RULES_UPDATES_TAB } from '../../../screens/alerts_detection_rules'; +import { + deleteFirstRule, + waitForRulesTableToBeLoaded, +} from '../../../tasks/alerts_detection_rules'; +import { + installAllPrebuiltRulesRequest, + createAndInstallMockedPrebuiltRules, +} from '../../../tasks/api_calls/prebuilt_rules'; +import { + resetRulesTableState, + deleteAlertsAndRules, + reload, + deletePrebuiltRulesAssets, +} from '../../../tasks/common'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; +import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation'; + +const RULE_1 = createRuleAssetSavedObject({ + name: 'Test rule 1', + rule_id: 'rule_1', +}); + +describe( + 'Detection rules, Prebuilt Rules Installation and Update Notifications', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + login(); + /* Make sure persisted rules table state is cleared */ + resetRulesTableState(); + deleteAlertsAndRules(); + deletePrebuiltRulesAssets(); + }); + + describe('No notifications', () => { + it('should NOT display install or update notifications when no prebuilt assets and no rules are installed', () => { + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + // TODO: test plan asserts "should NOT see a CTA to install prebuilt rules" + // but current behavior is to always show the CTA, even with no prebuilt rule assets installed + // Update that behaviour and then update this test. + cy.get(RULES_UPDATES_TAB).should('not.exist'); + }); + + it('should NOT display install or update notifications when latest rules are installed', () => { + createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: true }); + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + + /* Assert that there are no installation or update notifications */ + /* Add Elastic Rules button should not contain a number badge */ + /* and Rule Upgrade tab should not be displayed */ + cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', 'Add Elastic rules'); + cy.get(RULES_UPDATES_TAB).should('not.exist'); + }); + }); + + describe('Notifications', () => { + beforeEach(() => { + createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: false }); + }); + + describe('Rules installation notification when no rules have been installed', () => { + beforeEach(() => { + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + }); + + it('should notify user about prebuilt rules available for installation', () => { + cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible'); + cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`); + cy.get(RULES_UPDATES_TAB).should('not.exist'); + }); + }); + + describe('Rule installation notification when at least one rule already installed', () => { + beforeEach(() => { + installAllPrebuiltRulesRequest().then(() => { + /* Create new rule assets with a different rule_id as the one that was */ + /* installed before in order to trigger the installation notification */ + const RULE_2 = createRuleAssetSavedObject({ + name: 'Test rule 2', + rule_id: 'rule_2', + }); + const RULE_3 = createRuleAssetSavedObject({ + name: 'Test rule 3', + rule_id: 'rule_3', + }); + + createAndInstallMockedPrebuiltRules({ + rules: [RULE_2, RULE_3], + installToKibana: false, + }); + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + }); + }); + + it('should notify user about prebuilt rules available for installation', () => { + const numberOfAvailableRules = 2; + cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible'); + cy.get(ADD_ELASTIC_RULES_BTN).should( + 'have.text', + `Add Elastic rules${numberOfAvailableRules}` + ); + cy.get(RULES_UPDATES_TAB).should('not.exist'); + }); + + it('should notify user a rule is again available for installation if it is deleted', () => { + /* Install available rules, assert that the notification is gone */ + /* then delete one rule and assert that the notification is back */ + installAllPrebuiltRulesRequest().then(() => { + reload(); + deleteFirstRule(); + cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible'); + cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`); + }); + }); + }); + + describe('Rule update notification', () => { + beforeEach(() => { + installAllPrebuiltRulesRequest().then(() => { + /* Create new rule asset with the same rule_id as the one that was installed */ + /* but with a higher version, in order to trigger the update notification */ + const UPDATED_RULE = createRuleAssetSavedObject({ + name: 'Test rule 1.1 (updated)', + rule_id: 'rule_1', + version: 2, + }); + createAndInstallMockedPrebuiltRules({ rules: [UPDATED_RULE], installToKibana: false }); + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + reload(); + }); + }); + + it('should notify user about prebuilt rules package available for update', () => { + // No rules available for installation + cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules`); + // But 1 rule available for update + cy.get(RULES_UPDATES_TAB).should('be.visible'); + cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`); + }); + }); + + describe('Rule installation available and rule update available notifications', () => { + beforeEach(() => { + installAllPrebuiltRulesRequest().then(() => { + /* Create new rule assets with a different rule_id as the one that was */ + /* installed before in order to trigger the installation notification */ + const RULE_2 = createRuleAssetSavedObject({ + name: 'Test rule 2', + rule_id: 'rule_2', + }); + /* Create new rule asset with the same rule_id as the one that was installed */ + /* but with a higher version, in order to trigger the update notification */ + const UPDATED_RULE = createRuleAssetSavedObject({ + name: 'Test rule 1.1 (updated)', + rule_id: 'rule_1', + version: 2, + }); + createAndInstallMockedPrebuiltRules({ + rules: [RULE_2, UPDATED_RULE], + installToKibana: false, + }); + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + }); + }); + + it('should notify user about prebuilt rules available for installation and for upgrade', () => { + // 1 rule available for installation + cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`); + // 1 rule available for update + cy.get(RULES_UPDATES_TAB).should('be.visible'); + cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`); + }); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts new file mode 100644 index 0000000000000..021735f679a20 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions/rule_actions.cy.ts @@ -0,0 +1,78 @@ +/* + * 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 { tag } from '../../../tags'; + +import { getIndexConnector } from '../../../objects/connector'; +import { getSimpleCustomQueryRule } from '../../../objects/rule'; + +import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; +import { deleteIndex, waitForNewDocumentToBeIndexed } from '../../../tasks/api_calls/elasticsearch'; +import { + cleanKibana, + deleteAlertsAndRules, + deleteConnectors, + deleteDataView, +} from '../../../tasks/common'; +import { + createAndEnableRule, + fillAboutRuleAndContinue, + fillDefineCustomRuleAndContinue, + fillRuleAction, + fillScheduleRuleAndContinue, +} from '../../../tasks/create_new_rule'; +import { login, visit } from '../../../tasks/login'; + +import { RULE_CREATION } from '../../../urls/navigation'; + +describe( + 'Rule actions during detection rule creation', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + const indexConnector = getIndexConnector(); + + before(() => { + cleanKibana(); + }); + + beforeEach(() => { + login(); + deleteAlertsAndRules(); + deleteConnectors(); + deleteIndex(indexConnector.index); + deleteDataView(indexConnector.index); + }); + + const rule = getSimpleCustomQueryRule(); + const actions = { connectors: [indexConnector] }; + const index = actions.connectors[0].index; + const initialNumberOfDocuments = 0; + const expectedJson = JSON.parse(actions.connectors[0].document); + + it('Indexes a new document after the index action is triggered ', function () { + visit(RULE_CREATION); + fillDefineCustomRuleAndContinue(rule); + fillAboutRuleAndContinue(rule); + fillScheduleRuleAndContinue(rule); + fillRuleAction(actions); + createAndEnableRule(); + goToRuleDetails(); + + /* When the rule is executed, the action is triggered. We wait for the new document to be indexed */ + waitForNewDocumentToBeIndexed(index, initialNumberOfDocuments); + + /* We assert that the new indexed document is the one set on the index action */ + cy.request({ + method: 'GET', + url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_search`, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, + }).then((response) => { + expect(response.body.hits.hits[0]._source).to.deep.equal(expectedJson); + }); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts similarity index 99% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts index eb1abd71cd43e..5658a0d4aee3e 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { ruleFields } from '../../../data/detection_engine'; import { getNewRule, @@ -112,7 +114,7 @@ import { enablesRule, getDetails } from '../../../tasks/rule_details'; import { RULE_CREATION, DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; -describe('Custom query rules', () => { +describe('Custom query rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts index b1bcf1336670a..e352af5671ae0 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_query_rule_data_view.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules'; import { getDataViewRule } from '../../../objects/rule'; import { ALERTS_COUNT, ALERT_GRID_CELL } from '../../../screens/alerts'; @@ -67,7 +69,7 @@ import { getDetails } from '../../../tasks/rule_details'; import { RULE_CREATION } from '../../../urls/navigation'; -describe('Custom query rules', () => { +describe('Custom query rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { describe('Custom detection rules creation with data views', () => { const rule = getDataViewRule(); const expectedUrls = rule.references?.join(''); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts index 8cb8fc2ba7576..5c512e4c2eff8 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/custom_saved_query_rule.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { getNewRule, getSavedQueryRule } from '../../../objects/rule'; import { @@ -45,7 +47,7 @@ const savedQueryName = 'custom saved query'; const savedQueryQuery = 'process.name: test'; const savedQueryFilterKey = 'testAgent.value'; -describe('Custom saved_query rules', () => { +describe('Custom saved_query rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts index a470a322b1831..2d06b9ec977e7 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules'; import { getEqlRule, getEqlSequenceRule, getIndexPatterns } from '../../../objects/rule'; @@ -61,7 +63,7 @@ import { login, visit } from '../../../tasks/login'; import { RULE_CREATION } from '../../../urls/navigation'; -describe('EQL rules', () => { +describe('EQL rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); }); @@ -150,10 +152,10 @@ describe('EQL rules', () => { const rule = getEqlSequenceRule(); - before(() => { + beforeEach(() => { cy.task('esArchiverLoad', 'auditbeat_big'); }); - after(() => { + afterEach(() => { cy.task('esArchiverUnload', 'auditbeat_big'); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts similarity index 99% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts index ec216364a2031..9f2e8a796ee95 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/indicator_match_rule.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules'; import { getIndexPatterns, @@ -108,7 +110,7 @@ import { DETECTIONS_RULE_MANAGEMENT_URL, RULE_CREATION } from '../../../urls/nav const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d/d"'; -describe('indicator match', () => { +describe('indicator match', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { describe('Detection rules, Indicator Match', () => { const expectedUrls = getNewThreatIndicatorRule().references?.join(''); const expectedFalsePositives = getNewThreatIndicatorRule().false_positives?.join(''); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/machine_learning_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/machine_learning_rule.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/machine_learning_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/machine_learning_rule.cy.ts index d975be9249a5e..815da8ae92cb1 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/machine_learning_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/machine_learning_rule.cy.ts @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { isArray } from 'lodash'; +import { tag } from '../../../tags'; import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules'; import { getMachineLearningRule } from '../../../objects/rule'; @@ -54,7 +54,7 @@ import { login, visitWithoutDateRange } from '../../../tasks/login'; import { RULE_CREATION } from '../../../urls/navigation'; -describe('Detection rules, machine learning', () => { +describe('Detection rules, machine learning', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { const expectedUrls = (getMachineLearningRule().references ?? []).join(''); const expectedFalsePositives = (getMachineLearningRule().false_positives ?? []).join(''); const expectedTags = (getMachineLearningRule().tags ?? []).join(''); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts index ae6296aea904b..14b4b9ad2c717 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/new_terms_rule.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules'; import { getIndexPatterns, getNewTermsRule } from '../../../objects/rule'; @@ -59,7 +61,7 @@ import { login, visit } from '../../../tasks/login'; import { RULE_CREATION } from '../../../urls/navigation'; -describe('New Terms rules', () => { +describe('New Terms rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/override.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/override.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts index 0e6a9462237d8..01f7ff28e2507 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/override.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules'; import { getIndexPatterns, getNewOverrideRule, getSeveritiesOverride } from '../../../objects/rule'; @@ -61,7 +63,7 @@ import { getDetails } from '../../../tasks/rule_details'; import { RULE_CREATION } from '../../../urls/navigation'; -describe('Detection rules, override', () => { +describe('Detection rules, override', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { const rule = getNewOverrideRule(); const expectedUrls = rule.references?.join(''); const expectedFalsePositives = rule.false_positives?.join(''); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts index 5c244b8bb52ca..7c29afc4c0abe 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/threshold_rule.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../tags'; + import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules'; import { getIndexPatterns, getNewThresholdRule } from '../../../objects/rule'; @@ -59,7 +61,7 @@ import { login, visitWithoutDateRange } from '../../../tasks/login'; import { RULE_CREATION } from '../../../urls/navigation'; -describe('Detection rules, threshold', () => { +describe('Detection rules, threshold', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { const rule = getNewThresholdRule(); const expectedUrls = rule.references?.join(''); const expectedFalsePositives = rule.false_positives?.join(''); diff --git a/x-pack/plugins/security_solution/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 similarity index 93% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/authorization/all_rules_read_only.cy.ts index eb7fa7054896f..62f484b69427a 100644 --- a/x-pack/plugins/security_solution/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 @@ -5,7 +5,9 @@ * 2.0. */ -import { ROLES } from '../../../../../common/test'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../../tags'; + import { getNewRule } from '../../../../objects/rule'; import { COLLAPSED_ACTION_BTN, @@ -26,7 +28,7 @@ import { SECURITY_DETECTIONS_RULES_URL } from '../../../../urls/navigation'; const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges'; -describe('All rules - read only', () => { +describe('All rules - read only', { tags: tag.ESS }, () => { before(() => { cleanKibana(); createRule(getNewRule({ rule_id: '1' })); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/maintenance_windows/maintenance_window_callout.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/maintenance_windows/maintenance_window_callout.cy.ts similarity index 83% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/maintenance_windows/maintenance_window_callout.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/maintenance_windows/maintenance_window_callout.cy.ts index 738c844262bf2..e72e8d1664119 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/maintenance_windows/maintenance_window_callout.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/maintenance_windows/maintenance_window_callout.cy.ts @@ -8,11 +8,12 @@ import { INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH } from '@kbn/alerting-plugin/common'; import type { MaintenanceWindowCreateBody } from '@kbn/alerting-plugin/common'; import type { AsApiContract } from '@kbn/alerting-plugin/server/routes/lib'; +import { tag } from '../../../../tags'; import { cleanKibana } from '../../../../tasks/common'; import { login, visit } from '../../../../tasks/login'; import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation'; -describe('Maintenance window callout on Rule Management page', () => { +describe('Maintenance window callout on Rule Management page', { tags: [tag.ESS] }, () => { let maintenanceWindowId = ''; before(() => { @@ -34,7 +35,7 @@ describe('Maintenance window callout on Rule Management page', () => { cy.request({ method: 'POST', url: INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, body, }).then((response) => { maintenanceWindowId = response.body.id; @@ -46,7 +47,7 @@ describe('Maintenance window callout on Rule Management page', () => { cy.request({ method: 'DELETE', url: `${INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH}/${maintenanceWindowId}`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts index 56865abd794c3..c13079d1dd134 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../tags'; + import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation'; import { FIELD } from '../../../../screens/alerts_details'; @@ -52,7 +54,7 @@ Note that the rule we are using for testing purposes has the following character - Integration: unknown */ -describe('Related integrations', () => { +describe('Related integrations', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts index c687deff53cf9..bc228b7160a89 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../../tags'; + import { waitForRulesTableToBeLoaded, goToTheRuleDetailsOf, @@ -53,7 +55,7 @@ const EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item'; const NON_EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item with future expiration'; -describe('Detection rules, bulk duplicate', () => { +describe('Detection rules, bulk duplicate', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts similarity index 99% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts index 385a4476b2e8a..9aea185783e7d 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../../tags'; + import { MODAL_CONFIRMATION_BTN, MODAL_CONFIRMATION_BODY, @@ -121,7 +123,7 @@ const defaultRuleData = { timeline_id: '495ad7a7-316e-4544-8a0f-9c098daee76e', }; -describe('Detection rules, bulk edit', () => { +describe('Detection rules, bulk edit', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { 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 new file mode 100644 index 0000000000000..d6000c671fb86 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts @@ -0,0 +1,226 @@ +/* + * 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 { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../../../tags'; + +import { + RULES_BULK_EDIT_ACTIONS_INFO, + RULES_BULK_EDIT_ACTIONS_WARNING, + ADD_RULE_ACTIONS_MENU_ITEM, +} from '../../../../../screens/rules_bulk_actions'; +import { actionFormSelector } from '../../../../../screens/common/rule_actions'; + +import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common'; +import type { RuleActionCustomFrequency } from '../../../../../tasks/common/rule_actions'; +import { + addSlackRuleAction, + assertSlackRuleAction, + addEmailConnectorAndRuleAction, + assertEmailRuleAction, + assertSelectedCustomFrequencyOption, + assertSelectedPerRuleRunFrequencyOption, + assertSelectedSummaryOfAlertsOption, + pickCustomFrequencyOption, + pickPerRuleRunFrequencyOption, + pickSummaryOfAlertsOption, +} from '../../../../../tasks/common/rule_actions'; +import { + waitForRulesTableToBeLoaded, + selectNumberOfRules, + goToEditRuleActionsSettingsOf, +} from '../../../../../tasks/alerts_detection_rules'; +import { + waitForBulkEditActionToFinish, + submitBulkEditForm, + checkOverwriteRuleActionsCheckbox, + openBulkEditRuleActionsForm, + openBulkActionsMenu, +} from '../../../../../tasks/rules_bulk_actions'; +import { login, visitWithoutDateRange } from '../../../../../tasks/login'; + +import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation'; + +import { createRule } from '../../../../../tasks/api_calls/rules'; +import { createSlackConnector } from '../../../../../tasks/api_calls/connectors'; + +import { + getEqlRule, + getNewThreatIndicatorRule, + getNewRule, + getNewThresholdRule, + getMachineLearningRule, + getNewTermsRule, +} from '../../../../../objects/rule'; +import { excessivelyInstallAllPrebuiltRules } from '../../../../../tasks/api_calls/prebuilt_rules'; + +const ruleNameToAssert = 'Custom rule name with actions'; +const expectedNumberOfCustomRulesToBeEdited = 7; +// 7 custom rules of different types + 3 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 expectedExistingSlackMessage = 'Existing slack action'; +const expectedSlackMessage = 'Slack action test message'; + +// TODO: Fix flakiness and unskip https://github.com/elastic/kibana/issues/154721 +describe.skip( + 'Detection rules, bulk edit of rule actions', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + before(() => { + cleanKibana(); + login(); + }); + + beforeEach(() => { + deleteAlertsAndRules(); + deleteConnectors(); + cy.task('esArchiverResetKibana'); + + createSlackConnector().then(({ body }) => { + const actions: RuleActionArray = [ + { + id: body.id, + action_type_id: '.slack', + group: 'default', + params: { + message: expectedExistingSlackMessage, + }, + frequency: { + summary: true, + throttle: null, + notifyWhen: 'onActiveAlert', + }, + }, + ]; + + createRule(getNewRule({ name: ruleNameToAssert, rule_id: '1', max_signals: 500, actions })); + }); + + createRule(getEqlRule({ rule_id: '2' })); + createRule(getMachineLearningRule({ rule_id: '3' })); + createRule(getNewThreatIndicatorRule({ rule_id: '4' })); + createRule(getNewThresholdRule({ rule_id: '5' })); + createRule(getNewTermsRule({ rule_id: '6' })); + createRule(getNewRule({ saved_id: 'mocked', rule_id: '7' })); + + createSlackConnector(); + }); + + 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); + waitForRulesTableToBeLoaded(); + + selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); + + openBulkActionsMenu(); + + cy.get(ADD_RULE_ACTIONS_MENU_ITEM).should('be.disabled'); + }); + }); + + context('All actions privileges', () => { + beforeEach(() => { + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + waitForRulesTableToBeLoaded(); + }); + + it('Add a rule action to rules (existing connector)', () => { + const expectedActionFrequency: RuleActionCustomFrequency = { + throttle: 1, + throttleUnit: 'd', + }; + + excessivelyInstallAllPrebuiltRules(); + + // select both custom and prebuilt rules + selectNumberOfRules(expectedNumberOfRulesToBeEdited); + openBulkEditRuleActionsForm(); + + // ensure rule actions info callout displayed on the form + cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible'); + + addSlackRuleAction(expectedSlackMessage); + pickSummaryOfAlertsOption(); + pickCustomFrequencyOption(expectedActionFrequency); + + submitBulkEditForm(); + waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited }); + + // check if rule has been updated + goToEditRuleActionsSettingsOf(ruleNameToAssert); + + assertSelectedSummaryOfAlertsOption(); + assertSelectedCustomFrequencyOption(expectedActionFrequency, 1); + assertSlackRuleAction(expectedExistingSlackMessage, 0); + assertSlackRuleAction(expectedSlackMessage, 1); + // ensure there is no third action + cy.get(actionFormSelector(2)).should('not.exist'); + }); + + it('Overwrite rule actions in rules', () => { + excessivelyInstallAllPrebuiltRules(); + + // select both custom and prebuilt rules + selectNumberOfRules(expectedNumberOfRulesToBeEdited); + openBulkEditRuleActionsForm(); + + addSlackRuleAction(expectedSlackMessage); + pickSummaryOfAlertsOption(); + pickPerRuleRunFrequencyOption(); + + // check overwrite box, ensure warning is displayed + checkOverwriteRuleActionsCheckbox(); + cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains( + `You're about to overwrite rule actions for ${expectedNumberOfRulesToBeEdited} selected rules` + ); + + submitBulkEditForm(); + waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited }); + + // check if rule has been updated + goToEditRuleActionsSettingsOf(ruleNameToAssert); + + assertSelectedSummaryOfAlertsOption(); + assertSelectedPerRuleRunFrequencyOption(); + assertSlackRuleAction(expectedSlackMessage); + // ensure existing action was overwritten + cy.get(actionFormSelector(1)).should('not.exist'); + }); + + it('Add a rule action to rules (new connector)', () => { + const expectedActionFrequency: RuleActionCustomFrequency = { + throttle: 2, + throttleUnit: 'h', + }; + const expectedEmail = 'test@example.com'; + const expectedSubject = 'Subject'; + + selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); + openBulkEditRuleActionsForm(); + + addEmailConnectorAndRuleAction(expectedEmail, expectedSubject); + pickSummaryOfAlertsOption(); + pickCustomFrequencyOption(expectedActionFrequency); + + submitBulkEditForm(); + waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited }); + + // check if rule has been updated + goToEditRuleActionsSettingsOf(ruleNameToAssert); + + assertSelectedSummaryOfAlertsOption(); + assertSelectedCustomFrequencyOption(expectedActionFrequency, 1); + assertEmailRuleAction(expectedEmail, expectedSubject); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts new file mode 100644 index 0000000000000..824699e2cd230 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_data_view.cy.ts @@ -0,0 +1,255 @@ +/* + * 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 { tag } from '../../../../../tags'; + +import { + RULES_BULK_EDIT_DATA_VIEWS_WARNING, + RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX, +} from '../../../../../screens/rules_bulk_actions'; + +import { DATA_VIEW_DETAILS, INDEX_PATTERNS_DETAILS } from '../../../../../screens/rule_details'; + +import { + waitForRulesTableToBeLoaded, + goToRuleDetails, + selectNumberOfRules, + goToTheRuleDetailsOf, +} from '../../../../../tasks/alerts_detection_rules'; + +import { + typeIndexPatterns, + waitForBulkEditActionToFinish, + submitBulkEditForm, + checkOverwriteDataViewCheckbox, + checkOverwriteIndexPatternsCheckbox, + openBulkEditAddIndexPatternsForm, + openBulkEditDeleteIndexPatternsForm, +} from '../../../../../tasks/rules_bulk_actions'; + +import { + hasIndexPatterns, + getDetails, + assertDetailsNotExist, +} from '../../../../../tasks/rule_details'; +import { login, visitWithoutDateRange } from '../../../../../tasks/login'; + +import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation'; +import { createRule } from '../../../../../tasks/api_calls/rules'; +import { cleanKibana, deleteAlertsAndRules, postDataView } from '../../../../../tasks/common'; + +import { + getEqlRule, + getNewThreatIndicatorRule, + getNewRule, + getNewThresholdRule, + getNewTermsRule, +} from '../../../../../objects/rule'; + +const DATA_VIEW_ID = 'auditbeat'; + +const expectedIndexPatterns = ['index-1-*', 'index-2-*']; + +const expectedNumberOfCustomRulesToBeEdited = 6; + +describe( + 'Bulk editing index patterns of rules with a data view only', + { tags: [tag.ESS, tag.SERVERLESS] }, + () => { + before(() => { + cleanKibana(); + }); + + beforeEach(() => { + deleteAlertsAndRules(); + cy.task('esArchiverResetKibana'); + login(); + + postDataView(DATA_VIEW_ID); + + createRule(getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '1' })); + createRule(getEqlRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '2' })); + createRule( + getNewThreatIndicatorRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '3' }) + ); + createRule( + getNewThresholdRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '4' }) + ); + createRule(getNewTermsRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '5' })); + createRule( + getNewRule({ + index: undefined, + data_view_id: DATA_VIEW_ID, + saved_id: 'mocked', + rule_id: '6', + }) + ); + + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + + waitForRulesTableToBeLoaded(); + }); + + it('Add index patterns to custom rules with configured data view: all rules are skipped', () => { + selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); + + openBulkEditAddIndexPatternsForm(); + typeIndexPatterns(expectedIndexPatterns); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + skippedCount: expectedNumberOfCustomRulesToBeEdited, + showDataViewsWarning: true, + }); + + // check if rule still has data view and index patterns field does not exist + goToRuleDetails(); + getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); + assertDetailsNotExist(INDEX_PATTERNS_DETAILS); + }); + + it('Add index patterns to custom rules with configured data view when data view checkbox is checked: rules are updated', () => { + selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); + + openBulkEditAddIndexPatternsForm(); + typeIndexPatterns(expectedIndexPatterns); + + // click on data view overwrite checkbox, ensure warning is displayed + cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('not.exist'); + checkOverwriteDataViewCheckbox(); + cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('be.visible'); + + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited }); + + // check if rule has been updated with index patterns and data view does not exist + goToRuleDetails(); + hasIndexPatterns(expectedIndexPatterns.join('')); + assertDetailsNotExist(DATA_VIEW_DETAILS); + }); + + it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is NOT checked:: rules are skipped', () => { + selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); + + openBulkEditAddIndexPatternsForm(); + typeIndexPatterns(expectedIndexPatterns); + checkOverwriteIndexPatternsCheckbox(); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + skippedCount: expectedNumberOfCustomRulesToBeEdited, + showDataViewsWarning: true, + }); + + // check if rule still has data view and index patterns field does not exist + goToRuleDetails(); + getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); + assertDetailsNotExist(INDEX_PATTERNS_DETAILS); + }); + + it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is checked: rules are updated', () => { + selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); + + openBulkEditAddIndexPatternsForm(); + typeIndexPatterns(expectedIndexPatterns); + checkOverwriteIndexPatternsCheckbox(); + checkOverwriteDataViewCheckbox(); + + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited }); + + // check if rule has been overwritten with index patterns and data view does not exist + goToRuleDetails(); + hasIndexPatterns(expectedIndexPatterns.join('')); + assertDetailsNotExist(DATA_VIEW_DETAILS); + }); + + it('Delete index patterns in custom rules with configured data view: rules are skipped', () => { + selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited); + + openBulkEditDeleteIndexPatternsForm(); + typeIndexPatterns(expectedIndexPatterns); + + // in delete form data view checkbox is absent + cy.get(RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX).should('not.exist'); + + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + skippedCount: expectedNumberOfCustomRulesToBeEdited, + showDataViewsWarning: true, + }); + + // check if rule still has data view and index patterns field does not exist + goToRuleDetails(); + getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); + }); + } +); + +describe('Bulk editing index patterns of rules with index patterns and rules with a data view', () => { + const customRulesNumber = 2; + + before(() => { + cleanKibana(); + }); + + beforeEach(() => { + login(); + deleteAlertsAndRules(); + cy.task('esArchiverResetKibana'); + + postDataView(DATA_VIEW_ID); + + createRule( + getNewRule({ name: 'with dataview', index: [], data_view_id: DATA_VIEW_ID, rule_id: '1' }) + ); + createRule(getNewRule({ name: 'no data view', index: ['test-index-1-*'], rule_id: '2' })); + + visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL); + + waitForRulesTableToBeLoaded(); + }); + + it('Add index patterns to custom rules: one rule is updated, one rule is skipped', () => { + selectNumberOfRules(customRulesNumber); + + openBulkEditAddIndexPatternsForm(); + typeIndexPatterns(expectedIndexPatterns); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 1, + skippedCount: 1, + showDataViewsWarning: true, + }); + + // check if rule still has data view and index patterns field does not exist + goToTheRuleDetailsOf('with dataview'); + getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID); + assertDetailsNotExist(INDEX_PATTERNS_DETAILS); + }); + + it('Add index patterns to custom rules when overwrite data view checkbox is checked: all rules are updated', () => { + selectNumberOfRules(customRulesNumber); + + openBulkEditAddIndexPatternsForm(); + typeIndexPatterns(expectedIndexPatterns); + checkOverwriteDataViewCheckbox(); + submitBulkEditForm(); + + waitForBulkEditActionToFinish({ + updatedCount: 2, + }); + + // check if rule still has data view and index patterns field does not exist + goToRuleDetails(); + assertDetailsNotExist(DATA_VIEW_DETAILS); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts index 6c3c1dee6c7ad..e88920efd9726 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/export_rule.cy.ts @@ -6,6 +6,7 @@ */ import path from 'path'; +import { tag } from '../../../../../tags'; import { expectedExportedRule, getNewRule } from '../../../../../objects/rule'; import { @@ -56,7 +57,7 @@ const prebuiltRules = Array.from(Array(7)).map((_, i) => { }); }); -describe('Export rules', () => { +describe('Export rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { const downloadsFolder = Cypress.config('downloadsFolder'); before(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts index 183ab85bbd5d3..4c3eaaefd03c1 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/import_export/import_rules.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../../tags'; + import { TOASTER } from '../../../../../screens/alerts_detection_rules'; import { expectManagementTableRules, @@ -17,7 +19,7 @@ import { login, visitWithoutDateRange } from '../../../../../tasks/login'; import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../../urls/navigation'; const RULES_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_rules.ndjson'; -describe('Import rules', () => { +describe('Import rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts index b3939ff3c7b27..c16ca1a337622 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts @@ -6,7 +6,9 @@ */ import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/common'; -import type { RuleResponse } from '../../../../../../common/api/detection_engine'; +import type { RuleResponse } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { tag } from '../../../../../tags'; + import { createRule, snoozeRule as snoozeRuleViaAPI } from '../../../../../tasks/api_calls/rules'; import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common'; import { login, visitWithoutDateRange } from '../../../../../tasks/login'; @@ -42,7 +44,7 @@ import { TOOLTIP } from '../../../../../screens/common'; const RULES_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_rules.ndjson'; -describe('rule snoozing', () => { +describe('rule snoozing', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts index bd3363572915d..d56beb1fec0e0 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../tags'; + import { RULE_CHECKBOX, REFRESH_RULES_STATUS, @@ -32,7 +34,7 @@ import { getNewRule } from '../../../../objects/rule'; const DEFAULT_RULE_REFRESH_INTERVAL_VALUE = 60000; const NUM_OF_TEST_RULES = 6; -describe('Rules table: auto-refresh', () => { +describe('Rules table: auto-refresh', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts index 5c94cfb3f1bcb..3c113648e2a23 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../tags'; + import { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../../../tasks/common'; import { login, visitWithoutDateRange } from '../../../../tasks/login'; import { @@ -26,7 +28,7 @@ import { import { getNewRule } from '../../../../objects/rule'; -describe('Rules table: filtering', () => { +describe('Rules table: filtering', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts index b7fa19531065d..fe638d41f6587 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../tags'; + import { getNewRule } from '../../../../objects/rule'; import { RULES_MONITORING_TAB, RULE_NAME } from '../../../../screens/alerts_detection_rules'; import { createRule } from '../../../../tasks/api_calls/rules'; @@ -12,7 +14,7 @@ import { cleanKibana, deleteAlertsAndRules } from '../../../../tasks/common'; import { login, visitWithoutDateRange } from '../../../../tasks/login'; import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation'; -describe('Rules table: links', () => { +describe('Rules table: links', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts index ef3d23cf71162..a6ef9d1d0115e 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts @@ -6,6 +6,8 @@ */ import { encode } from '@kbn/rison'; +import { tag } from '../../../../tags'; + import { cleanKibana, resetRulesTableState } from '../../../../tasks/common'; import { login, visit } from '../../../../tasks/login'; import { @@ -98,7 +100,7 @@ function expectDefaultRulesTableState(): void { expectTablePage(1); } -describe('Rules table: persistent state', () => { +describe('Rules table: persistent state', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); createTestRules(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts index db68e62d92315..3ff965be8c663 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_selection.cy.ts @@ -4,6 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + +import { tag } from '../../../../tags'; + import { createRuleAssetSavedObject } from '../../../../helpers/rules'; import { SELECTED_RULES_NUMBER_LABEL, @@ -32,7 +35,7 @@ const RULE_2 = createRuleAssetSavedObject({ rule_id: 'rule_2', }); -describe('Rules table: selection', () => { +describe('Rules table: selection', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_sorting.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_sorting.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_sorting.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_sorting.cy.ts index 66fe81f43c874..99b7cc9a3a8e1 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management/rules_table/rules_table_sorting.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_sorting.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../tags'; + import { FIRST_RULE, RULE_NAME, @@ -37,7 +39,7 @@ import { } from '../../../../tasks/table_pagination'; import { TABLE_FIRST_PAGE, TABLE_SECOND_PAGE } from '../../../../screens/table_pagination'; -describe('Rules table: sorting', () => { +describe('Rules table: sorting', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_response/value_lists/value_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/detection_response/value_lists/value_lists.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts index dbbb9badd8b9d..60b0b02d79726 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_response/value_lists/value_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts @@ -5,8 +5,10 @@ * 2.0. */ -import { ROLES } from '../../../../common/test'; -import { deleteRoleAndUser, login, visitWithoutDateRange } from '../../../tasks/login'; +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../tags'; + +import { login, visitWithoutDateRange } from '../../../tasks/login'; import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; import { createListsIndex, @@ -29,7 +31,7 @@ import { } from '../../../screens/lists'; describe('value lists', () => { - describe('management modal', () => { + describe('management modal', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { login(); createListsIndex(); @@ -221,17 +223,10 @@ describe('value lists', () => { }); }); - describe('user with restricted access role', () => { - before(() => { + describe('user with restricted access role', { tags: tag.ESS }, () => { + it('Does not allow a t1 analyst user to upload a value list', () => { login(ROLES.t1_analyst); visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL, ROLES.t1_analyst); - }); - - after(() => { - deleteRoleAndUser(ROLES.t1_analyst); - }); - - it('Does not allow a t1 analyst user to upload a value list', () => { cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled'); }); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts index da06359fc789b..b70a25a676459 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { PAGE_TITLE, HOST_RISK_PREVIEW_TABLE, @@ -41,7 +43,10 @@ import { describe( 'Entity analytics management page', - { env: { ftrConfig: { enableExperimental: ['riskScoringRoutesEnabled'] } } }, + { + env: { ftrConfig: { enableExperimental: ['riskScoringRoutesEnabled'] } }, + tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS], + }, () => { before(() => { cleanKibana(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts new file mode 100644 index 0000000000000..3e29f3a08cb70 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/endpoint_exceptions.cy.ts @@ -0,0 +1,127 @@ +/* + * 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 { tag } from '../../../tags'; + +import { deleteAlertsAndRules } from '../../../tasks/common'; +import { + expandFirstAlert, + goToClosedAlertsOnRuleDetailsPage, + openAddEndpointExceptionFromAlertActionButton, + openAddEndpointExceptionFromFirstAlert, + waitForAlerts, +} from '../../../tasks/alerts'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; +import { getEndpointRule } from '../../../objects/rule'; +import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; +import { createRule } from '../../../tasks/api_calls/rules'; +import { + waitForAlertsToPopulate, + waitForTheRuleToBeExecuted, +} from '../../../tasks/create_new_rule'; +import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; +import { + addExceptionEntryFieldValueAndSelectSuggestion, + addExceptionEntryFieldValueValue, + addExceptionFlyoutItemName, + editExceptionFlyoutItemName, + selectCloseSingleAlerts, + submitNewExceptionItem, + validateExceptionConditionField, +} from '../../../tasks/exceptions'; +import { ALERTS_COUNT } from '../../../screens/alerts'; +import { + ADD_AND_BTN, + EXCEPTION_CARD_ITEM_CONDITIONS, + EXCEPTION_CARD_ITEM_NAME, + EXCEPTION_ITEM_VIEWER_CONTAINER, +} from '../../../screens/exceptions'; +import { goToEndpointExceptionsTab } from '../../../tasks/rule_details'; + +describe( + 'Endpoint Exceptions workflows from Alert', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + const ITEM_NAME = 'Sample Exception List Item'; + const ITEM_NAME_EDIT = 'Sample Exception List Item'; + const ADDITIONAL_ENTRY = 'host.hostname'; + + beforeEach(() => { + cy.task('esArchiverUnload', 'endpoint'); + cy.task('esArchiverResetKibana'); + login(); + deleteAlertsAndRules(); + cy.task('esArchiverLoad', 'endpoint'); + createRule(getEndpointRule()); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + goToRuleDetails(); + waitForTheRuleToBeExecuted(); + waitForAlertsToPopulate(); + }); + + after(() => { + cy.task('esArchiverUnload', 'endpoint'); + }); + + it('Should be able to create and close single Endpoint exception from overflow menu', () => { + // The Endpoint will populated with predefined fields + openAddEndpointExceptionFromFirstAlert(); + + // As the endpoint.alerts-* is used to trigger the alert the + // file.Ext.code_signature will be auto-populated + validateExceptionConditionField('file.Ext.code_signature'); + + selectCloseSingleAlerts(); + addExceptionFlyoutItemName(ITEM_NAME); + submitNewExceptionItem(); + + // Instead of immediately checking if the Opened Alert has moved to the closed tab, + // use the waitForAlerts method to create a buffer, allowing the alerts some time to + // be moved to the Closed Alert tab. + waitForAlerts(); + + // Closed alert should appear in table + goToClosedAlertsOnRuleDetailsPage(); + cy.get(ALERTS_COUNT).should('exist'); + }); + + it('Should be able to create Endpoint exception from Alerts take action button, and change multiple exception items without resetting to initial auto-prefilled entries', () => { + // Open first Alert Summary + expandFirstAlert(); + + // The Endpoint should populated with predefined fields + openAddEndpointExceptionFromAlertActionButton(); + + // As the endpoint.alerts-* is used to trigger the alert the + // file.Ext.code_signature will be auto-populated + validateExceptionConditionField('file.Ext.code_signature'); + addExceptionFlyoutItemName(ITEM_NAME); + + cy.get(ADD_AND_BTN).click(); + // edit conditions + addExceptionEntryFieldValueAndSelectSuggestion(ADDITIONAL_ENTRY, 6); + addExceptionEntryFieldValueValue('foo', 4); + + // Change the name again + editExceptionFlyoutItemName(ITEM_NAME_EDIT); + + // validate the condition is still "agent.name" or got rest after the name is changed + validateExceptionConditionField(ADDITIONAL_ENTRY); + + selectCloseSingleAlerts(); + submitNewExceptionItem(); + + // Endpoint Exception will move to Endpoint List under Exception tab of rule + goToEndpointExceptionsTab(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', ADDITIONAL_ENTRY); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts new file mode 100644 index 0000000000000..6a7df890aec06 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/auto_populate_with_alert_data.cy.ts @@ -0,0 +1,198 @@ +/* + * 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 { tag } from '../../../../tags'; +import { LOADING_INDICATOR } from '../../../../screens/security_header'; +import { getEndpointRule } from '../../../../objects/rule'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { goToRuleDetails } from '../../../../tasks/alerts_detection_rules'; +import { + addExceptionFromFirstAlert, + expandFirstAlert, + openAddRuleExceptionFromAlertActionButton, +} from '../../../../tasks/alerts'; +import { + addExceptionEntryFieldValue, + addExceptionEntryFieldValueValue, + addExceptionFlyoutItemName, + submitNewExceptionItem, + validateExceptionConditionField, + validateExceptionCommentCountAndText, + editExceptionFlyoutItemName, + validateHighlightedFieldsPopulatedAsExceptionConditions, + validateEmptyExceptionConditionField, +} from '../../../../tasks/exceptions'; +import { login, visitWithoutDateRange } from '../../../../tasks/login'; +import { goToExceptionsTab } from '../../../../tasks/rule_details'; + +import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation'; +import { deleteAlertsAndRules } from '../../../../tasks/common'; +import { + ADD_AND_BTN, + ENTRY_DELETE_BTN, + EXCEPTION_CARD_ITEM_CONDITIONS, + EXCEPTION_CARD_ITEM_NAME, + EXCEPTION_ITEM_VIEWER_CONTAINER, +} from '../../../../screens/exceptions'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; + +describe( + 'Auto populate exception with Alert data', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + const ITEM_NAME = 'Sample Exception Item'; + const ITEM_NAME_EDIT = 'Sample Exception Item Edit'; + const ADDITIONAL_ENTRY = 'host.hostname'; + + beforeEach(() => { + cy.task('esArchiverUnload', 'endpoint'); + cy.task('esArchiverResetKibana'); + cy.task('esArchiverLoad', 'endpoint'); + login(); + createRule(getEndpointRule()); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + goToRuleDetails(); + waitForAlertsToPopulate(); + }); + after(() => { + cy.task('esArchiverUnload', 'endpoint'); + deleteAlertsAndRules(); + }); + afterEach(() => { + cy.task('esArchiverUnload', 'endpoint'); + }); + + it('Should create a Rule exception item from alert actions overflow menu and auto populate the conditions using alert Highlighted fields', () => { + cy.get(LOADING_INDICATOR).should('not.exist'); + addExceptionFromFirstAlert(); + + const highlightedFieldsBasedOnAlertDoc = [ + 'host.name', + 'agent.id', + 'user.name', + 'process.executable', + 'file.path', + ]; + + /** + * Validate the highlighted fields are auto populated, these + * fields are based on the alert document that should be generated + * when the endpoint rule runs + */ + validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc); + + /** + * Validate that the comments are opened by default with one comment added + * showing a text contains information about the pre-filled conditions + */ + validateExceptionCommentCountAndText( + 1, + 'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):' + ); + + addExceptionFlyoutItemName(ITEM_NAME); + submitNewExceptionItem(); + }); + it('Should create a Rule exception from Alerts take action button and change multiple exception items without resetting to initial auto-prefilled entries', () => { + cy.get(LOADING_INDICATOR).should('not.exist'); + + // Open first Alert Summary + expandFirstAlert(); + + // The Rule exception should populated with highlighted fields + openAddRuleExceptionFromAlertActionButton(); + + const highlightedFieldsBasedOnAlertDoc = [ + 'host.name', + 'agent.id', + 'user.name', + 'process.executable', + 'file.path', + ]; + + /** + * Validate the highlighted fields are auto populated, these + * fields are based on the alert document that should be generated + * when the endpoint rule runs + */ + validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc); + + /** + * Validate that the comments are opened by default with one comment added + * showing a text contains information about the pre-filled conditions + */ + validateExceptionCommentCountAndText( + 1, + 'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):' + ); + + addExceptionFlyoutItemName(ITEM_NAME); + + cy.get(ADD_AND_BTN).click(); + + // edit conditions + addExceptionEntryFieldValue(ADDITIONAL_ENTRY, 5); + addExceptionEntryFieldValueValue('foo', 5); + + // Change the name again + editExceptionFlyoutItemName(ITEM_NAME_EDIT); + + // validate the condition is still 'host.hostname' or got rest after the name is changed + validateExceptionConditionField(ADDITIONAL_ENTRY); + + submitNewExceptionItem(); + + goToExceptionsTab(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', 'host.hostname'); + }); + it('Should delete all prefilled exception entries when creating a Rule exception from Alerts take action button without resetting to initial auto-prefilled entries', () => { + cy.get(LOADING_INDICATOR).should('not.exist'); + + // Open first Alert Summary + expandFirstAlert(); + + // The Rule exception should populated with highlighted fields + openAddRuleExceptionFromAlertActionButton(); + + const highlightedFieldsBasedOnAlertDoc = [ + 'host.name', + 'agent.id', + 'user.name', + 'process.executable', + 'file.path', + ]; + + /** + * Validate the highlighted fields are auto populated, these + * fields are based on the alert document that should be generated + * when the endpoint rule runs + */ + validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc); + + /** + * Delete all the highlighted fields to see if any condition + * will prefuilled again. + */ + const highlightedFieldsCount = highlightedFieldsBasedOnAlertDoc.length - 1; + highlightedFieldsBasedOnAlertDoc.forEach((_, index) => + cy + .get(ENTRY_DELETE_BTN) + .eq(highlightedFieldsCount - index) + .click() + ); + + /** + * Validate that there are no highlighted fields are auto populated + * after the deletion + */ + validateEmptyExceptionConditionField(); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/alerts_table_flow/rule_exceptions/closing_all_matching_alerts.cy.ts diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/flyout_validation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/flyout_validation.cy.ts similarity index 99% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/flyout_validation.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/flyout_validation.cy.ts index a6f52c4d39d90..92b63e1eb9137 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/flyout_validation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/flyout_validation.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; @@ -65,7 +66,7 @@ import { getExceptionList } from '../../../objects/exception'; // to test in enzyme and very small changes can inadvertently add // bugs. As the complexity within the builder grows, these should // ensure the most basic logic holds. -describe.skip('Exceptions flyout', { testIsolation: false }, () => { +describe.skip('Exceptions flyout', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cy.task('esArchiverResetKibana'); // this is a made-up index that has just the necessary diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts index d417673ea8e31..424bc9dfd5505 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/multiple_conditions.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; @@ -30,7 +31,7 @@ import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; describe( 'Add multiple conditions and validate the generated exceptions', - { testIsolation: false }, + { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { cy.task('esArchiverResetKibana'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/use_value_list.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/use_value_list.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/use_value_list.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/use_value_list.cy.ts index efde240ebb70b..381024e413794 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/entry/use_value_list.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/use_value_list.cy.ts @@ -4,6 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; + import { addExceptionEntryFieldMatchIncludedValue, addExceptionEntryFieldValue, @@ -49,7 +51,7 @@ const goToRulesAndOpenValueListModal = () => { openValueListsModal(); }; -describe('Use Value list in exception entry', () => { +describe('Use Value list in exception entry', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts index be3fa9bdce58b..4f523c9fe0290 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; @@ -44,7 +45,7 @@ import { } from '../../../screens/exceptions'; import { createEndpointExceptionList } from '../../../tasks/api_calls/exceptions'; -describe('Add endpoint exception from rule details', () => { +describe('Add endpoint exception from rule details', { tags: [tag.ESS, tag.SERVERLESS] }, () => { const ITEM_NAME = 'Sample Exception List Item'; before(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts index ebf396ce7dbe1..fc91468b88c56 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getException, getExceptionList } from '../../../objects/exception'; import { getNewRule } from '../../../objects/rule'; @@ -59,7 +60,7 @@ import { } from '../../../tasks/api_calls/exceptions'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; -describe('Add/edit exception from rule details', () => { +describe('Add/edit exception from rule details', { tags: [tag.ESS, tag.SERVERLESS] }, () => { const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; const ITEM_FIELD = 'unique_value.test'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts new file mode 100644 index 0000000000000..1d020462683da --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts @@ -0,0 +1,183 @@ +/* + * 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 { tag } from '../../../tags'; + +import { getNewRule } from '../../../objects/rule'; +import { ALERTS_COUNT, EMPTY_ALERT_TABLE } from '../../../screens/alerts'; +import { createRule } from '../../../tasks/api_calls/rules'; +import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; +import { + goToClosedAlertsOnRuleDetailsPage, + goToOpenedAlertsOnRuleDetailsPage, +} from '../../../tasks/alerts'; +import { + editException, + editExceptionFlyoutItemName, + submitEditedExceptionItem, +} from '../../../tasks/exceptions'; +import { login, visitWithoutDateRange } from '../../../tasks/login'; +import { + addFirstExceptionFromRuleDetails, + goToAlertsTab, + goToExceptionsTab, + openEditException, + removeException, + waitForTheRuleToBeExecuted, +} from '../../../tasks/rule_details'; + +import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; +import { postDataView, deleteAlertsAndRules } from '../../../tasks/common'; +import { + NO_EXCEPTIONS_EXIST_PROMPT, + EXCEPTION_ITEM_VIEWER_CONTAINER, + EXCEPTION_CARD_ITEM_NAME, + EXCEPTION_CARD_ITEM_CONDITIONS, + EXCEPTION_ITEM_CONTAINER, + VALUES_INPUT, + FIELD_INPUT_PARENT, +} from '../../../screens/exceptions'; +import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; + +describe( + 'Add exception using data views from rule details', + { tags: [tag.ESS, tag.SERVERLESS] }, + () => { + const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert'; + const ITEM_NAME = 'Sample Exception List Item'; + + before(() => { + cy.task('esArchiverResetKibana'); + cy.task('esArchiverLoad', 'exceptions'); + login(); + postDataView('exceptions-*'); + }); + + after(() => { + cy.task('esArchiverUnload', 'exceptions'); + }); + + beforeEach(() => { + deleteAlertsAndRules(); + createRule( + getNewRule({ + query: 'agent.name:*', + data_view_id: 'exceptions-*', + interval: '10s', + rule_id: 'rule_testing', + }) + ); + login(); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + goToRuleDetails(); + waitForAlertsToPopulate(); + }); + + afterEach(() => { + cy.task('esArchiverUnload', 'exceptions_2'); + }); + + it('Creates an exception item and close all matching alerts', () => { + goToExceptionsTab(); + // when no exceptions exist, empty component shows with action to add exception + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); + + // clicks prompt button to add first exception that will also select to close + // all matching alerts + addFirstExceptionFromRuleDetails( + { + field: 'agent.name', + operator: 'is', + values: ['foo'], + }, + ITEM_NAME + ); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // Alerts table should now be empty from having added exception and closed + // matching alert + goToAlertsTab(); + cy.get(EMPTY_ALERT_TABLE).should('exist'); + + // Closed alert should appear in table + goToClosedAlertsOnRuleDetailsPage(); + cy.get(ALERTS_COUNT).should('exist'); + cy.get(ALERTS_COUNT).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`); + + // Remove the exception and load an event that would have matched that exception + // to show that said exception now starts to show up again + goToExceptionsTab(); + + // when removing exception and again, no more exist, empty screen shows again + removeException(); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist'); + + // load more docs + cy.task('esArchiverLoad', 'exceptions_2'); + + // now that there are no more exceptions, the docs should match and populate alerts + goToAlertsTab(); + goToOpenedAlertsOnRuleDetailsPage(); + waitForTheRuleToBeExecuted(); + waitForAlertsToPopulate(); + + cy.get(ALERTS_COUNT).should('exist'); + cy.get(ALERTS_COUNT).should('have.text', '2 alerts'); + }); + + it('Edits an exception item', () => { + const NEW_ITEM_NAME = 'Exception item-EDITED'; + const ITEM_FIELD = 'unique_value.test'; + const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name'; + + goToExceptionsTab(); + // add item to edit + addFirstExceptionFromRuleDetails( + { + field: ITEM_FIELD, + operator: 'is', + values: ['foo'], + }, + ITEM_NAME + ); + + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' unique_value.testIS foo'); + + // open edit exception modal + openEditException(); + + // edit exception item name + editExceptionFlyoutItemName(NEW_ITEM_NAME); + + // check that the existing item's field is being populated + cy.get(EXCEPTION_ITEM_CONTAINER) + .eq(0) + .find(FIELD_INPUT_PARENT) + .eq(0) + .should('have.text', ITEM_FIELD); + cy.get(VALUES_INPUT).should('have.text', 'foo'); + + // edit conditions + editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); + + // submit + submitEditedExceptionItem(); + + // new exception item displays + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + + // check that updates stuck + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.nameIS foo'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts index 6464b782ae675..0e0aaeea06ddc 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/read_only_view.cy.ts @@ -4,10 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../tags'; import { getExceptionList } from '../../../objects/exception'; import { getNewRule } from '../../../objects/rule'; -import { ROLES } from '../../../../common/test'; import { createRule } from '../../../tasks/api_calls/rules'; import { login, visitWithoutDateRange } from '../../../tasks/login'; import { goToExceptionsTab, goToAlertsTab } from '../../../tasks/rule_details'; @@ -27,7 +28,7 @@ import { deleteExceptionList, } from '../../../tasks/api_calls/exceptions'; -describe('Exceptions viewer read only', () => { +describe('Exceptions viewer read only', { tags: tag.ESS }, () => { const exceptionList = getExceptionList(); before(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts index bb7c17cab612b..dca4ee9d805f0 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { getExceptionList } from '../../../../objects/exception'; import { getNewRule } from '../../../../objects/rule'; @@ -40,7 +41,7 @@ const getExceptionList1 = () => ({ const EXCEPTION_LIST_NAME = 'Newly created list'; -describe('Exception list detail page', () => { +describe('Exception list detail page', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cy.task('esArchiverResetKibana'); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts index 5782534470930..9a56d20d244de 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; import { login, visitWithoutDateRange } from '../../../tasks/login'; @@ -38,7 +39,7 @@ import { waitForExceptionsTableToBeLoaded, } from '../../../tasks/exceptions_table'; -describe('Add, edit and delete exception', () => { +describe('Add, edit and delete exception', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cy.task('esArchiverResetKibana'); cy.task('esArchiverLoad', 'exceptions'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts index b47816f7ed693..3f73aaf88a01e 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { createRule } from '../../../../tasks/api_calls/rules'; import { getExceptionList } from '../../../../objects/exception'; @@ -40,7 +41,7 @@ const getExceptionList2 = () => ({ list_id: 'exception_list_2', }); -describe('Duplicate List', () => { +describe('Duplicate List', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { cy.task('esArchiverResetKibana'); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/filter_table.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/filter_table.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/filter_table.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/filter_table.cy.ts index a8815ab8219bb..52e7386032608 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/filter_table.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/filter_table.cy.ts @@ -4,6 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; + import { getExceptionList } from '../../../../objects/exception'; import { getNewRule } from '../../../../objects/rule'; import { @@ -34,7 +36,7 @@ const getExceptionList2 = () => ({ name: EXCEPTION_LIST_NAME_TWO, list_id: 'exception_list_2', }); -describe('Filter Lists', () => { +describe('Filter Lists', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { cy.task('esArchiverResetKibana'); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts index 8e07fc219f8d3..d453b2f89edbe 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { IMPORT_SHARED_EXCEPTION_LISTS_CLOSE_BTN, @@ -20,7 +21,7 @@ import { import { login, visitWithoutDateRange } from '../../../../tasks/login'; import { EXCEPTIONS_URL } from '../../../../urls/navigation'; -describe('Import Lists', () => { +describe('Import Lists', { tags: [tag.ESS, tag.SERVERLESS] }, () => { const LIST_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_exception_list.ndjson'; before(() => { cy.task('esArchiverResetKibana'); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts new file mode 100644 index 0000000000000..a1f3e9eb96faf --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/manage_lists.cy.ts @@ -0,0 +1,146 @@ +/* + * 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 { tag } from '../../../../tags'; + +import { getExceptionList, expectedExportedExceptionList } from '../../../../objects/exception'; +import { getNewRule } from '../../../../objects/rule'; + +import { createRule } from '../../../../tasks/api_calls/rules'; +import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../../../tasks/login'; + +import { EXCEPTIONS_URL } from '../../../../urls/navigation'; +import { + deleteExceptionListWithoutRuleReferenceByListId, + deleteExceptionListWithRuleReferenceByListId, + exportExceptionList, + waitForExceptionsTableToBeLoaded, + createSharedExceptionList, + linkRulesToExceptionList, + assertNumberLinkedRules, +} from '../../../../tasks/exceptions_table'; +import { + EXCEPTIONS_LIST_MANAGEMENT_NAME, + EXCEPTIONS_TABLE_SHOWING_LISTS, +} from '../../../../screens/exceptions'; +import { createExceptionList } from '../../../../tasks/api_calls/exceptions'; + +import { TOASTER } from '../../../../screens/alerts_detection_rules'; + +const EXCEPTION_LIST_NAME = 'My test list'; +const EXCEPTION_LIST_TO_DUPLICATE_NAME = 'A test list 2'; + +const getExceptionList1 = () => ({ + ...getExceptionList(), + name: EXCEPTION_LIST_NAME, + list_id: 'exception_list_1', +}); + +const getExceptionList2 = () => ({ + ...getExceptionList(), + name: EXCEPTION_LIST_TO_DUPLICATE_NAME, + list_id: 'exception_list_2', +}); + +describe( + 'Manage lists from "Shared Exception Lists" page', + { tags: [tag.ESS, tag.SERVERLESS] }, + () => { + describe('Create/Export/Delete List', () => { + before(() => { + createRule(getNewRule({ name: 'Another rule' })); + + // Create exception list associated with a rule + createExceptionList(getExceptionList2(), getExceptionList2().list_id).then((response) => + createRule( + getNewRule({ + exceptions_list: [ + { + id: response.body.id, + list_id: getExceptionList2().list_id, + type: getExceptionList2().type, + namespace_type: getExceptionList2().namespace_type, + }, + ], + }) + ) + ); + + // Create exception list not used by any rules + createExceptionList(getExceptionList1(), getExceptionList1().list_id).as( + 'exceptionListResponse' + ); + }); + + beforeEach(() => { + login(); + visitWithoutDateRange(EXCEPTIONS_URL); + waitForExceptionsTableToBeLoaded(); + }); + + it('Export exception list', function () { + cy.intercept(/(\/api\/exception_lists\/_export)/).as('export'); + + exportExceptionList(getExceptionList1().list_id); + + cy.wait('@export').then(({ response }) => { + cy.wrap(response?.body).should( + 'eql', + expectedExportedExceptionList(this.exceptionListResponse) + ); + + cy.get(TOASTER).should( + 'have.text', + `Exception list "${EXCEPTION_LIST_NAME}" exported successfully` + ); + }); + }); + + it('Link rules to shared exception list', function () { + assertNumberLinkedRules(getExceptionList2().list_id, '1'); + linkRulesToExceptionList(getExceptionList2().list_id, 1); + assertNumberLinkedRules(getExceptionList2().list_id, '2'); + }); + + it('Create exception list', function () { + createSharedExceptionList( + { name: 'Newly created list', description: 'This is my list.' }, + true + ); + + // After creation - directed to list detail page + cy.get(EXCEPTIONS_LIST_MANAGEMENT_NAME).should('have.text', 'Newly created list'); + }); + + it('Delete exception list without rule reference', () => { + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '4'); + + deleteExceptionListWithoutRuleReferenceByListId(getExceptionList1().list_id); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); + }); + + it('Deletes exception list with rule reference', () => { + waitForPageWithoutDateRange(EXCEPTIONS_URL); + waitForExceptionsTableToBeLoaded(); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3'); + + deleteExceptionListWithRuleReferenceByListId(getExceptionList2().list_id); + + // Using cy.contains because we do not care about the exact text, + // just checking number of lists shown + cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2'); + }); + }); + } +); diff --git a/x-pack/plugins/security_solution/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 similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/read_only.cy.ts index c86660a93f512..25b9d2e34fe2e 100644 --- a/x-pack/plugins/security_solution/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 @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../../tags'; -import { ROLES } from '../../../../../common/test'; import { getExceptionList } from '../../../../objects/exception'; import { EXCEPTIONS_OVERFLOW_ACTIONS_BTN, @@ -22,7 +23,7 @@ import { EXCEPTIONS_URL } from '../../../../urls/navigation'; const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges'; -describe('Shared exception lists - read only', () => { +describe('Shared exception lists - read only', { tags: tag.ESS }, () => { before(() => { cy.task('esArchiverResetKibana'); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts similarity index 88% rename from x-pack/plugins/security_solution/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts index a567befcb5b3b..a60c45c0add28 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_alert_to_case.cy.ts @@ -4,9 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; -import { ROLES } from '../../../../common/test'; import { expandFirstAlertActions } from '../../../tasks/alerts'; import { createRule } from '../../../tasks/api_calls/rules'; @@ -34,7 +35,7 @@ describe('Alerts timeline', () => { waitForAlertsToPopulate(); }); - context('Privileges: read only', () => { + context('Privileges: read only', { tags: tag.ESS }, () => { beforeEach(() => { loadDetectionsPage(ROLES.reader); }); @@ -52,10 +53,10 @@ describe('Alerts timeline', () => { }); }); - context('Privileges: can crud', () => { + context('Privileges: can crud', { tags: tag.ESS }, () => { beforeEach(() => { loadDetectionsPage(ROLES.platform_engineer); - cy.get(LOADING_INDICATOR).should('not.exist'); // on CI, waitForPageToBeLoaded fails because the loading icon can't be found + cy.get(LOADING_INDICATOR).should('not.exist'); }); it('should allow a user with crud privileges to attach alerts to cases', () => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/attach_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_timeline.cy.ts similarity index 77% rename from x-pack/plugins/security_solution/cypress/e2e/explore/cases/attach_timeline.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_timeline.cy.ts index 85713b7acae49..669d73fc597a9 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/attach_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/attach_timeline.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { login, visitTimeline } from '../../../tasks/login'; import { @@ -19,7 +20,7 @@ import { createTimeline } from '../../../tasks/api_calls/timelines'; import { cleanKibana, deleteTimelines } from '../../../tasks/common'; import { createCase } from '../../../tasks/api_calls/cases'; -describe('attach timeline to case', () => { +describe('attach timeline to case', { tags: [tag.ESS, tag.SERVERLESS] }, () => { context('without cases created', () => { before(() => { cleanKibana(); @@ -33,7 +34,7 @@ describe('attach timeline to case', () => { }); }); - it('attach timeline to a new case', function () { + it('attach timeline to a new case', { tags: tag.BROKEN_IN_SERVERLESS }, function () { visitTimeline(this.myTimeline.savedObjectId); attachTimelineToNewCase(); @@ -45,21 +46,25 @@ describe('attach timeline to case', () => { }); }); - it('attach timeline to an existing case with no case', function () { - visitTimeline(this.myTimeline.savedObjectId); - attachTimelineToExistingCase(); - addNewCase(); + it( + 'attach timeline to an existing case with no case', + { tags: tag.BROKEN_IN_SERVERLESS }, + function () { + visitTimeline(this.myTimeline.savedObjectId); + attachTimelineToExistingCase(); + addNewCase(); - cy.location('origin').then((origin) => { - cy.get(DESCRIPTION_INPUT).should( - 'have.text', - `[${this.myTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${this.myTimeline.savedObjectId}%27,isOpen:!t))` - ); - }); - }); + cy.location('origin').then((origin) => { + cy.get(DESCRIPTION_INPUT).should( + 'have.text', + `[${this.myTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${this.myTimeline.savedObjectId}%27,isOpen:!t))` + ); + }); + } + ); }); - context('with cases created', () => { + context('with cases created', { tags: tag.BROKEN_IN_SERVERLESS }, () => { before(() => { login(); deleteTimelines(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/connector_options.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connector_options.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/explore/cases/connector_options.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connector_options.cy.ts index b70f559bfbda0..0b4b0372b2f2f 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/connector_options.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connector_options.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { login, visitWithoutDateRange } from '../../../tasks/login'; import { @@ -28,7 +29,7 @@ import { CASES_URL } from '../../../urls/navigation'; import { CONNECTOR_CARD_DETAILS, CONNECTOR_TITLE } from '../../../screens/case_details'; import { cleanKibana } from '../../../tasks/common'; -describe('Cases connector incident fields', () => { +describe('Cases connector incident fields', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/connectors.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connectors.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/explore/cases/connectors.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connectors.cy.ts index b3cb9551cf2c8..2789b72b09acf 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/connectors.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/connectors.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getServiceNowConnector, getServiceNowITSMHealthResponse } from '../../../objects/case'; @@ -20,7 +21,7 @@ import { login, visitWithoutDateRange } from '../../../tasks/login'; import { CASES_URL } from '../../../urls/navigation'; -describe('Cases connectors', () => { +describe('Cases connectors', { tags: [tag.ESS, tag.SERVERLESS] }, () => { const configureResult = { connector: { id: 'e271c3b8-f702-4fbc-98e0-db942b573bbd', diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/explore/cases/creation.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts index 33bbd68ac9cb0..868c80a7b743f 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/creation.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import type { TestCase } from '../../../objects/case'; import { getCase1 } from '../../../objects/case'; @@ -53,7 +54,7 @@ import { loginWithUser, visit, visitWithoutDateRange } from '../../../tasks/logi import { CASES_URL, OVERVIEW_URL } from '../../../urls/navigation'; -describe('Cases', () => { +describe('Cases', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); createTimeline(getCase1().timeline).then((response) => @@ -86,8 +87,8 @@ describe('Cases', () => { cy.get(ALL_CASES_OPEN_CASES_COUNT).should('have.text', 'Open (1)'); cy.get(ALL_CASES_TAGS_COUNT).should('have.text', 'Tags2'); cy.get(ALL_CASES_NAME).should('have.text', this.mycase.name); - (this.mycase as TestCase).tags.forEach((tag) => { - cy.get(ALL_CASES_TAGS(tag)).should('have.text', tag); + (this.mycase as TestCase).tags.forEach((CaseTag) => { + cy.get(ALL_CASES_TAGS(CaseTag)).should('have.text', CaseTag); }); cy.get(ALL_CASES_COMMENTS_COUNT).should('have.text', '0'); cy.get(ALL_CASES_OPENED_ON).should('include.text', 'ago'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/privileges.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/privileges.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/explore/cases/privileges.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/privileges.cy.ts index ce55e05c6e5e8..fa494a832a634 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/cases/privileges.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/cases/privileges.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import type { TestCaseWithoutTimeline } from '../../../objects/case'; import { ALL_CASES_CREATE_NEW_CASE_BTN, ALL_CASES_NAME } from '../../../screens/all_cases'; @@ -48,7 +49,7 @@ const testCase: TestCaseWithoutTimeline = { owner: 'securitySolution', }; -describe('Cases privileges', () => { +describe('Cases privileges', { tags: tag.ESS }, () => { before(() => { cleanKibana(); createUsersAndRoles(usersToCreate, rolesToCreate); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts index 2761d04ed0f07..d7c7aca013282 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/enable_risk_score.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; import { @@ -32,7 +33,7 @@ import { ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; const spaceId = 'default'; -describe('Enable risk scores', () => { +describe('Enable risk scores', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/entity_analytics.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/entity_analytics.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts index b261ad0ed5828..14d326febf11a 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/entity_analytics.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts @@ -4,12 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { login, visit } from '../../../tasks/login'; import { ALERTS_URL, ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; -import { cleanKibana, deleteAlertsAndRules, waitForPageToBeLoaded } from '../../../tasks/common'; +import { cleanKibana, deleteAlertsAndRules } from '../../../tasks/common'; import { ANOMALIES_TABLE, @@ -55,7 +56,7 @@ const SIEM_KIBANA_HOST_ALERTS = 2; const SIEM_KIBANA_HOST_NAME = 'siem-kibana'; const END_DATE = 'Jan 19, 2019 @ 20:33:29.186'; -describe('Entity Analytics Dashboard', () => { +describe('Entity Analytics Dashboard', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); }); @@ -307,7 +308,6 @@ describe('Entity Analytics Dashboard', () => { cy.task('esArchiverLoad', 'network'); login(); visit(ENTITY_ANALYTICS_URL); - waitForPageToBeLoaded(); cy.get(ANOMALIES_TABLE).should('be.visible'); waitForAnomaliesToBeLoaded(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts index 636f6e0bdb988..de6d2ad295b58 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; import { @@ -38,7 +39,7 @@ import { ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; const spaceId = 'default'; -describe('Upgrade risk scores', () => { +describe('Upgrade risk scores', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/filters/pinned_filters.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/filters/pinned_filters.cy.ts similarity index 83% rename from x-pack/plugins/security_solution/cypress/e2e/explore/filters/pinned_filters.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/filters/pinned_filters.cy.ts index 96878e7eac2e8..d1c2649d901d3 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/filters/pinned_filters.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/filters/pinned_filters.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { login, visitWithoutDateRange } from '../../../tasks/login'; @@ -22,7 +23,7 @@ import { import { ALERTS_PAGE } from '../../../screens/kibana_navigation'; import { postDataView } from '../../../tasks/common'; -describe('pinned filters', () => { +describe('pinned filters', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { postDataView('audit*'); }); @@ -31,7 +32,7 @@ describe('pinned filters', () => { login(); }); - it('show pinned filters on security', () => { + it('show pinned filters on security', { tags: tag.BROKEN_IN_SERVERLESS }, () => { visitWithoutDateRange(DISCOVER_WITH_PINNED_FILTER_URL); cy.get(GLOBAL_SEARCH_BAR_FILTER_ITEM).find(GLOBAL_SEARCH_BAR_PINNED_FILTER).should('exist'); @@ -41,7 +42,7 @@ describe('pinned filters', () => { cy.get(GLOBAL_SEARCH_BAR_FILTER_ITEM).should('have.text', 'host.name: test-host'); }); - it('does not show discover filters on security', () => { + it('does not show discover filters on security', { tags: tag.BROKEN_IN_SERVERLESS }, () => { visitWithoutDateRange(DISCOVER_WITH_FILTER_URL); cy.get(GLOBAL_SEARCH_BAR_FILTER_ITEM).should('exist'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/guided_onboarding/tour.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/guided_onboarding/tour.cy.ts similarity index 57% rename from x-pack/plugins/security_solution/cypress/e2e/explore/guided_onboarding/tour.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/guided_onboarding/tour.cy.ts index 1c180857c00b9..eaad7fb549bf6 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/guided_onboarding/tour.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/guided_onboarding/tour.cy.ts @@ -4,6 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { AlertsCasesTourSteps } from '@kbn/security-solution-plugin/public/common/components/guided_onboarding_tour/tour_config'; +import { tag } from '../../../tags'; import { disableExpandableFlyout } from '../../../tasks/api_calls/kibana_advanced_settings'; import { navigateFromHeaderTo } from '../../../tasks/security_header'; @@ -26,10 +28,9 @@ import { getNewRule } from '../../../objects/rule'; import { ALERTS_URL, DASHBOARDS_URL } from '../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { login, visit } from '../../../tasks/login'; -import { quitGlobalTour, startAlertsCasesTour } from '../../../tasks/api_calls/tour'; -import { AlertsCasesTourSteps } from '../../../../public/common/components/guided_onboarding_tour/tour_config'; +import { startAlertsCasesTour } from '../../../tasks/api_calls/tour'; -describe('Guided onboarding tour', () => { +describe('Guided onboarding tour', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); login(); @@ -42,9 +43,7 @@ describe('Guided onboarding tour', () => { visit(ALERTS_URL); waitForAlertsToPopulate(); }); - after(() => { - quitGlobalTour(); - }); + it('Completes the tour with next button clicks', () => { startTour(); completeTourWithNextButton(); @@ -71,37 +70,49 @@ describe('Guided onboarding tour', () => { assertTourStepExist(AlertsCasesTourSteps.pointToAlertName); }); - describe('persists tour steps in flyout on flyout toggle', () => { - const stepsInAlertsFlyout = [ - AlertsCasesTourSteps.reviewAlertDetailsFlyout, - AlertsCasesTourSteps.addAlertToCase, - AlertsCasesTourSteps.viewCase, - ]; + describe.skip( + 'persists tour steps in flyout on flyout toggle', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + const stepsInAlertsFlyout = [ + AlertsCasesTourSteps.reviewAlertDetailsFlyout, + AlertsCasesTourSteps.addAlertToCase, + AlertsCasesTourSteps.viewCase, + ]; - const stepsInCasesFlyout = [AlertsCasesTourSteps.createCase, AlertsCasesTourSteps.submitCase]; + const stepsInCasesFlyout = [AlertsCasesTourSteps.createCase, AlertsCasesTourSteps.submitCase]; - stepsInAlertsFlyout.forEach((step) => { - it(`step: ${step}, resets to ${step}`, () => { - startTour(); - goToStep(step); - assertTourStepExist(step); - closeAlertFlyout(); - assertTourStepNotExist(step); - expandFirstAlert(); - assertTourStepExist(step); + stepsInAlertsFlyout.forEach((step) => { + it( + `step: ${step}, resets to ${step}`, + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + startTour(); + goToStep(step); + assertTourStepExist(step); + closeAlertFlyout(); + assertTourStepNotExist(step); + expandFirstAlert(); + assertTourStepExist(step); + } + ); }); - }); - stepsInCasesFlyout.forEach((step) => { - it(`step: ${step}, resets to ${AlertsCasesTourSteps.createCase}`, () => { - startTour(); - goToStep(step); - assertTourStepExist(step); - closeCreateCaseFlyout(); - assertTourStepNotExist(step); - addToCase(); - assertTourStepExist(AlertsCasesTourSteps.createCase); + stepsInCasesFlyout.forEach((step) => { + it( + `step: ${step}, resets to ${AlertsCasesTourSteps.createCase}`, + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + startTour(); + goToStep(step); + assertTourStepExist(step); + closeCreateCaseFlyout(); + assertTourStepNotExist(step); + addToCase(); + assertTourStepExist(AlertsCasesTourSteps.createCase); + } + ); }); - }); - }); + } + ); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/host_details/risk_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/host_details/risk_tab.cy.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/e2e/explore/host_details/risk_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/host_details/risk_tab.cy.ts index 46797adc1a7d8..e6b7d1636de28 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/host_details/risk_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/host_details/risk_tab.cy.ts @@ -4,13 +4,14 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { login, visitHostDetailsPage } from '../../../tasks/login'; import { cleanKibana, waitForTableToLoad } from '../../../tasks/common'; import { TABLE_CELL, TABLE_ROWS } from '../../../screens/alerts_details'; -describe('risk tab', () => { +describe('risk tab', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'risk_hosts'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/hosts/events_viewer.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/explore/hosts/events_viewer.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts index e97dc0722d815..54583bae3042e 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/hosts/events_viewer.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { FIELDS_BROWSER_CHECKBOX, @@ -45,7 +46,7 @@ const defaultHeadersInDefaultEcsCategory = [ { id: 'destination.ip' }, ]; -describe('Events Viewer', () => { +describe('Events Viewer', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cy.task('esArchiverLoad', 'auditbeat_big'); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/hosts/host_risk_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/e2e/explore/hosts/host_risk_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts index a6d1ab1ebdb50..0f6b1823f3388 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/hosts/host_risk_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/host_risk_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { cleanKibana } from '../../../tasks/common'; import { @@ -21,7 +22,7 @@ import { login, visit } from '../../../tasks/login'; import { HOSTS_URL } from '../../../urls/navigation'; import { clearSearchBar, kqlSearch } from '../../../tasks/security_header'; -describe('risk tab', () => { +describe('risk tab', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'risk_hosts'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts similarity index 90% rename from x-pack/plugins/security_solution/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts index 79149b9374789..b38dda89423ac 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/hosts_risk_column.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { login, visit } from '../../../tasks/login'; @@ -12,7 +13,7 @@ import { cleanKibana } from '../../../tasks/common'; import { TABLE_CELL } from '../../../screens/alerts_details'; import { kqlSearch } from '../../../tasks/security_header'; -describe('All hosts table', () => { +describe('All hosts table', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'risk_hosts'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/network/hover_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/network/hover_actions.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/explore/network/hover_actions.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/network/hover_actions.cy.ts index 4859b7e4cd09b..30104b2aa8a88 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/network/hover_actions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/network/hover_actions.cy.ts @@ -4,6 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; + import { TOP_N_CONTAINER } from '../../../screens/network/flows'; import { GLOBAL_SEARCH_BAR_FILTER_ITEM } from '../../../screens/search_bar'; import { DATA_PROVIDERS } from '../../../screens/timeline'; @@ -24,7 +26,7 @@ import { openTimelineUsingToggle } from '../../../tasks/security_main'; const testDomain = 'myTest'; // tracked by https://github.com/elastic/kibana/issues/161874 -describe.skip('Hover actions', () => { +describe.skip('Hover actions', { tags: [tag.ESS, tag.SERVERLESS] }, () => { const onBeforeLoadCallback = (win: Cypress.AUTWindow) => { // avoid cypress being held by windows prompt and timeout cy.stub(win, 'prompt').returns(true); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/network/overflow_items.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/network/overflow_items.cy.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/e2e/explore/network/overflow_items.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/network/overflow_items.cy.ts index 305a80a2cd482..1dc34f50e2b7a 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/network/overflow_items.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/network/overflow_items.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { ADD_TO_TIMELINE, @@ -22,7 +23,7 @@ import { NETWORK_URL } from '../../../urls/navigation'; const testDomainOne = 'myTest'; const testDomainTwo = 'myTest2'; -describe('Overflow items', () => { +describe('Overflow items', { tags: [tag.ESS, tag.SERVERLESS] }, () => { context('Network stats and tables', () => { before(() => { cy.task('esArchiverLoad', 'network'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/overview/overview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/explore/overview/overview.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts index b26cf4759d5f5..b031a73b69e37 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/overview/overview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { HOST_STATS, NETWORK_STATS, OVERVIEW_EMPTY_PAGE } from '../../../screens/overview'; @@ -16,7 +17,7 @@ import { cleanKibana } from '../../../tasks/common'; import { createTimeline, favoriteTimeline } from '../../../tasks/api_calls/timelines'; import { getTimeline } from '../../../objects/timeline'; -describe('Overview Page', () => { +describe('Overview Page', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'overview'); @@ -64,7 +65,7 @@ describe('Overview Page', () => { }); }); -describe('Overview page with no data', () => { +describe('Overview page with no data', { tags: tag.BROKEN_IN_SERVERLESS }, () => { before(() => { cy.task('esArchiverUnload', 'auditbeat'); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/pagination/pagination.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/pagination/pagination.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/explore/pagination/pagination.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/pagination/pagination.cy.ts index a6a0aa98406e1..93a2e2b9d2dbb 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/explore/pagination/pagination.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/pagination/pagination.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { PROCESS_NAME_FIELD, @@ -20,7 +21,7 @@ import { ALL_HOSTS_TABLE } from '../../../screens/hosts/all_hosts'; import { ALL_USERS_TABLE } from '../../../screens/users/all_users'; import { goToTablePage, sortFirstTableColumn } from '../../../tasks/table_pagination'; -describe('Pagination', () => { +describe('Pagination', { tags: [tag.ESS, tag.SERVERLESS] }, () => { describe('Host uncommon processes table)', () => { before(() => { cy.task('esArchiverLoad', 'host_uncommon_processes'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/users/user_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/users/user_details.cy.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/e2e/explore/users/user_details.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/users/user_details.cy.ts diff --git a/x-pack/plugins/security_solution/cypress/e2e/explore/users/users_tabs.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/users/users_tabs.cy.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/e2e/explore/users/users_tabs.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/explore/users/users_tabs.cy.ts diff --git a/x-pack/plugins/security_solution/cypress/e2e/header/navigation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/header/navigation.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/header/navigation.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/header/navigation.cy.ts index ee848736e3279..55321e4027e37 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/header/navigation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/header/navigation.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../tags'; import { CASES, @@ -77,7 +78,7 @@ import { THREAT_INTELLIGENCE_PAGE, } from '../../screens/kibana_navigation'; -describe('top-level navigation common to all pages in the Security app', () => { +describe('top-level navigation common to all pages in the Security app', { tags: tag.ESS }, () => { beforeEach(() => { login(); visit(TIMELINES_URL); @@ -199,7 +200,7 @@ describe('top-level navigation common to all pages in the Security app', () => { }); }); -describe('Kibana navigation to all pages in the Security app ', () => { +describe('Kibana navigation to all pages in the Security app ', { tags: tag.ESS }, () => { beforeEach(() => { login(); visit(KIBANA_HOME); diff --git a/x-pack/plugins/security_solution/cypress/e2e/header/search_bar.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/header/search_bar.cy.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/e2e/header/search_bar.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/header/search_bar.cy.ts index a138849a8a934..aec33676ad60f 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/header/search_bar.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/header/search_bar.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../tags'; import { login, visit } from '../../tasks/login'; import { @@ -22,7 +23,7 @@ import { getHostIpFilter } from '../../objects/filter'; import { HOSTS_URL } from '../../urls/navigation'; import { waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts'; -describe('SearchBar', () => { +describe('SearchBar', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { login(); visit(HOSTS_URL); diff --git a/x-pack/plugins/security_solution/cypress/e2e/inspect/inspect_button.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/inspect/inspect_button.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts index 7b18eeab0a7e9..a71b22ead9f5f 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/inspect/inspect_button.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/inspect/inspect_button.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../tags'; import { INSPECT_BUTTONS_IN_SECURITY, @@ -17,16 +18,12 @@ import { openTableInspectModal, } from '../../tasks/inspect'; import { login, visit } from '../../tasks/login'; -import { - postDataView, - waitForPageToBeLoaded, - waitForWelcomePanelToBeLoaded, -} from '../../tasks/common'; +import { postDataView, waitForWelcomePanelToBeLoaded } from '../../tasks/common'; import { selectDataView } from '../../tasks/sourcerer'; const DATA_VIEW = 'auditbeat-*'; -describe('Inspect Explore pages', () => { +describe('Inspect Explore pages', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cy.task('esArchiverLoad', 'risk_users'); cy.task('esArchiverLoad', 'risk_hosts'); @@ -51,7 +48,6 @@ describe('Inspect Explore pages', () => { visit(url, { onLoad: () => { waitForWelcomePanelToBeLoaded(); - waitForPageToBeLoaded(); selectDataView(DATA_VIEW); }, }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alert_table_action_column.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alert_table_action_column.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alert_table_action_column.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alert_table_action_column.cy.ts index efa04027025f5..9b8babc551503 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alert_table_action_column.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alert_table_action_column.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { OVERLAY_CONTAINER } from '../../../screens/alerts'; import { @@ -15,7 +16,7 @@ import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { login, visit } from '../../../tasks/login'; import { ALERTS_URL } from '../../../urls/navigation'; -describe('Alerts Table Action column', () => { +describe('Alerts Table Action column', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'process_ancestry'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alert_table_controls.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alert_table_controls.cy.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alert_table_controls.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alert_table_controls.cy.ts diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts index 7b80498aad9d7..be84fba1cb9e5 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; import { CELL_COPY_BUTTON, FILTER_BADGE, SHOW_TOP_N_HEADER } from '../../../screens/alerts'; @@ -37,7 +38,7 @@ import { openActiveTimeline } from '../../../tasks/timeline'; import { ALERTS_URL } from '../../../urls/navigation'; -describe('Alerts cell actions', () => { +describe('Alerts cell actions', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); createRule(getNewRule()); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alerts_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alerts_details.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts index 7f5e0cde93b10..0808b79de216e 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/alerts_details.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import type { DataTableModel } from '@kbn/securitysolution-data-table'; +import { tag } from '../../../tags'; import { disableExpandableFlyout } from '../../../tasks/api_calls/kibana_advanced_settings'; import { ALERT_FLYOUT, @@ -35,7 +35,7 @@ import { ALERT_SUMMARY_SEVERITY_DONUT_CHART } from '../../../screens/alerts'; import { getLocalstorageEntryAsObject } from '../../../helpers/common'; import { goToRuleDetails } from '../../../tasks/alerts_detection_rules'; -describe('Alert details flyout', () => { +describe('Alert details flyout', { tags: [tag.ESS, tag.SERVERLESS] }, () => { describe('Basic functions', () => { before(() => { cleanKibana(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts similarity index 50% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts index d0455ad1466bb..d215f88886093 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getBuildingBlockRule } from '../../../objects/rule'; import { OVERVIEW_ALERTS_HISTOGRAM_EMPTY } from '../../../screens/overview'; @@ -22,33 +23,37 @@ import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation'; const EXPECTED_NUMBER_OF_ALERTS = 5; -describe('Alerts generated by building block rules', () => { - before(() => { - cy.task('esArchiverLoad', 'auditbeat_big'); - cleanKibana(); - login(); - }); - beforeEach(() => { - createRule(getBuildingBlockRule()); - }); - after(() => { - cy.task('esArchiverUnload', 'auditbeat_big'); - }); - - it('Alerts should be visible on the Rule Detail page and not visible on the Overview page', () => { - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - goToRuleDetails(); - waitForTheRuleToBeExecuted(); - - // Check that generated events are visible on the Details page - waitForAlertsToPopulate(EXPECTED_NUMBER_OF_ALERTS); - - // Make sure rows are highlighted - cy.get(HIGHLIGHTED_ROWS_IN_TABLE).should('exist'); - - navigateFromHeaderTo(OVERVIEW); - - // Check that generated events are hidden on the Overview page - cy.get(OVERVIEW_ALERTS_HISTOGRAM_EMPTY).should('contain.text', 'No results found'); - }); -}); +describe( + 'Alerts generated by building block rules', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + before(() => { + cy.task('esArchiverLoad', 'auditbeat_big'); + cleanKibana(); + login(); + }); + beforeEach(() => { + createRule(getBuildingBlockRule()); + }); + after(() => { + cy.task('esArchiverUnload', 'auditbeat_big'); + }); + + it('Alerts should be visible on the Rule Detail page and not visible on the Overview page', () => { + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + goToRuleDetails(); + waitForTheRuleToBeExecuted(); + + // Check that generated events are visible on the Details page + waitForAlertsToPopulate(EXPECTED_NUMBER_OF_ALERTS); + + // Make sure rows are highlighted + cy.get(HIGHLIGHTED_ROWS_IN_TABLE).should('exist'); + + navigateFromHeaderTo(OVERVIEW); + + // Check that generated events are hidden on the Overview page + cy.get(OVERVIEW_ALERTS_HISTOGRAM_EMPTY).should('contain.text', 'No results found'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts index 3b65d1ac80bdf..d714226e4021d 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../tags'; -import { ROLES } from '../../../../common/test'; import { getNewRule } from '../../../objects/rule'; import { ALERTS_COUNT, @@ -38,7 +39,7 @@ import { login, visit } from '../../../tasks/login'; import { ALERTS_URL } from '../../../urls/navigation'; -describe('Changing alert status', () => { +describe('Changing alert status', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cy.task('esArchiverLoad', 'auditbeat_big'); cleanKibana(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts index acff1f8acb426..e9ea4d15b6152 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts @@ -4,9 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { encode } from '@kbn/rison'; -import type { FilterItemObj } from '../../../../public/common/components/filter_group/types'; +import type { FilterItemObj } from '@kbn/security-solution-plugin/public/common/components/filter_group/types'; +import { DEFAULT_DETECTION_PAGE_FILTERS } from '@kbn/security-solution-plugin/common/constants'; +import { formatPageFilterSearchParam } from '@kbn/security-solution-plugin/common/utils/format_page_filter_search_param'; +import { tag } from '../../../tags'; + import { getNewRule } from '../../../objects/rule'; import { CONTROL_FRAMES, @@ -24,8 +27,6 @@ import { createRule } from '../../../tasks/api_calls/rules'; import { cleanKibana } from '../../../tasks/common'; import { login, visit } from '../../../tasks/login'; import { ALERTS_URL } from '../../../urls/navigation'; -import { DEFAULT_DETECTION_PAGE_FILTERS } from '../../../../common/constants'; -import { formatPageFilterSearchParam } from '../../../../common/utils/format_page_filter_search_param'; import { closePageFilterPopover, markAcknowledgedFirstAlert, @@ -107,7 +108,7 @@ const assertFilterControlsWithFilterObject = ( }); }; -describe(`Detections : Page Filters`, () => { +describe(`Detections : Page Filters`, { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); createRule(getNewRule({ rule_id: 'custom_rule_filters' })); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/event_rendered_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/event_rendered_view.cy.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/event_rendered_view.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/event_rendered_view.cy.ts diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts similarity index 57% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts index 573286b921d56..a413a3097b3f0 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../../../tags'; + import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON, DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_CONTENT, @@ -24,30 +26,34 @@ import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; -describe('Alert details expandable flyout left panel analyzer graph', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - expandDocumentDetailsExpandableFlyoutLeftSection(); - openGraphAnalyzerTab(); - }); +describe( + 'Alert details expandable flyout left panel analyzer graph', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + expandDocumentDetailsExpandableFlyoutLeftSection(); + openGraphAnalyzerTab(); + }); - it('should display analyzer graph and node list under visualize', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB) - .should('be.visible') - .and('have.text', 'Visualize'); + it('should display analyzer graph and node list under visualize', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB) + .should('be.visible') + .and('have.text', 'Visualize'); - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON) - .should('be.visible') - .and('have.text', 'Analyzer Graph'); + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON) + .should('be.visible') + .and('have.text', 'Analyzer Graph'); - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_CONTENT).should('be.visible'); - cy.get(ANALYZER_NODE).first().should('be.visible'); - }); -}); + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_CONTENT).should('be.visible'); + cy.get(ANALYZER_NODE).first().should('be.visible'); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts new file mode 100644 index 0000000000000..b80e9cdd76646 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_correlations_tab.cy.ts @@ -0,0 +1,93 @@ +/* + * 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 { tag } from '../../../../tags'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { getNewRule } from '../../../../objects/rule'; +import { + CORRELATIONS_ANCESTRY_SECTION, + CORRELATIONS_ANCESTRY_TABLE, + CORRELATIONS_CASES_SECTION, + CORRELATIONS_SESSION_SECTION, + CORRELATIONS_SOURCE_SECTION, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON, +} from '../../../../screens/expandable_flyout/alert_details_left_panel_correlations_tab'; +import { + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP, +} from '../../../../screens/expandable_flyout/alert_details_left_panel'; +import { + expandCorrelationsSection, + openCorrelationsTab, +} from '../../../../tasks/expandable_flyout/alert_details_left_panel_correlations_tab'; +import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; +import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; +import { + createNewCaseFromExpandableFlyout, + expandFirstAlertExpandableFlyout, +} from '../../../../tasks/expandable_flyout/common'; +import { cleanKibana } from '../../../../tasks/common'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { login, visit } from '../../../../tasks/login'; +import { ALERTS_URL } from '../../../../urls/navigation'; + +describe( + 'Expandable flyout left panel correlations', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + expandDocumentDetailsExpandableFlyoutLeftSection(); + createNewCaseFromExpandableFlyout(); + openInsightsTab(); + openCorrelationsTab(); + }); + + it('should render correlations details correctly', () => { + cy.log('link the alert to a new case'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).scrollIntoView(); + + cy.log('should render the Insights header'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB) + .should('be.visible') + .and('have.text', 'Insights'); + + cy.log('should render the inner tab switch'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); + + cy.log('should render correlations tab activator / button'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON) + .should('be.visible') + .and('have.text', 'Correlations'); + + cy.log('should render all the correlations sections'); + + cy.get(CORRELATIONS_ANCESTRY_SECTION) + .should('be.visible') + .and('have.text', '1 alert related by ancestry'); + + cy.get(CORRELATIONS_SOURCE_SECTION) + .should('be.visible') + .and('have.text', '0 alerts related by source event'); + + cy.get(CORRELATIONS_SESSION_SECTION) + .should('be.visible') + .and('have.text', '1 alert related by session'); + + cy.get(CORRELATIONS_CASES_SECTION).should('be.visible').and('have.text', '1 related case'); + + expandCorrelationsSection(CORRELATIONS_ANCESTRY_SECTION); + + cy.get(CORRELATIONS_ANCESTRY_TABLE).should('be.visible'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts similarity index 54% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts index a680f783af336..66433f2c193a3 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON, @@ -25,32 +26,38 @@ import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; -describe('Alert details expandable flyout left panel entities', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - expandDocumentDetailsExpandableFlyoutLeftSection(); - openInsightsTab(); - openEntitiesTab(); - }); +describe( + 'Alert details expandable flyout left panel entities', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + expandDocumentDetailsExpandableFlyoutLeftSection(); + openInsightsTab(); + openEntitiesTab(); + }); - it('should display analyzer graph and node list under Insights Entities', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).should('be.visible').and('have.text', 'Insights'); + it('should display analyzer graph and node list under Insights Entities', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB) + .should('be.visible') + .and('have.text', 'Insights'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON) - .should('be.visible') - .and('have.text', 'Entities'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON) + .should('be.visible') + .and('have.text', 'Entities'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('be.visible'); - }); -}); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('be.visible'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts similarity index 61% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts index 833d591344f57..13bae3fe61d67 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_investigation_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB, @@ -19,23 +20,27 @@ import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; -describe('Alert details expandable flyout left panel investigation', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - expandDocumentDetailsExpandableFlyoutLeftSection(); - openInvestigationTab(); - }); +describe( + 'Alert details expandable flyout left panel investigation', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + expandDocumentDetailsExpandableFlyoutLeftSection(); + openInvestigationTab(); + }); - it('should display investigation guide', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB) - .should('be.visible') - .and('have.text', 'Investigation'); + it('should display investigation guide', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB) + .should('be.visible') + .and('have.text', 'Investigation'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).should('be.visible'); - }); -}); + cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).should('be.visible'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts index ab06e9fea187e..0db69f8471bbb 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { openPrevalenceTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel_prevalence_tab'; import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; @@ -43,7 +44,7 @@ describe('Alert details expandable flyout left panel prevalence', () => { openPrevalenceTab(); }); - it('should display prevalence tab', () => { + it('should display prevalence tab', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).should('be.visible').and('have.text', 'Insights'); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_response_tab.cy.ts diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts similarity index 51% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts index afc3ac1b0b918..190e45a0e5f4a 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON, @@ -22,32 +23,36 @@ import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; -describe('Alert details expandable flyout left panel session view', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - expandDocumentDetailsExpandableFlyoutLeftSection(); - }); +describe( + 'Alert details expandable flyout left panel session view', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + expandDocumentDetailsExpandableFlyoutLeftSection(); + }); - it('should display session view under visualize', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB) - .should('be.visible') - .and('have.text', 'Visualize'); + it('should display session view under visualize', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB) + .should('be.visible') + .and('have.text', 'Visualize'); - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON) - .should('be.visible') - .and('have.text', 'Session View'); + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON) + .should('be.visible') + .and('have.text', 'Session View'); - // TODO ideally we would have a test for the session view component instead - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_ERROR) - .should('be.visible') - .and('contain.text', 'Unable to display session view') - .and('contain.text', 'There was an error displaying session view'); - }); -}); + // TODO ideally we would have a test for the session view component instead + cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_ERROR) + .should('be.visible') + .and('contain.text', 'Unable to display session view') + .and('contain.text', 'There was an error displaying session view'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts similarity index 60% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts index c5cd168836179..af5504b08ce7b 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { createRule } from '../../../../tasks/api_calls/rules'; import { getNewRule } from '../../../../objects/rule'; @@ -22,28 +23,34 @@ import { } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON } from '../../../../screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab'; -describe('Expandable flyout left panel threat intelligence', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - expandDocumentDetailsExpandableFlyoutLeftSection(); - openInsightsTab(); - openThreatIntelligenceTab(); - }); +describe( + 'Expandable flyout left panel threat intelligence', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + expandDocumentDetailsExpandableFlyoutLeftSection(); + openInsightsTab(); + openThreatIntelligenceTab(); + }); - it('should serialize its state to url', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).should('be.visible').and('have.text', 'Insights'); + it('should serialize its state to url', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB) + .should('be.visible') + .and('have.text', 'Insights'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON) - .should('be.visible') - .and('have.text', 'Threat Intelligence'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON) + .should('be.visible') + .and('have.text', 'Threat Intelligence'); - cy.get(INDICATOR_MATCH_ENRICHMENT_SECTION).should('be.visible'); - }); -}); + cy.get(INDICATOR_MATCH_ENRICHMENT_SECTION).should('be.visible'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts similarity index 53% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts index cc48e4568d908..d22d1894b5325 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel_rule_preview.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; import { @@ -48,49 +49,55 @@ describe('Alert details expandable flyout rule preview panel', () => { }); describe('rule preview', () => { - it('should display rule preview and its sub sections', () => { - cy.log('rule preview panel'); + it( + 'should display rule preview and its sub sections', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + cy.log('rule preview panel'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SECTION).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_HEADER).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_BODY).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SECTION).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_HEADER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_BODY).should('be.visible'); - cy.log('title'); + cy.log('title'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_CREATED_BY).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_UPDATED_BY).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_TITLE).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_CREATED_BY).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_UPDATED_BY).should('be.visible'); - cy.log('about'); + cy.log('about'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_HEADER) - .should('be.visible') - .and('contain.text', 'About'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_CONTENT).should('be.visible'); - toggleRulePreviewAboutSection(); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_HEADER) + .should('be.visible') + .and('contain.text', 'About'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_ABOUT_SECTION_CONTENT).should('be.visible'); + toggleRulePreviewAboutSection(); - cy.log('definition'); + cy.log('definition'); - toggleRulePreviewDefinitionSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_HEADER) - .should('be.visible') - .and('contain.text', 'Definition'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_CONTENT).should('be.visible'); - toggleRulePreviewDefinitionSection(); + toggleRulePreviewDefinitionSection(); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_HEADER) + .should('be.visible') + .and('contain.text', 'Definition'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_DEFINITION_SECTION_CONTENT).should( + 'be.visible' + ); + toggleRulePreviewDefinitionSection(); - cy.log('schedule'); + cy.log('schedule'); - toggleRulePreviewScheduleSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_HEADER) - .should('be.visible') - .and('contain.text', 'Schedule'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_CONTENT).should('be.visible'); - toggleRulePreviewScheduleSection(); + toggleRulePreviewScheduleSection(); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_HEADER) + .should('be.visible') + .and('contain.text', 'Schedule'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SCHEDULE_SECTION_CONTENT).should('be.visible'); + toggleRulePreviewScheduleSection(); - cy.log('footer'); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER).scrollIntoView(); - cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER).should('be.visible'); - }); + cy.log('footer'); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_FOOTER).should('be.visible'); + } + ); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts new file mode 100644 index 0000000000000..612d49f328fef --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts @@ -0,0 +1,239 @@ +/* + * 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 { upperFirst } from 'lodash'; +import { tag } from '../../../../tags'; + +import { + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_CREATE_BUTTON, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_DESCRIPTION_INPUT, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_NAME_INPUT, + EXISTING_CASE_SELECT_BUTTON, + VIEW_CASE_TOASTER_LINK, +} from '../../../../screens/expandable_flyout/common'; +import { + createNewCaseFromCases, + expandFirstAlertExpandableFlyout, + navigateToAlertsPage, + navigateToCasesPage, +} from '../../../../tasks/expandable_flyout/common'; +import { ALERT_CHECKBOX } from '../../../../screens/alerts'; +import { CASE_DETAILS_PAGE_TITLE } from '../../../../screens/case_details'; +import { + DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON, + DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON, + DOCUMENT_DETAILS_FLYOUT_FOOTER, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE, + DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE, + DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY, + DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION, + DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED, + DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND, + DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON, + DOCUMENT_DETAILS_FLYOUT_HEADER_CHAT_BUTTON, + DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE, + DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE, + DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY, + DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE, + DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS, + DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE, + DOCUMENT_DETAILS_FLYOUT_JSON_TAB, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB, + DOCUMENT_DETAILS_FLYOUT_TABLE_TAB, +} from '../../../../screens/expandable_flyout/alert_details_right_panel'; +import { + collapseDocumentDetailsExpandableFlyoutLeftSection, + expandDocumentDetailsExpandableFlyoutLeftSection, + openJsonTab, + openTableTab, + openTakeActionButton, + openTakeActionButtonAndSelectItem, + selectTakeActionItem, +} from '../../../../tasks/expandable_flyout/alert_details_right_panel'; +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'; + +describe( + 'Alert details expandable flyout right panel', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + const rule = getNewRule(); + + beforeEach(() => { + cleanKibana(); + login(); + createRule(rule); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + it('should display header and footer basics', () => { + expandFirstAlertExpandableFlyout(); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('be.visible').and('have.text', rule.name); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_CHAT_BUTTON).should('be.visible'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS).should('be.visible'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE) + .should('be.visible') + .and('have.text', rule.risk_score); + + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE) + .should('be.visible') + .and('have.text', upperFirst(rule.severity)); + + cy.log('Verify all 3 tabs are visible'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB) + .should('be.visible') + .and('have.text', 'Overview'); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB).should('be.visible').and('have.text', 'Table'); + cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB).should('be.visible').and('have.text', 'JSON'); + + cy.log('Verify the expand/collapse button is visible and functionality works'); + + expandDocumentDetailsExpandableFlyoutLeftSection(); + cy.get(DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON) + .should('be.visible') + .and('have.text', 'Collapse details'); + + collapseDocumentDetailsExpandableFlyoutLeftSection(); + cy.get(DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON) + .should('be.visible') + .and('have.text', 'Expand details'); + + cy.log('Verify the take action button is visible on all tabs'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + + openTableTab(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + + openJsonTab(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + }); + + // TODO this will change when add to existing case is improved + // https://github.com/elastic/security-team/issues/6298 + it('should add to existing case', () => { + navigateToCasesPage(); + createNewCaseFromCases(); + + cy.get(CASE_DETAILS_PAGE_TITLE).should('be.visible').and('have.text', 'case'); + navigateToAlertsPage(); + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE); + + cy.get(EXISTING_CASE_SELECT_BUTTON).should('be.visible').contains('Select').click(); + cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case'); + }); + + // TODO this will change when add to new case is improved + // https://github.com/elastic/security-team/issues/6298 + it('should add to new case', () => { + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE); + + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_NAME_INPUT).type('case'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_DESCRIPTION_INPUT).type( + 'case description' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_CREATE_BUTTON).click(); + + cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case'); + }); + + it('should mark as acknowledged', () => { + cy.get(ALERT_CHECKBOX).should('have.length', 2); + + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED); + + // TODO figure out how to verify the toasts pops up + // cy.get(KIBANA_TOAST) + // .should('be.visible') + // .and('have.text', 'Successfully marked 1 alert as acknowledged.'); + cy.get(ALERT_CHECKBOX).should('have.length', 1); + }); + + it('should mark as closed', () => { + cy.get(ALERT_CHECKBOX).should('have.length', 2); + + expandFirstAlertExpandableFlyout(); + openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED); + + // TODO figure out how to verify the toasts pops up + // cy.get(KIBANA_TOAST).should('be.visible').and('have.text', 'Successfully closed 1 alert.'); + cy.get(ALERT_CHECKBOX).should('have.length', 1); + }); + + // these actions are now grouped together as we're not really testing their functionality but just the existence of the option in the dropdown + it('should test other action within take action dropdown', () => { + expandFirstAlertExpandableFlyout(); + + cy.log('should add endpoint exception'); + + // TODO figure out why this option is disabled in Cypress but not running the app locally + // https://github.com/elastic/security-team/issues/6300 + openTakeActionButton(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION).should('be.disabled'); + + cy.log('should add rule exception'); + + // TODO this isn't fully testing the add rule exception yet + // https://github.com/elastic/security-team/issues/6301 + selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON) + .should('be.visible') + .click(); + + // cy.log('should isolate host'); + + // TODO figure out why isolate host isn't showing up in the dropdown + // https://github.com/elastic/security-team/issues/6302 + // openTakeActionButton(); + // cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST).should('be.visible'); + + cy.log('should respond'); + + // TODO this will change when respond is improved + // https://github.com/elastic/security-team/issues/6303 + openTakeActionButton(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND).should('be.disabled'); + + cy.log('should investigate in timeline'); + + selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION) + .first() + .within(() => + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY).should('be.visible') + ); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts similarity index 57% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts index 5a1c9703ae83d..482ffd4a16417 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_json_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { scrollWithinDocumentDetailsExpandableFlyoutRightSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel_json_tab'; import { openJsonTab } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; @@ -16,21 +17,25 @@ import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; -describe('Alert details expandable flyout right panel json tab', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - openJsonTab(); - }); +describe( + 'Alert details expandable flyout right panel json tab', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + openJsonTab(); + }); - it('should display the json component', () => { - // the json component is rendered within a dom element with overflow, so Cypress isn't finding it - // this next line is a hack that vertically scrolls down to ensure Cypress finds it - scrollWithinDocumentDetailsExpandableFlyoutRightSection(0, 7000); - cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT).should('be.visible'); - }); -}); + it('should display the json component', () => { + // the json component is rendered within a dom element with overflow, so Cypress isn't finding it + // this next line is a hack that vertically scrolls down to ensure Cypress finds it + scrollWithinDocumentDetailsExpandableFlyoutRightSection(0, 7000); + cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT).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 new file mode 100644 index 0000000000000..2cdf95746dcfa --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts @@ -0,0 +1,359 @@ +/* + * 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 { tag } from '../../../../tags'; + +import { collapseDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; +import { DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT } from '../../../../screens/expandable_flyout/alert_details_left_panel_investigation_tab'; +import { + createNewCaseFromExpandableFlyout, + expandFirstAlertExpandableFlyout, +} from '../../../../tasks/expandable_flyout/common'; +import { + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_RULE_PREVIEW_BUTTON, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_SECTION_EMPTY_RESPONSE, +} from '../../../../screens/expandable_flyout/alert_details_right_panel_overview_tab'; +import { + navigateToCorrelationsDetails, + clickInvestigationGuideButton, + navigateToPrevalenceDetails, + toggleOverviewTabAboutSection, + toggleOverviewTabInsightsSection, + toggleOverviewTabInvestigationSection, + toggleOverviewTabResponseSection, + toggleOverviewTabVisualizationsSection, +} 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 { + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS, +} from '../../../../screens/expandable_flyout/alert_details_left_panel_entities_tab'; + +describe( + 'Alert details expandable flyout right panel overview tab', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + const rule = getNewRule(); + + beforeEach(() => { + cleanKibana(); + login(); + createRule(rule); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + }); + + describe('about section', () => { + it('should display about section', () => { + cy.log('header and content'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_HEADER) + .should('be.visible') + .and('have.text', 'About'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_CONTENT).should('be.visible'); + + cy.log('description'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE) + .should('be.visible') + .and('contain.text', 'Rule description'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE) + .should('be.visible') + .within(() => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_RULE_PREVIEW_BUTTON) + .should('be.visible') + .and('have.text', 'Rule summary'); + }); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS) + .should('be.visible') + .and('have.text', rule.description); + + cy.log('reason'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE) + .should('be.visible') + .and('have.text', 'Alert reason'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS) + .should('be.visible') + .and('contain.text', rule.name); + + cy.log('mitre attack'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE) + .should('be.visible') + // @ts-ignore + .and('contain.text', rule.threat[0].framework); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS) + .should('be.visible') + // @ts-ignore + .and('contain.text', rule.threat[0].technique[0].name) + // @ts-ignore + .and('contain.text', rule.threat[0].tactic.name); + }); + }); + + describe('visualizations section', () => { + it('should display analyzer and session previews', () => { + toggleOverviewTabAboutSection(); + toggleOverviewTabVisualizationsSection(); + + cy.log('analyzer graph preview'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT).should('be.visible'); + + cy.log('session view preview'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT).should('be.visible'); + }); + }); + + describe('investigation section', () => { + it('should display investigation section', () => { + toggleOverviewTabAboutSection(); + + cy.log('header and content'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_HEADER) + .should('be.visible') + .and('have.text', 'Investigation'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_CONTENT).should( + 'be.visible' + ); + + cy.log('investigation guide button'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON) + .should('be.visible') + .and('have.text', 'Investigation guide'); + + cy.log('should navigate to left Investigation tab'); + + clickInvestigationGuideButton(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).should('be.visible'); + + cy.log('highlighted fields'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE) + .should('be.visible') + .and('have.text', 'Highlighted fields'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS).should( + 'be.visible' + ); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL) + .should('be.visible') + .and('contain.text', 'host.name'); + const hostNameCell = + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('siem-kibana'); + cy.get(hostNameCell).should('be.visible').and('have.text', 'siem-kibana'); + + cy.get(hostNameCell).click(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('be.visible'); + + collapseDocumentDetailsExpandableFlyoutLeftSection(); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL) + .should('be.visible') + .and('contain.text', 'user.name'); + const userNameCell = + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('test'); + cy.get(userNameCell).should('be.visible').and('have.text', 'test'); + + cy.get(userNameCell).click(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('be.visible'); + }); + }); + + describe('insights section', () => { + it('should display entities section', () => { + toggleOverviewTabAboutSection(); + toggleOverviewTabInvestigationSection(); + toggleOverviewTabInsightsSection(); + + cy.log('header and content'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER) + .should('be.visible') + .and('have.text', 'Entities'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_CONTENT).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER).should('be.visible'); + + cy.log('should navigate to left panel Entities tab'); + + // TODO: skipping this section as Cypress can't seem to find the element (though it's in the DOM) + // navigateToEntitiesDetails(); + // cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); + }); + + it('should display threat intelligence section', () => { + toggleOverviewTabAboutSection(); + toggleOverviewTabInvestigationSection(); + toggleOverviewTabInsightsSection(); + + cy.log('header and content'); + + cy.get( + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER + ).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER) + .should('be.visible') + .and('have.text', 'Threat Intelligence'); + cy.get( + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT + ).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT) + .should('be.visible') + .within(() => { + // threat match detected + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) + .eq(0) + .should('be.visible') + .and('have.text', '0 threat match detected'); // TODO work on getting proper IoC data to get proper data here + + // field with threat enrichement + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) + .eq(1) + .should('be.visible') + .and('have.text', '0 field enriched with threat intelligence'); // TODO work on getting proper IoC data to get proper data here + }); + + cy.log('should navigate to left panel Threat Intelligence tab'); + + // TODO: skipping this section as Cypress can't seem to find the element (though it's in the DOM) + // navigateToThreatIntelligenceDetails(); + // cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Threat Intelligence sub tab directly + }); + + // TODO: skipping this due to flakiness + it.skip('should display correlations section', () => { + cy.log('link the alert to a new case'); + + createNewCaseFromExpandableFlyout(); + + toggleOverviewTabAboutSection(); + toggleOverviewTabInvestigationSection(); + toggleOverviewTabInsightsSection(); + + cy.log('header and content'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER) + .should('be.visible') + .and('have.text', 'Correlations'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT) + .should('be.visible') + .within(() => { + // TODO the order in which these appear is not deterministic currently, hence this can cause flakiness + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) + .eq(0) + .should('be.visible') + .and('have.text', '1 alert related by ancestry'); + // cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) + // .eq(2) + // .should('be.visible') + // .and('have.text', '1 alert related by the same source event'); // TODO work on getting proper data to display some same source data here + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) + .eq(2) + .should('be.visible') + .and('have.text', '1 alert related by session'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES) + .eq(1) + .should('be.visible') + .and('have.text', '1 related case'); + }); + + cy.log('should navigate to left panel Correlations tab'); + + navigateToCorrelationsDetails(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Correlations sub tab directly + }); + + // TODO work on getting proper data to make the prevalence section work here + // we need to generate enough data to have at least one field with prevalence + it.skip('should display prevalence section', () => { + toggleOverviewTabAboutSection(); + toggleOverviewTabInvestigationSection(); + toggleOverviewTabInsightsSection(); + + cy.log('header and content'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER) + .should('be.visible') + .and('have.text', 'Prevalence'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT).scrollIntoView(); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT) + .should('be.visible') + .within(() => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES) + .should('be.visible') + .and('have.text', 'is uncommon'); + }); + + cy.log('should navigate to left panel Prevalence tab'); + + navigateToPrevalenceDetails(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Prevalence sub tab directly + }); + }); + + describe('response section', () => { + it('should display empty message', () => { + toggleOverviewTabAboutSection(); + toggleOverviewTabInvestigationSection(); + toggleOverviewTabResponseSection(); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_SECTION_EMPTY_RESPONSE).should( + 'be.visible' + ); + }); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts similarity index 50% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts index ff89e16a02b03..ec6768c5ddc3c 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_table_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { openTableTab } from '../../../../tasks/expandable_flyout/alert_details_right_panel'; import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; @@ -31,48 +32,52 @@ import { getNewRule } from '../../../../objects/rule'; import { ALERTS_URL } from '../../../../urls/navigation'; import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; -describe('Alert details expandable flyout right panel table tab', () => { - beforeEach(() => { - cleanKibana(); - login(); - createRule(getNewRule()); - visit(ALERTS_URL); - waitForAlertsToPopulate(); - expandFirstAlertExpandableFlyout(); - openTableTab(); - }); +describe( + 'Alert details expandable flyout right panel table tab', + { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, + () => { + beforeEach(() => { + cleanKibana(); + login(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandFirstAlertExpandableFlyout(); + openTableTab(); + }); - it('should display and filter the table', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW).should('be.visible'); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ID_ROW).should('be.visible'); - filterTableTabTable('timestamp'); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW).should('be.visible'); - clearFilterTableTabTable(); - }); + it('should display and filter the table', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ID_ROW).should('be.visible'); + filterTableTabTable('timestamp'); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_TIMESTAMP_ROW).should('be.visible'); + clearFilterTableTabTable(); + }); - it('should test cell actions', () => { - cy.log('cell actions filter in'); + it('should test cell actions', () => { + cy.log('cell actions filter in'); - filterInTableTabTable(); - cy.get(FILTER_BADGE).first().should('contain.text', '@timestamp:'); - removeKqlFilter(); + filterInTableTabTable(); + cy.get(FILTER_BADGE).first().should('contain.text', '@timestamp:'); + removeKqlFilter(); - cy.log('cell actions filter out'); + cy.log('cell actions filter out'); - filterOutTableTabTable(); - cy.get(FILTER_BADGE).first().should('contain.text', 'NOT @timestamp:'); - removeKqlFilter(); + filterOutTableTabTable(); + cy.get(FILTER_BADGE).first().should('contain.text', 'NOT @timestamp:'); + removeKqlFilter(); - cy.log('cell actions add to timeline'); + cy.log('cell actions add to timeline'); - addToTimelineTableTabTable(); - openActiveTimeline(); - cy.get(PROVIDER_BADGE).first().should('contain.text', '@timestamp'); - closeTimeline(); + addToTimelineTableTabTable(); + openActiveTimeline(); + cy.get(PROVIDER_BADGE).first().should('contain.text', '@timestamp'); + closeTimeline(); - cy.log('cell actions copy to clipboard'); + cy.log('cell actions copy to clipboard'); - copyToClipboardTableTabTable(); - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_COPY_TO_CLIPBOARD).should('be.visible'); - }); -}); + copyToClipboardTableTabTable(); + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_COPY_TO_CLIPBOARD).should('be.visible'); + }); + } +); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts index e926e93e63301..e61c41234d22b 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_url_sync.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../../tags'; import { getNewRule } from '../../../../objects/rule'; import { cleanKibana } from '../../../../tasks/common'; @@ -15,7 +16,7 @@ import { closeFlyout } from '../../../../tasks/expandable_flyout/alert_details_r import { expandFirstAlertExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; import { DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE } from '../../../../screens/expandable_flyout/alert_details_right_panel'; -describe('Expandable flyout state sync', () => { +describe('Expandable flyout state sync', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { const rule = getNewRule(); beforeEach(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts index 5ef959899178a..f4e2530be4e88 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { disableExpandableFlyout } from '../../../tasks/api_calls/kibana_advanced_settings'; import { getNewRule } from '../../../objects/rule'; @@ -27,7 +28,7 @@ import { } from '../../../screens/alerts_details'; import { verifyInsightCount } from '../../../tasks/alerts_details'; -describe('Investigate in timeline', () => { +describe('Investigate in timeline', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); createRule(getNewRule()); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/navigation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/navigation.cy.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/navigation.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/navigation.cy.ts index 201e31271c170..120ae0130e369 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/navigation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/navigation.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { expandFirstAlert, waitForAlerts } from '../../../tasks/alerts'; import { createRule } from '../../../tasks/api_calls/rules'; @@ -23,7 +24,7 @@ import { OPEN_ALERT_DETAILS_PAGE } from '../../../screens/alerts_details'; // This is skipped as the details page POC will be removed in favor of the expanded alert flyout // https://github.com/elastic/kibana/issues/154477 -describe.skip('Alert Details Page Navigation', () => { +describe.skip('Alert Details Page Navigation', { tags: [tag.ESS, tag.SERVERLESS] }, () => { describe('navigating to alert details page', () => { const rule = getNewRule(); before(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/resolver.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/resolver.cy.ts similarity index 92% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/resolver.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/resolver.cy.ts index 8da8aa484607d..fdb910a12aca0 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/resolver.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/resolver.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { ANALYZER_NODE } from '../../../screens/alerts'; @@ -17,7 +18,7 @@ import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { login, visit } from '../../../tasks/login'; import { ALERTS_URL } from '../../../urls/navigation'; -describe('Analyze events view for alerts', () => { +describe('Analyze events view for alerts', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); createRule(getNewRule()); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts index 5b9d2e6ae133d..d399648842977 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/dasbhoards/detection_response.cy.ts @@ -4,6 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; + import { getNewRule } from '../../../objects/rule'; import { ALERTS_COUNT } from '../../../screens/alerts'; import { @@ -41,7 +43,7 @@ import { ALERTS_URL, DASHBOARDS_URL, DETECTIONS_RESPONSE_URL } from '../../../ur const TEST_USER_NAME = 'test'; const SIEM_KIBANA_HOST_NAME = 'siem-kibana'; -describe('Detection response view', () => { +describe('Detection response view', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); createRule(getNewRule()); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timeline_templates/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/creation.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timeline_templates/creation.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/creation.cy.ts index c2cbf8ecf5d2d..1a07cac483c03 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timeline_templates/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/creation.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getTimeline } from '../../../objects/timeline'; @@ -48,7 +49,7 @@ import { openTimeline, waitForTimelinesPanelToBeLoaded } from '../../../tasks/ti import { TIMELINES_URL } from '../../../urls/navigation'; -describe('Timeline Templates', () => { +describe('Timeline Templates', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timeline_templates/export.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/export.cy.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timeline_templates/export.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/export.cy.ts index bdfbf897d01a1..52efe04b5957b 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timeline_templates/export.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timeline_templates/export.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { exportTimeline } from '../../../tasks/timelines'; import { login, visitWithoutDateRange } from '../../../tasks/login'; @@ -17,7 +18,7 @@ import { createTimelineTemplate } from '../../../tasks/api_calls/timelines'; import { cleanKibana } from '../../../tasks/common'; import { searchByTitle } from '../../../tasks/table_pagination'; -describe('Export timelines', () => { +describe('Export timelines', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/bulk_add_to_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/bulk_add_to_timeline.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/bulk_add_to_timeline.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/bulk_add_to_timeline.cy.ts index c609e885bd31c..6bf2ee2fca787 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/bulk_add_to_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/bulk_add_to_timeline.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getNewRule } from '../../../objects/rule'; import { SELECTED_ALERTS } from '../../../screens/alerts'; @@ -22,7 +23,7 @@ import { openEvents, openSessions } from '../../../tasks/hosts/main'; import { login, visit } from '../../../tasks/login'; import { ALERTS_URL, HOSTS_URL } from '../../../urls/navigation'; -describe('Bulk Investigate in Timeline', () => { +describe('Bulk Investigate in Timeline', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'bulk_process'); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/correlation_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/correlation_tab.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/correlation_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/correlation_tab.cy.ts index f1c53df7ba361..31ed9a15f8394 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/correlation_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/correlation_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { openTimeline } from '../../../tasks/timelines'; import { getTimeline } from '../../../objects/timeline'; @@ -22,7 +23,7 @@ import { TIMELINES_URL } from '../../../urls/navigation'; import { EQL_QUERY_VALIDATION_ERROR } from '../../../screens/create_new_rule'; import { deleteTimelines } from '../../../tasks/common'; -describe('Correlation tab', () => { +describe('Correlation tab', { tags: [tag.ESS, tag.SERVERLESS] }, () => { const eql = 'any where process.name == "zsh"'; beforeEach(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts similarity index 58% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/creation.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts index fb207b1dcca31..d6cece5eb0bc0 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts @@ -4,9 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../../tags'; import { getTimeline } from '../../../objects/timeline'; -import { ROLES } from '../../../../common/test'; import { LOCKED_ICON, @@ -42,7 +43,7 @@ import { import { OVERVIEW_URL, TIMELINE_TEMPLATES_URL } from '../../../urls/navigation'; -describe.skip('Create a timeline from a template', () => { +describe.skip('Create a timeline from a template', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { deleteTimelines(); login(); @@ -54,16 +55,20 @@ describe.skip('Create a timeline from a template', () => { visitWithoutDateRange(TIMELINE_TEMPLATES_URL); }); - it('Should have the same query and open the timeline modal', () => { - selectCustomTemplates(); - expandEventAction(); - clickingOnCreateTimelineFormTemplateBtn(); - - cy.get(TIMELINE_FLYOUT_WRAPPER).should('have.css', 'visibility', 'visible'); - cy.get(TIMELINE_DESCRIPTION).should('have.text', getTimeline().description); - cy.get(TIMELINE_QUERY).should('have.text', getTimeline().query); - closeTimeline(); - }); + it( + 'Should have the same query and open the timeline modal', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + selectCustomTemplates(); + expandEventAction(); + clickingOnCreateTimelineFormTemplateBtn(); + + cy.get(TIMELINE_FLYOUT_WRAPPER).should('have.css', 'visibility', 'visible'); + cy.get(TIMELINE_DESCRIPTION).should('have.text', getTimeline().description); + cy.get(TIMELINE_QUERY).should('have.text', getTimeline().query); + closeTimeline(); + } + ); }); describe('Timelines', (): void => { @@ -72,7 +77,7 @@ describe('Timelines', (): void => { }); describe('Toggle create timeline from plus icon', () => { - context('Privileges: CRUD', () => { + context('Privileges: CRUD', { tags: tag.ESS }, () => { beforeEach(() => { login(); visit(OVERVIEW_URL); @@ -85,7 +90,7 @@ describe('Timelines', (): void => { }); }); - context('Privileges: READ', () => { + context('Privileges: READ', { tags: tag.ESS }, () => { beforeEach(() => { login(ROLES.reader); visit(OVERVIEW_URL, undefined, ROLES.reader); @@ -105,37 +110,41 @@ describe('Timelines', (): void => { }); }); - describe.skip('Creates a timeline by clicking untitled timeline from bottom bar', () => { - beforeEach(() => { - login(); - visit(OVERVIEW_URL); - openTimelineUsingToggle(); - addNameAndDescriptionToTimeline(getTimeline()); - populateTimeline(); - goToQueryTab(); - }); + describe.skip( + 'Creates a timeline by clicking untitled timeline from bottom bar', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + beforeEach(() => { + login(); + visit(OVERVIEW_URL); + openTimelineUsingToggle(); + addNameAndDescriptionToTimeline(getTimeline()); + populateTimeline(); + goToQueryTab(); + }); - it('can be added filter', () => { - addFilter(getTimeline().filter); - cy.get(TIMELINE_FILTER(getTimeline().filter)).should('exist'); - }); + it('can be added filter', () => { + addFilter(getTimeline().filter); + cy.get(TIMELINE_FILTER(getTimeline().filter)).should('exist'); + }); - it('pins an event', () => { - pinFirstEvent(); - cy.get(PIN_EVENT) - .should('have.attr', 'aria-label') - .and('match', /Unpin the event in row 2/); - }); + it('pins an event', () => { + pinFirstEvent(); + cy.get(PIN_EVENT) + .should('have.attr', 'aria-label') + .and('match', /Unpin the event in row 2/); + }); - it('has a lock icon', () => { - cy.get(LOCKED_ICON).should('be.visible'); - }); + it('has a lock icon', () => { + cy.get(LOCKED_ICON).should('be.visible'); + }); - it('can be added notes', () => { - addNotesToTimeline(getTimeline().notes); - cy.get(TIMELINE_TAB_CONTENT_GRAPHS_NOTES) - .find(NOTES_TEXT) - .should('have.text', getTimeline().notes); - }); - }); + it('can be added notes', () => { + addNotesToTimeline(getTimeline().notes); + cy.get(TIMELINE_TAB_CONTENT_GRAPHS_NOTES) + .find(NOTES_TEXT) + .should('have.text', getTimeline().notes); + }); + } + ); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/data_providers.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/data_providers.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/data_providers.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/data_providers.cy.ts index f1bee2d9190ef..aaac56b7c2413 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/data_providers.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/data_providers.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { TIMELINE_DROPPED_DATA_PROVIDERS, @@ -29,7 +30,7 @@ import { getTimeline } from '../../../objects/timeline'; import { HOSTS_URL } from '../../../urls/navigation'; import { cleanKibana, scrollToBottom } from '../../../tasks/common'; -describe('timeline data providers', () => { +describe('timeline data providers', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/export.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/export.cy.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/export.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/export.cy.ts index aa36ef1a4f458..4c58a03904855 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/export.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/export.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { exportTimeline, @@ -20,7 +21,7 @@ import { createTimeline } from '../../../tasks/api_calls/timelines'; import { expectedExportedTimeline, getTimeline } from '../../../objects/timeline'; import { cleanKibana } from '../../../tasks/common'; -describe('Export timelines', () => { +describe('Export timelines', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/fields_browser.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/fields_browser.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts index d13c21325dfdf..b0287d26c11ef 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/fields_browser.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { FIELDS_BROWSER_CATEGORIES_COUNT, @@ -49,7 +50,7 @@ const defaultHeaders = [ { id: 'user.name' }, ]; -describe('Fields Browser', () => { +describe('Fields Browser', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/flyout_button.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/flyout_button.cy.ts similarity index 86% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/flyout_button.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/flyout_button.cy.ts index e4cfa5e4b80f2..3cfe4260f3d9d 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/flyout_button.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/flyout_button.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON } from '../../../screens/security_main'; import { CREATE_NEW_TIMELINE, TIMELINE_FLYOUT_HEADER } from '../../../screens/timeline'; @@ -23,7 +24,7 @@ import { import { HOSTS_URL } from '../../../urls/navigation'; -describe('timeline flyout button', () => { +describe('timeline flyout button', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); }); @@ -47,12 +48,16 @@ describe('timeline flyout button', () => { cy.get(TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON).should('have.focus'); }); - it('re-focuses the toggle button when timeline is closed by clicking the [X] close button', () => { - openTimelineUsingToggle(); - closeTimelineUsingCloseButton(); + it( + 're-focuses the toggle button when timeline is closed by clicking the [X] close button', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + openTimelineUsingToggle(); + closeTimelineUsingCloseButton(); - cy.get(TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON).should('have.focus'); - }); + cy.get(TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON).should('have.focus'); + } + ); it('re-focuses the toggle button when timeline is closed by pressing the Esc key', () => { openTimelineUsingToggle(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/full_screen.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/full_screen.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/full_screen.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/full_screen.cy.ts index 56778ddc6bd6e..e28d12969ff99 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/full_screen.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/full_screen.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { TIMELINE_HEADER, TIMELINE_TABS } from '../../../screens/timeline'; import { cleanKibana } from '../../../tasks/common'; @@ -18,7 +19,7 @@ import { populateTimeline } from '../../../tasks/timeline'; import { HOSTS_URL } from '../../../urls/navigation'; -describe('Toggle full screen', () => { +describe('Toggle full screen', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/inspect.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/inspect.cy.ts similarity index 89% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/inspect.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/inspect.cy.ts index a637508c90e98..9c50d534a5d10 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/inspect.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/inspect.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { INSPECT_MODAL } from '../../../screens/inspect'; @@ -13,7 +14,7 @@ import { executeTimelineKQL, openTimelineInspectButton } from '../../../tasks/ti import { HOSTS_URL } from '../../../urls/navigation'; -describe('Inspect', () => { +describe('Inspect', { tags: [tag.ESS, tag.SERVERLESS] }, () => { context('Timeline', () => { it('inspects the timeline', () => { const hostExistsQuery = 'host.name: *'; diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/local_storage.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/local_storage.cy.ts similarity index 88% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/local_storage.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/local_storage.cy.ts index 239dbea8fce96..ad1b79de8c63f 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/local_storage.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/local_storage.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { reload } from '../../../tasks/common'; import { login, visit } from '../../../tasks/login'; @@ -13,7 +14,7 @@ import { DATAGRID_HEADERS, DATAGRID_HEADER } from '../../../screens/timeline'; import { waitsForEventsToBeLoaded } from '../../../tasks/hosts/events'; import { removeColumn } from '../../../tasks/timeline'; -describe('persistent timeline', () => { +describe('persistent timeline', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { login(); visit(HOSTS_URL); @@ -27,7 +28,7 @@ describe('persistent timeline', () => { ); }); - it('persist the deletion of a column', function () { + it('persist the deletion of a column', { tags: tag.BROKEN_IN_SERVERLESS }, function () { /* For testing purposes we are going to use the message column */ const COLUMN = 'message'; diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/notes_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/notes_tab.cy.ts similarity index 97% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/notes_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/notes_tab.cy.ts index cbde4900d2e79..2c891ea89534a 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/notes_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/notes_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getTimelineNonValidQuery } from '../../../objects/timeline'; @@ -35,7 +36,7 @@ import { TIMELINES_URL } from '../../../urls/navigation'; const text = 'system_indices_superuser'; const link = 'https://www.elastic.co/'; -describe.skip('Timeline notes tab', () => { +describe.skip('Timeline notes tab', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/open_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/open_timeline.cy.ts similarity index 67% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/open_timeline.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/open_timeline.cy.ts index da6215d26796c..bc09f0318cc83 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/open_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/open_timeline.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getTimeline } from '../../../objects/timeline'; @@ -35,33 +36,33 @@ import { import { TIMELINES_URL } from '../../../urls/navigation'; -describe('Open timeline', () => { - before(() => { - cleanKibana(); - login(); - visitWithoutDateRange(TIMELINES_URL); - - createTimeline(getTimeline()) - .then((response) => response.body.data.persistTimeline.timeline.savedObjectId) - .then((timelineId: string) => { - refreshTimelinesUntilTimeLinePresent(timelineId) - // This cy.wait is here because we cannot do a pipe on a timeline as that will introduce multiple URL - // request responses and indeterminism since on clicks to activates URL's. - .then(() => cy.wrap(timelineId).as('timelineId')) - // eslint-disable-next-line cypress/no-unnecessary-waiting - .then(() => cy.wait(1000)) - .then(() => - addNoteToTimeline(getTimeline().notes, timelineId).should((response) => - expect(response.status).to.equal(200) +describe('Open timeline', { tags: [tag.BROKEN_IN_SERVERLESS, tag.ESS] }, () => { + describe('Open timeline modal', () => { + before(function () { + cleanKibana(); + login(); + visitWithoutDateRange(TIMELINES_URL); + + createTimeline(getTimeline()) + .then((response) => response.body.data.persistTimeline.timeline.savedObjectId) + .then((timelineId: string) => { + refreshTimelinesUntilTimeLinePresent(timelineId) + // This cy.wait is here because we cannot do a pipe on a timeline as that will introduce multiple URL + // request responses and indeterminism since on clicks to activates URL's. + .then(() => cy.wrap(timelineId).as('timelineId')) + // eslint-disable-next-line cypress/no-unnecessary-waiting + .then(() => cy.wait(1000)) + .then(() => + addNoteToTimeline(getTimeline().notes, timelineId).should((response) => + expect(response.status).to.equal(200) + ) ) - ) - .then(() => openTimelineById(timelineId)) - .then(() => pinFirstEvent()) - .then(() => markAsFavorite()); - }); - }); + .then(() => openTimelineById(timelineId)) + .then(() => pinFirstEvent()) + .then(() => markAsFavorite()); + }); + }); - describe('Open timeline modal', () => { beforeEach(function () { login(); visitWithoutDateRange(TIMELINES_URL); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/overview.cy.tsx b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/overview.cy.tsx similarity index 96% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/overview.cy.tsx rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/overview.cy.tsx index 7c2fd9ba06020..ff01b83df97b1 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/overview.cy.tsx +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/overview.cy.tsx @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { TIMELINES_OVERVIEW_TABLE, @@ -24,7 +25,7 @@ import { createTimeline, favoriteTimeline } from '../../../tasks/api_calls/timel import { TIMELINES_URL } from '../../../urls/navigation'; -describe('timeline overview search', () => { +describe('timeline overview search', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/pagination.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/pagination.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts index be6827f0365db..df9a9d32fa08b 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/pagination.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { TIMELINE_EVENT, @@ -23,7 +24,7 @@ import { populateTimeline } from '../../../tasks/timeline'; import { HOSTS_URL } from '../../../urls/navigation'; const defaultPageSize = 25; -describe('Pagination', () => { +describe('Pagination', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', 'timeline'); @@ -48,7 +49,7 @@ describe('Pagination', () => { cy.get(TIMELINE_EVENTS_COUNT_PER_PAGE).should('contain.text', defaultPageSize); }); - it('should be able to go to next / previous page', () => { + it('should be able to go to next / previous page', { tags: tag.BROKEN_IN_SERVERLESS }, () => { cy.get(`${TIMELINE_FLYOUT} ${TIMELINE_EVENTS_COUNT_NEXT_PAGE}`).first().click(); cy.get(`${TIMELINE_FLYOUT} ${TIMELINE_EVENTS_COUNT_PREV_PAGE}`).first().click(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/query_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/query_tab.cy.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/query_tab.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/query_tab.cy.ts index bd8d80ceed851..e4661d5e7ef20 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/query_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/query_tab.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { getTimeline } from '../../../objects/timeline'; @@ -30,7 +31,7 @@ import { import { TIMELINES_URL } from '../../../urls/navigation'; -describe.skip('Timeline query tab', () => { +describe.skip('Timeline query tab', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); login(); @@ -81,7 +82,7 @@ describe.skip('Timeline query tab', () => { .and('match', /Unpin the event in row 2/); }); - it('should have an unlock icon', () => { + it('should have an unlock icon', { tags: tag.BROKEN_IN_SERVERLESS }, () => { cy.get(UNLOCKED_ICON).should('be.visible'); }); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/row_renderers.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/row_renderers.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts index 9ae5993f8b80c..bbb54d9c0d7e4 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/row_renderers.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { elementsOverlap } from '../../../helpers/rules'; import { @@ -15,12 +16,7 @@ import { TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE_TOOLTIP, TIMELINE_ROW_RENDERERS_SURICATA_LINK_TOOLTIP, } from '../../../screens/timeline'; -import { - cleanKibana, - deleteTimelines, - waitForPageToBeLoaded, - waitForWelcomePanelToBeLoaded, -} from '../../../tasks/common'; +import { cleanKibana, deleteTimelines, waitForWelcomePanelToBeLoaded } from '../../../tasks/common'; import { waitForAllHostsToBeLoaded } from '../../../tasks/hosts/all_hosts'; import { login, visit } from '../../../tasks/login'; @@ -29,7 +25,7 @@ import { populateTimeline } from '../../../tasks/timeline'; import { HOSTS_URL } from '../../../urls/navigation'; -describe('Row renderers', () => { +describe('Row renderers', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); }); @@ -40,7 +36,6 @@ describe('Row renderers', () => { visit(HOSTS_URL, { onLoad: () => { waitForWelcomePanelToBeLoaded(); - waitForPageToBeLoaded(); waitForAllHostsToBeLoaded(); }, }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/search_or_filter.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/search_or_filter.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/search_or_filter.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/search_or_filter.cy.ts index eb72baca67af1..903a9c28acaeb 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/search_or_filter.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/search_or_filter.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { ADD_FILTER, @@ -26,7 +27,7 @@ import { waitForTimelinesPanelToBeLoaded } from '../../../tasks/timelines'; import { HOSTS_URL, TIMELINES_URL } from '../../../urls/navigation'; -describe('Timeline search and filters', () => { +describe('Timeline search and filters', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/toggle_column.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/toggle_column.cy.ts similarity index 92% rename from x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/toggle_column.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/toggle_column.cy.ts index 7ee011ca931f4..76604b3fc12f2 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/toggle_column.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/toggle_column.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../../tags'; import { ID_HEADER_FIELD, TIMESTAMP_HEADER_FIELD } from '../../../screens/timeline'; import { cleanKibana } from '../../../tasks/common'; @@ -19,7 +20,7 @@ import { import { HOSTS_URL } from '../../../urls/navigation'; -describe('toggle column in timeline', () => { +describe('toggle column in timeline', { tags: [tag.ESS, tag.SERVERLESS] }, () => { before(() => { cleanKibana(); cy.intercept('POST', '/api/timeline/_export?file_name=timelines_export.ndjson').as('export'); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts new file mode 100644 index 0000000000000..5614d649531b7 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts @@ -0,0 +1,200 @@ +/* + * 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 { tag } from '../../../tags'; + +import type { Timeline } from '../../../objects/timeline'; +import { + MODAL_CONFIRMATION_BTN, + MODAL_CONFIRMATION_CANCEL_BTN, +} from '../../../screens/alerts_detection_rules'; +import { + ALERTS_PAGE, + APP_LEAVE_CONFIRM_MODAL, + CASES_PAGE, + MANAGE_PAGE, + OBSERVABILITY_ALERTS_PAGE, +} from '../../../screens/kibana_navigation'; +import { TIMELINE_SAVE_MODAL } from '../../../screens/timeline'; +import { cleanKibana } from '../../../tasks/common'; +import { + navigateFromKibanaCollapsibleTo, + openKibanaNavigation, +} from '../../../tasks/kibana_navigation'; +import { login, visit } from '../../../tasks/login'; +import { closeTimelineUsingToggle } from '../../../tasks/security_main'; +import { + addNameAndDescriptionToTimeline, + createNewTimeline, + populateTimeline, + waitForTimelineChanges, +} from '../../../tasks/timeline'; +import { HOSTS_URL, MANAGE_URL } from '../../../urls/navigation'; + +describe('Save Timeline Prompts', { tags: [tag.ESS, tag.SERVERLESS] }, () => { + before(() => { + cleanKibana(); + login(); + /* + * When timeline changes are pending, chrome would popup with + * a confirm dialog stating that `you can lose unsaved changed. + * Below changes will disable that. + * + * */ + cy.window().then((win) => { + win.onbeforeunload = null; + }); + }); + + beforeEach(() => { + login(); + visit(HOSTS_URL); + createNewTimeline(); + }); + + it( + 'unchanged & unsaved timeline should NOT prompt when user navigates away', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + openKibanaNavigation(); + navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); + cy.url().should('not.contain', HOSTS_URL); + } + ); + + it( + 'Changed & unsaved timeline should prompt when user navigates away from security solution', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + populateTimeline(); + waitForTimelineChanges(); + closeTimelineUsingToggle(); + openKibanaNavigation(); + navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_BTN).click(); + } + ); + + it( + 'Changed & unsaved timeline should NOT prompt when user navigates away within security solution where timelines are enabled', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + populateTimeline(); + + waitForTimelineChanges(); + closeTimelineUsingToggle(); + // navigate to any other page in security solution + openKibanaNavigation(); + cy.get(CASES_PAGE).click(); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); + } + ); + + it( + 'Changed & unsaved timeline should prompt when user navigates away within security solution where timelines are disbaled eg. admin screen', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + populateTimeline(); + waitForTimelineChanges(); + openKibanaNavigation(); + cy.get(MANAGE_PAGE).click(); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_BTN).click(); + } + ); + + it( + 'Changed & saved timeline should NOT prompt when user navigates away out of security solution', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + populateTimeline(); + waitForTimelineChanges(); + closeTimelineUsingToggle(); + openKibanaNavigation(); + navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_CANCEL_BTN).click(); + addNameAndDescriptionToTimeline( + { + title: 'Some Timeline', + description: 'Some Timeline', + } as Timeline, + true + ); + openKibanaNavigation(); + navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); + cy.url().should('not.contain', HOSTS_URL); + } + ); + + it( + 'Changed & saved timeline should NOT prompt when user navigates within security solution where timelines are disabled', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + populateTimeline(); + waitForTimelineChanges(); + closeTimelineUsingToggle(); + openKibanaNavigation(); + cy.get(MANAGE_PAGE).click(); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_CANCEL_BTN).click(); + addNameAndDescriptionToTimeline( + { + title: 'Some Timeline', + description: 'Some Timeline', + } as Timeline, + true + ); + openKibanaNavigation(); + cy.get(MANAGE_PAGE).click(); + cy.url().should('not.contain', HOSTS_URL); + } + ); + + it( + 'When user navigates to the page where timeline is present, Time save modal should not exists.', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + populateTimeline(); + waitForTimelineChanges(); + closeTimelineUsingToggle(); + openKibanaNavigation(); + cy.get(MANAGE_PAGE).click(); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_BTN).click(); + + // Navigate back to HOSTS_URL and ensure that + // timeline save modal is NOT present + + openKibanaNavigation(); + cy.get(ALERTS_PAGE).click(); + cy.get(TIMELINE_SAVE_MODAL).should('not.exist'); + } + ); + + it( + 'Changed and unsaved timeline should NOT prompt when user navigates from the page where timeline is disabled', + { tags: tag.BROKEN_IN_SERVERLESS }, + () => { + populateTimeline(); + waitForTimelineChanges(); + closeTimelineUsingToggle(); + openKibanaNavigation(); + cy.get(MANAGE_PAGE).click(); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + cy.get(MODAL_CONFIRMATION_BTN).click(); + // now we have come from MANAGE_PAGE where timeline is disabled + // to outside app where timeline is not present. + // There should be NO confirmation model in that case. + openKibanaNavigation(); + navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); + // should not be manage page i.e. successfull navigation + cy.get(TIMELINE_SAVE_MODAL).should('not.exist'); + cy.url().should('not.contain', MANAGE_URL); + } + ); +}); diff --git a/x-pack/plugins/security_solution/cypress/e2e/ml/ml_conditional_links.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/ml/ml_conditional_links.cy.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/e2e/ml/ml_conditional_links.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/ml/ml_conditional_links.cy.ts index 40caf2ae4ed8e..11ae0be3373e1 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/ml/ml_conditional_links.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/ml/ml_conditional_links.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../tags'; import { KQL_INPUT } from '../../screens/security_header'; @@ -25,7 +26,7 @@ import { mlNetworkSingleIpNullKqlQuery, } from '../../urls/ml_conditional_links'; -describe('ml conditional links', () => { +describe('ml conditional links', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { beforeEach(() => { login(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/overview/cti_link_panel.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/overview/cti_link_panel.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/overview/cti_link_panel.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/overview/cti_link_panel.cy.ts index 1bc501260b850..f8044b318c76e 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/overview/cti_link_panel.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/overview/cti_link_panel.cy.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { tag } from '../../tags'; import { OVERVIEW_CTI_ENABLE_MODULE_BUTTON, @@ -15,7 +16,7 @@ import { import { login, visit } from '../../tasks/login'; import { OVERVIEW_URL } from '../../urls/navigation'; -describe('CTI Link Panel', () => { +describe('CTI Link Panel', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { login(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/urls/compatibility.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/urls/compatibility.cy.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/e2e/urls/compatibility.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/urls/compatibility.cy.ts index 9e522baf4a4b1..990e960011b32 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/urls/compatibility.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/urls/compatibility.cy.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ROLES } from '@kbn/security-solution-plugin/common/test'; +import { tag } from '../../tags'; -import { ROLES } from '../../../common/test'; import { login, visit, visitWithoutDateRange } from '../../tasks/login'; import { @@ -34,13 +35,10 @@ const ABSOLUTE_DATE = { const RULE_ID = '5a4a0460-d822-11eb-8962-bfd4aff0a9b3'; -describe('URL compatibility', () => { - before(() => { +describe('URL compatibility', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { + beforeEach(() => { login(ROLES.platform_engineer); visit(SECURITY_DETECTIONS_URL); - }); - - beforeEach(() => { login(); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/urls/not_found.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts similarity index 95% rename from x-pack/plugins/security_solution/cypress/e2e/urls/not_found.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts index 0f1b064403025..0a5ca24b510df 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/urls/not_found.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/urls/not_found.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { login, visit } from '../../tasks/login'; import { @@ -24,7 +26,7 @@ import { NOT_FOUND } from '../../screens/common/page'; const mockRuleId = '5a4a0460-d822-11eb-8962-bfd4aff0a9b3'; -describe('Display not found page', () => { +describe('Display not found page', { tags: [tag.ESS, tag.SERVERLESS] }, () => { beforeEach(() => { login(); visit(TIMELINES_URL); diff --git a/x-pack/plugins/security_solution/cypress/e2e/urls/state.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/urls/state.cy.ts similarity index 99% rename from x-pack/plugins/security_solution/cypress/e2e/urls/state.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/urls/state.cy.ts index fcb9c6298c03d..b696f4943ad22 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/urls/state.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/urls/state.cy.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { tag } from '../../tags'; + import { DATE_PICKER_APPLY_BUTTON_TIMELINE, DATE_PICKER_END_DATE_POPOVER_BUTTON, @@ -70,7 +72,7 @@ const ABSOLUTE_DATE = { firefoxStartTimeTyped: '2019-08-01T14:33:29', }; -describe('url state', () => { +describe('url state', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => { beforeEach(() => { login(); }); diff --git a/x-pack/plugins/security_solution/cypress/fixtures/7_15_timeline.ndjson b/x-pack/test/security_solution_cypress/cypress/fixtures/7_15_timeline.ndjson similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/7_15_timeline.ndjson rename to x-pack/test/security_solution_cypress/cypress/fixtures/7_15_timeline.ndjson diff --git a/x-pack/plugins/security_solution/cypress/fixtures/7_16_case.ndjson b/x-pack/test/security_solution_cypress/cypress/fixtures/7_16_case.ndjson similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/7_16_case.ndjson rename to x-pack/test/security_solution_cypress/cypress/fixtures/7_16_case.ndjson diff --git a/x-pack/plugins/security_solution/cypress/fixtures/7_16_exception_list.ndjson b/x-pack/test/security_solution_cypress/cypress/fixtures/7_16_exception_list.ndjson similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/7_16_exception_list.ndjson rename to x-pack/test/security_solution_cypress/cypress/fixtures/7_16_exception_list.ndjson diff --git a/x-pack/plugins/security_solution/cypress/fixtures/7_16_rules.ndjson b/x-pack/test/security_solution_cypress/cypress/fixtures/7_16_rules.ndjson similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/7_16_rules.ndjson rename to x-pack/test/security_solution_cypress/cypress/fixtures/7_16_rules.ndjson diff --git a/x-pack/plugins/security_solution/cypress/fixtures/cidr_list.txt b/x-pack/test/security_solution_cypress/cypress/fixtures/cidr_list.txt similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/cidr_list.txt rename to x-pack/test/security_solution_cypress/cypress/fixtures/cidr_list.txt diff --git a/x-pack/plugins/security_solution/cypress/fixtures/ip_list.txt b/x-pack/test/security_solution_cypress/cypress/fixtures/ip_list.txt similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/ip_list.txt rename to x-pack/test/security_solution_cypress/cypress/fixtures/ip_list.txt diff --git a/x-pack/plugins/security_solution/cypress/fixtures/related_integrations.ndjson b/x-pack/test/security_solution_cypress/cypress/fixtures/related_integrations.ndjson similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/related_integrations.ndjson rename to x-pack/test/security_solution_cypress/cypress/fixtures/related_integrations.ndjson diff --git a/x-pack/plugins/security_solution/cypress/fixtures/value_list.txt b/x-pack/test/security_solution_cypress/cypress/fixtures/value_list.txt similarity index 100% rename from x-pack/plugins/security_solution/cypress/fixtures/value_list.txt rename to x-pack/test/security_solution_cypress/cypress/fixtures/value_list.txt diff --git a/x-pack/plugins/security_solution/cypress/helpers/common.ts b/x-pack/test/security_solution_cypress/cypress/helpers/common.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/helpers/common.ts rename to x-pack/test/security_solution_cypress/cypress/helpers/common.ts diff --git a/x-pack/plugins/security_solution/cypress/helpers/rules.ts b/x-pack/test/security_solution_cypress/cypress/helpers/rules.ts similarity index 90% rename from x-pack/plugins/security_solution/cypress/helpers/rules.ts rename to x-pack/test/security_solution_cypress/cypress/helpers/rules.ts index 86b5255d100c9..40b3b8e5798b4 100644 --- a/x-pack/plugins/security_solution/cypress/helpers/rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/helpers/rules.ts @@ -6,10 +6,10 @@ */ import dateMath from '@kbn/datemath'; import moment from 'moment'; -import type { PrebuiltRuleAsset } from '../../server/lib/detection_engine/prebuilt_rules'; -import { getPrebuiltRuleMock } from '../../server/lib/detection_engine/prebuilt_rules/mocks'; +import type { PrebuiltRuleAsset } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules'; +import { getPrebuiltRuleMock } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/mocks'; -import type { ThreatArray } from '../../common/api/detection_engine'; +import type { ThreatArray } from '@kbn/security-solution-plugin/common/api/detection_engine'; export const formatMitreAttackDescription = (mitre: ThreatArray) => { return mitre diff --git a/x-pack/plugins/security_solution/cypress/objects/case.ts b/x-pack/test/security_solution_cypress/cypress/objects/case.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/objects/case.ts rename to x-pack/test/security_solution_cypress/cypress/objects/case.ts diff --git a/x-pack/plugins/security_solution/cypress/objects/connector.ts b/x-pack/test/security_solution_cypress/cypress/objects/connector.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/objects/connector.ts rename to x-pack/test/security_solution_cypress/cypress/objects/connector.ts diff --git a/x-pack/plugins/security_solution/cypress/objects/exception.ts b/x-pack/test/security_solution_cypress/cypress/objects/exception.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/objects/exception.ts rename to x-pack/test/security_solution_cypress/cypress/objects/exception.ts diff --git a/x-pack/plugins/security_solution/cypress/objects/filter.ts b/x-pack/test/security_solution_cypress/cypress/objects/filter.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/objects/filter.ts rename to x-pack/test/security_solution_cypress/cypress/objects/filter.ts diff --git a/x-pack/plugins/security_solution/cypress/objects/rule.ts b/x-pack/test/security_solution_cypress/cypress/objects/rule.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/objects/rule.ts rename to x-pack/test/security_solution_cypress/cypress/objects/rule.ts index 8488d94e9d329..e2920f4975478 100644 --- a/x-pack/plugins/security_solution/cypress/objects/rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/objects/rule.ts @@ -6,7 +6,7 @@ */ import type { SeverityMappingItem, Threat } from '@kbn/securitysolution-io-ts-alerting-types'; -import { getMockThreatData } from '../../public/detections/mitre/mitre_tactics_techniques'; +import { getMockThreatData } from '@kbn/security-solution-plugin/public/detections/mitre/mitre_tactics_techniques'; import type { EqlRuleCreateProps, MachineLearningRuleCreateProps, @@ -16,7 +16,7 @@ import type { SavedQueryRuleCreateProps, ThreatMatchRuleCreateProps, ThresholdRuleCreateProps, -} from '../../common/api/detection_engine'; +} from '@kbn/security-solution-plugin/common/api/detection_engine'; import type { CreateRulePropsRewrites } from './types'; const ccsRemoteName: string = Cypress.env('CCS_REMOTE_NAME'); diff --git a/x-pack/plugins/security_solution/cypress/objects/timeline.ts b/x-pack/test/security_solution_cypress/cypress/objects/timeline.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/objects/timeline.ts rename to x-pack/test/security_solution_cypress/cypress/objects/timeline.ts index 885734f93f734..5ad542ac49530 100644 --- a/x-pack/plugins/security_solution/cypress/objects/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/objects/timeline.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { TimelineResponse } from '../../common/api/timeline'; +import type { TimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; export interface Timeline { title: string; diff --git a/x-pack/plugins/security_solution/cypress/objects/types.ts b/x-pack/test/security_solution_cypress/cypress/objects/types.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/objects/types.ts rename to x-pack/test/security_solution_cypress/cypress/objects/types.ts diff --git a/x-pack/plugins/security_solution/cypress/reporter_config.json b/x-pack/test/security_solution_cypress/cypress/reporter_config.json similarity index 100% rename from x-pack/plugins/security_solution/cypress/reporter_config.json rename to x-pack/test/security_solution_cypress/cypress/reporter_config.json diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts.ts b/x-pack/test/security_solution_cypress/cypress/screens/alerts.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/alerts.ts rename to x-pack/test/security_solution_cypress/cypress/screens/alerts.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts_details.ts b/x-pack/test/security_solution_cypress/cypress/screens/alerts_details.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/alerts_details.ts rename to x-pack/test/security_solution_cypress/cypress/screens/alerts_details.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts b/x-pack/test/security_solution_cypress/cypress/screens/alerts_detection_rules.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts rename to x-pack/test/security_solution_cypress/cypress/screens/alerts_detection_rules.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/all_cases.ts b/x-pack/test/security_solution_cypress/cypress/screens/all_cases.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/all_cases.ts rename to x-pack/test/security_solution_cypress/cypress/screens/all_cases.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/case_details.ts b/x-pack/test/security_solution_cypress/cypress/screens/case_details.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/case_details.ts rename to x-pack/test/security_solution_cypress/cypress/screens/case_details.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/common.ts b/x-pack/test/security_solution_cypress/cypress/screens/common.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/common.ts rename to x-pack/test/security_solution_cypress/cypress/screens/common.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/common/callouts.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/callouts.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/common/callouts.ts rename to x-pack/test/security_solution_cypress/cypress/screens/common/callouts.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/common/controls.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/controls.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/common/controls.ts rename to x-pack/test/security_solution_cypress/cypress/screens/common/controls.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/common/data_grid.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/data_grid.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/common/data_grid.ts rename to x-pack/test/security_solution_cypress/cypress/screens/common/data_grid.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/common/filter_group.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/filter_group.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/common/filter_group.ts rename to x-pack/test/security_solution_cypress/cypress/screens/common/filter_group.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/common/page.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/page.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/common/page.ts rename to x-pack/test/security_solution_cypress/cypress/screens/common/page.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/common/rule_actions.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/rule_actions.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/common/rule_actions.ts rename to x-pack/test/security_solution_cypress/cypress/screens/common/rule_actions.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/configure_cases.ts b/x-pack/test/security_solution_cypress/cypress/screens/configure_cases.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/configure_cases.ts rename to x-pack/test/security_solution_cypress/cypress/screens/configure_cases.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/create_new_case.ts b/x-pack/test/security_solution_cypress/cypress/screens/create_new_case.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/create_new_case.ts rename to x-pack/test/security_solution_cypress/cypress/screens/create_new_case.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/create_new_rule.ts rename to x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/create_runtime_field.ts b/x-pack/test/security_solution_cypress/cypress/screens/create_runtime_field.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/create_runtime_field.ts rename to x-pack/test/security_solution_cypress/cypress/screens/create_runtime_field.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/dashboards/common.ts b/x-pack/test/security_solution_cypress/cypress/screens/dashboards/common.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/dashboards/common.ts rename to x-pack/test/security_solution_cypress/cypress/screens/dashboards/common.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/date_picker.ts b/x-pack/test/security_solution_cypress/cypress/screens/date_picker.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/date_picker.ts rename to x-pack/test/security_solution_cypress/cypress/screens/date_picker.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/detection_response.ts b/x-pack/test/security_solution_cypress/cypress/screens/detection_response.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/detection_response.ts rename to x-pack/test/security_solution_cypress/cypress/screens/detection_response.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/edit_connector.ts b/x-pack/test/security_solution_cypress/cypress/screens/edit_connector.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/edit_connector.ts rename to x-pack/test/security_solution_cypress/cypress/screens/edit_connector.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/edit_rule.ts b/x-pack/test/security_solution_cypress/cypress/screens/edit_rule.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/edit_rule.ts rename to x-pack/test/security_solution_cypress/cypress/screens/edit_rule.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/entity_analytics.ts rename to x-pack/test/security_solution_cypress/cypress/screens/entity_analytics.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/entity_analytics_management.ts b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/entity_analytics_management.ts rename to x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/exceptions.ts rename to x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel.ts similarity index 81% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel.ts index f62d5848270c2..4a00d44cee981 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel.ts @@ -8,9 +8,12 @@ import { INSIGHTS_TAB_BUTTON_GROUP_TEST_ID, VISUALIZE_TAB_BUTTON_GROUP_TEST_ID, -} from '../../../public/flyout/left/tabs/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; +import { + INSIGHTS_TAB_TEST_ID, + VISUALIZE_TAB_TEST_ID, +} from '@kbn/security-solution-plugin/public/flyout/left/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { INSIGHTS_TAB_TEST_ID, VISUALIZE_TAB_TEST_ID } from '../../../public/flyout/left/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB = getDataTestSubjectSelector(INSIGHTS_TAB_TEST_ID); diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts similarity index 71% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts index cb35dff64b9be..c9b16f3ada2cd 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; +import { ANALYZER_GRAPH_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON_TEST_ID } from '../../../public/flyout/left/tabs/test_ids'; -import { ANALYZER_GRAPH_TEST_ID } from '../../../public/flyout/left/components/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON = getDataTestSubjectSelector(VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON_TEST_ID); diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts similarity index 86% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts index c05c0da82c820..2e01659976b1e 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { getDataTestSubjectSelector } from '../../helpers/common'; -import { INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID } from '../../../public/flyout/left/tabs/test_ids'; +import { INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; import { CORRELATIONS_DETAILS_BY_ANCESTRY_SECTION_TEST_ID, CORRELATIONS_DETAILS_BY_ANCESTRY_TABLE_TEST_ID, CORRELATIONS_DETAILS_BY_SESSION_SECTION_TEST_ID, CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TEST_ID, CORRELATIONS_DETAILS_CASES_SECTION_TEST_ID, -} from '../../../public/flyout/left/components/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; +import { getDataTestSubjectSelector } from '../../helpers/common'; export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON = getDataTestSubjectSelector( INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts similarity index 82% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts index 32620b112bb83..20e8940aa5488 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts @@ -9,9 +9,9 @@ import { ENTITIES_DETAILS_TEST_ID, HOST_DETAILS_TEST_ID, USER_DETAILS_TEST_ID, -} from '../../../public/flyout/left/components/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; +import { INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID } from '../../../public/flyout/left/tabs/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON = getDataTestSubjectSelector( INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_investigation_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_investigation_tab.ts similarity index 72% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_investigation_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_investigation_tab.ts index 084d2dc63b013..e981af1cdb895 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_investigation_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_investigation_tab.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { INVESTIGATION_TAB_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/test_ids'; +import { INVESTIGATION_TAB_CONTENT_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { INVESTIGATION_TAB_TEST_ID } from '../../../public/flyout/left/test_ids'; -import { INVESTIGATION_TAB_CONTENT_TEST_ID } from '../../../public/flyout/left/tabs/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB = getDataTestSubjectSelector(INVESTIGATION_TAB_TEST_ID); diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts similarity index 90% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts index b1e19dd9588a2..0b343d4375233 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts @@ -13,9 +13,9 @@ import { PREVALENCE_DETAILS_TABLE_TEST_ID, PREVALENCE_DETAILS_TABLE_TYPE_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID, -} from '../../../public/flyout/left/components/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; +import { INSIGHTS_TAB_PREVALENCE_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { INSIGHTS_TAB_PREVALENCE_BUTTON_TEST_ID } from '../../../public/flyout/left/tabs/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_BUTTON = getDataTestSubjectSelector( INSIGHTS_TAB_PREVALENCE_BUTTON_TEST_ID diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts similarity index 71% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts index 0620d34230b8c..15d0aeede669b 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { RESPONSE_TAB_TEST_ID } from '../../../public/flyout/left/test_ids'; -import { RESPONSE_EMPTY_TEST_ID } from '../../../public/flyout/left/components/test_ids'; +import { RESPONSE_TAB_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/test_ids'; +import { RESPONSE_EMPTY_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; export const DOCUMENT_DETAILS_FLYOUT_RESPONSE_TAB = diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts similarity index 71% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts index b382e85e47174..d7e4f86d79c82 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { VISUALIZE_TAB_SESSION_VIEW_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; +import { SESSION_VIEW_ERROR_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { VISUALIZE_TAB_SESSION_VIEW_BUTTON_TEST_ID } from '../../../public/flyout/left/tabs/test_ids'; -import { SESSION_VIEW_ERROR_TEST_ID } from '../../../public/flyout/left/components/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON = getDataTestSubjectSelector( VISUALIZE_TAB_SESSION_VIEW_BUTTON_TEST_ID diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts similarity index 89% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts index ab7275d50ea57..a60a7d7a40105 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON_TEST_ID } from '../../../public/flyout/left/tabs/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON = getDataTestSubjectSelector(INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON_TEST_ID); diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts index 5ccb58e1ef969..23a3985a36d9a 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel_rule_preview.ts @@ -17,7 +17,7 @@ import { RULE_PREVIEW_SCHEDULE_HEADER_TEST_ID, RULE_PREVIEW_SCHEDULE_CONTENT_TEST_ID, RULE_PREVIEW_FOOTER_TEST_ID, -} from '../../../public/flyout/preview/components/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/preview/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; export const DOCUMENT_DETAILS_FLYOUT_RULE_PREVIEW_SECTION = diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel.ts index 60ebbe7fdd071..7ea0712aae290 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel.ts @@ -5,13 +5,12 @@ * 2.0. */ -import { getDataTestSubjectSelector } from '../../helpers/common'; import { FLYOUT_BODY_TEST_ID, JSON_TAB_TEST_ID, OVERVIEW_TAB_TEST_ID, TABLE_TAB_TEST_ID, -} from '../../../public/flyout/right/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/right/test_ids'; import { COLLAPSE_DETAILS_BUTTON_TEST_ID, EXPAND_DETAILS_BUTTON_TEST_ID, @@ -22,7 +21,8 @@ import { FLYOUT_HEADER_SEVERITY_VALUE_TEST_ID, FLYOUT_HEADER_STATUS_BUTTON_TEST_ID, FLYOUT_HEADER_TITLE_TEST_ID, -} from '../../../public/flyout/right/components/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/right/components/test_ids'; +import { getDataTestSubjectSelector } from '../../helpers/common'; export const DOCUMENT_DETAILS_FLYOUT_BODY = getDataTestSubjectSelector(FLYOUT_BODY_TEST_ID); diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts similarity index 80% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts index e7de5c5114250..f3cd1a262b281 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_json_tab.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { JSON_TAB_CONTENT_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/right/tabs/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; -import { JSON_TAB_CONTENT_TEST_ID } from '../../../public/flyout/right/tabs/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_JSON_TAB_CONTENT = getDataTestSubjectSelector(JSON_TAB_CONTENT_TEST_ID); diff --git a/x-pack/plugins/security_solution/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 similarity index 98% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts index 6bc2f1400e0ae..dc7e3fdd1020e 100644 --- a/x-pack/plugins/security_solution/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 @@ -5,7 +5,6 @@ * 2.0. */ -import { getDataTestSubjectSelector } from '../../helpers/common'; import { ABOUT_SECTION_CONTENT_TEST_ID, ABOUT_SECTION_HEADER_TEST_ID, @@ -39,7 +38,8 @@ import { ANALYZER_PREVIEW_CONTENT_TEST_ID, SESSION_PREVIEW_CONTENT_TEST_ID, INSIGHTS_PREVALENCE_VALUE_TEST_ID, -} from '../../../public/flyout/right/components/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/right/components/test_ids'; +import { getDataTestSubjectSelector } from '../../helpers/common'; /* About section */ diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts index 0d23b23692f42..b8cd86f639e2a 100644 --- a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_table_tab.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { TABLE_TAB_CONTENT_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/right/tabs/test_ids'; import { getClassSelector, getDataTestSubjectSelector } from '../../helpers/common'; -import { TABLE_TAB_CONTENT_TEST_ID } from '../../../public/flyout/right/tabs/test_ids'; export const DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_CONTENT = getDataTestSubjectSelector(TABLE_TAB_CONTENT_TEST_ID); diff --git a/x-pack/plugins/security_solution/cypress/screens/expandable_flyout/common.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/common.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/expandable_flyout/common.ts rename to x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/common.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/fields_browser.ts b/x-pack/test/security_solution_cypress/cypress/screens/fields_browser.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/fields_browser.ts rename to x-pack/test/security_solution_cypress/cypress/screens/fields_browser.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/guided_onboarding.ts b/x-pack/test/security_solution_cypress/cypress/screens/guided_onboarding.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/guided_onboarding.ts rename to x-pack/test/security_solution_cypress/cypress/screens/guided_onboarding.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/all_hosts.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/all_hosts.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/hosts/all_hosts.ts rename to x-pack/test/security_solution_cypress/cypress/screens/hosts/all_hosts.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/authentications.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/authentications.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/hosts/authentications.ts rename to x-pack/test/security_solution_cypress/cypress/screens/hosts/authentications.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/events.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/events.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/hosts/events.ts rename to x-pack/test/security_solution_cypress/cypress/screens/hosts/events.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/host_risk.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/host_risk.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/hosts/host_risk.ts rename to x-pack/test/security_solution_cypress/cypress/screens/hosts/host_risk.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/main.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/main.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/hosts/main.ts rename to x-pack/test/security_solution_cypress/cypress/screens/hosts/main.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/uncommon_processes.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/uncommon_processes.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/hosts/uncommon_processes.ts rename to x-pack/test/security_solution_cypress/cypress/screens/hosts/uncommon_processes.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/inspect.ts b/x-pack/test/security_solution_cypress/cypress/screens/inspect.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/inspect.ts rename to x-pack/test/security_solution_cypress/cypress/screens/inspect.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/integrations.ts b/x-pack/test/security_solution_cypress/cypress/screens/integrations.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/integrations.ts rename to x-pack/test/security_solution_cypress/cypress/screens/integrations.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/kibana_navigation.ts b/x-pack/test/security_solution_cypress/cypress/screens/kibana_navigation.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/kibana_navigation.ts rename to x-pack/test/security_solution_cypress/cypress/screens/kibana_navigation.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/lists.ts b/x-pack/test/security_solution_cypress/cypress/screens/lists.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/lists.ts rename to x-pack/test/security_solution_cypress/cypress/screens/lists.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/loading.ts b/x-pack/test/security_solution_cypress/cypress/screens/loading.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/loading.ts rename to x-pack/test/security_solution_cypress/cypress/screens/loading.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/network/dns.ts b/x-pack/test/security_solution_cypress/cypress/screens/network/dns.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/network/dns.ts rename to x-pack/test/security_solution_cypress/cypress/screens/network/dns.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/network/flows.ts b/x-pack/test/security_solution_cypress/cypress/screens/network/flows.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/network/flows.ts rename to x-pack/test/security_solution_cypress/cypress/screens/network/flows.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/network/http.ts b/x-pack/test/security_solution_cypress/cypress/screens/network/http.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/network/http.ts rename to x-pack/test/security_solution_cypress/cypress/screens/network/http.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/network/tls.ts b/x-pack/test/security_solution_cypress/cypress/screens/network/tls.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/network/tls.ts rename to x-pack/test/security_solution_cypress/cypress/screens/network/tls.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/overview.ts b/x-pack/test/security_solution_cypress/cypress/screens/overview.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/overview.ts rename to x-pack/test/security_solution_cypress/cypress/screens/overview.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/rule_details.ts b/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/rule_details.ts rename to x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/rule_snoozing.ts b/x-pack/test/security_solution_cypress/cypress/screens/rule_snoozing.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/rule_snoozing.ts rename to x-pack/test/security_solution_cypress/cypress/screens/rule_snoozing.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/rules_bulk_actions.ts b/x-pack/test/security_solution_cypress/cypress/screens/rules_bulk_actions.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/rules_bulk_actions.ts rename to x-pack/test/security_solution_cypress/cypress/screens/rules_bulk_actions.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/saved_objects.ts b/x-pack/test/security_solution_cypress/cypress/screens/saved_objects.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/saved_objects.ts rename to x-pack/test/security_solution_cypress/cypress/screens/saved_objects.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/search_bar.ts b/x-pack/test/security_solution_cypress/cypress/screens/search_bar.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/search_bar.ts rename to x-pack/test/security_solution_cypress/cypress/screens/search_bar.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/security_header.ts b/x-pack/test/security_solution_cypress/cypress/screens/security_header.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/security_header.ts rename to x-pack/test/security_solution_cypress/cypress/screens/security_header.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/security_main.ts b/x-pack/test/security_solution_cypress/cypress/screens/security_main.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/security_main.ts rename to x-pack/test/security_solution_cypress/cypress/screens/security_main.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/shared.ts b/x-pack/test/security_solution_cypress/cypress/screens/shared.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/shared.ts rename to x-pack/test/security_solution_cypress/cypress/screens/shared.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/sourcerer.ts b/x-pack/test/security_solution_cypress/cypress/screens/sourcerer.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/sourcerer.ts rename to x-pack/test/security_solution_cypress/cypress/screens/sourcerer.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/table_pagination.ts b/x-pack/test/security_solution_cypress/cypress/screens/table_pagination.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/table_pagination.ts rename to x-pack/test/security_solution_cypress/cypress/screens/table_pagination.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/templates.ts b/x-pack/test/security_solution_cypress/cypress/screens/templates.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/templates.ts rename to x-pack/test/security_solution_cypress/cypress/screens/templates.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/timeline.ts b/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/timeline.ts rename to x-pack/test/security_solution_cypress/cypress/screens/timeline.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/timelines.ts b/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/timelines.ts rename to x-pack/test/security_solution_cypress/cypress/screens/timelines.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/users/all_users.ts b/x-pack/test/security_solution_cypress/cypress/screens/users/all_users.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/users/all_users.ts rename to x-pack/test/security_solution_cypress/cypress/screens/users/all_users.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/users/user_anomalies.ts b/x-pack/test/security_solution_cypress/cypress/screens/users/user_anomalies.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/users/user_anomalies.ts rename to x-pack/test/security_solution_cypress/cypress/screens/users/user_anomalies.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/users/user_authentications.ts b/x-pack/test/security_solution_cypress/cypress/screens/users/user_authentications.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/users/user_authentications.ts rename to x-pack/test/security_solution_cypress/cypress/screens/users/user_authentications.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/users/user_events.ts b/x-pack/test/security_solution_cypress/cypress/screens/users/user_events.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/users/user_events.ts rename to x-pack/test/security_solution_cypress/cypress/screens/users/user_events.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/users/user_risk_score.ts b/x-pack/test/security_solution_cypress/cypress/screens/users/user_risk_score.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/screens/users/user_risk_score.ts rename to x-pack/test/security_solution_cypress/cypress/screens/users/user_risk_score.ts diff --git a/x-pack/plugins/security_solution/cypress/support/commands.js b/x-pack/test/security_solution_cypress/cypress/support/commands.js similarity index 100% rename from x-pack/plugins/security_solution/cypress/support/commands.js rename to x-pack/test/security_solution_cypress/cypress/support/commands.js diff --git a/x-pack/plugins/security_solution/cypress/support/e2e.js b/x-pack/test/security_solution_cypress/cypress/support/e2e.js similarity index 100% rename from x-pack/plugins/security_solution/cypress/support/e2e.js rename to x-pack/test/security_solution_cypress/cypress/support/e2e.js diff --git a/x-pack/plugins/security_solution/cypress/support/es_archiver.ts b/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts similarity index 68% rename from x-pack/plugins/security_solution/cypress/support/es_archiver.ts rename to x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts index efc3285686555..42ddb4a526387 100644 --- a/x-pack/plugins/security_solution/cypress/support/es_archiver.ts +++ b/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts @@ -30,29 +30,13 @@ export const esArchiver = ( log, client, kbnClient, - baseDir: '../../../test/security_solution_cypress/es_archives', + baseDir: '../es_archives', }); on('task', { esArchiverLoad: async (archiveName) => esArchiverInstance.load(archiveName), esArchiverUnload: async (archiveName) => esArchiverInstance.unload(archiveName), esArchiverResetKibana: async () => esArchiverInstance.emptyKibanaIndex(), - esArchiverCCSLoad: async (archiveName) => { - const ccsEsArchiverInstance = new EsArchiver({ - client: new Client({ - node: config.env.CCS_ELASTICSEARCH_URL, - Connection: HttpConnection, - }), - log, - kbnClient: new KbnClient({ - log, - url: config.env.CCS_KIBANA_URL, - }), - baseDir: '../../../test/security_solution_cypress/es_archives', - }); - - return ccsEsArchiverInstance.load(archiveName); - }, }); return esArchiverInstance; diff --git a/x-pack/plugins/security_solution/cypress/support/index.d.ts b/x-pack/test/security_solution_cypress/cypress/support/index.d.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/support/index.d.ts rename to x-pack/test/security_solution_cypress/cypress/support/index.d.ts diff --git a/x-pack/test/security_solution_cypress/cypress/tags.ts b/x-pack/test/security_solution_cypress/cypress/tags.ts new file mode 100644 index 0000000000000..a0698a4c40951 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/tags.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const tag = { + SERVERLESS: '@serverless', + ESS: '@ess', + BROKEN_IN_SERVERLESS: '@brokenInServerless', +}; diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/tasks/alerts.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts index e69a8705f7e22..8816851dcec7c 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts @@ -7,7 +7,8 @@ import { encode } from '@kbn/rison'; import { recurse } from 'cypress-recurse'; -import { formatPageFilterSearchParam } from '../../common/utils/format_page_filter_search_param'; +import { formatPageFilterSearchParam } from '@kbn/security-solution-plugin/common/utils/format_page_filter_search_param'; +import type { FilterItemObj } from '@kbn/security-solution-plugin/public/common/components/filter_group/types'; import { TOP_N_CONTAINER } from '../screens/network/flows'; import { ADD_EXCEPTION_BTN, @@ -82,7 +83,6 @@ import { import { LOADING_SPINNER } from '../screens/common/page'; import { ALERTS_URL } from '../urls/navigation'; import { FIELDS_BROWSER_BTN } from '../screens/rule_details'; -import type { FilterItemObj } from '../../public/common/components/filter_group/types'; import { visit } from './login'; import { openFilterGroupContextMenu } from './common/filter_group'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_details.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts_details.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/alerts_details.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/alerts_details.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/all_cases.ts b/x-pack/test/security_solution_cypress/cypress/tasks/all_cases.ts similarity index 87% rename from x-pack/plugins/security_solution/cypress/tasks/all_cases.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/all_cases.ts index 5485a47214ac3..90d41a92c8f16 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/all_cases.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/all_cases.ts @@ -10,15 +10,12 @@ import { ALL_CASES_CREATE_NEW_CASE_BTN, EDIT_EXTERNAL_CONNECTION, } from '../screens/all_cases'; -import { waitForPageToBeLoaded } from './common'; export const goToCreateNewCase = () => { cy.get(ALL_CASES_CREATE_NEW_CASE_BTN, { timeout: 60000 }).click({ force: true }); - waitForPageToBeLoaded(); }; export const goToCaseDetails = () => { - waitForPageToBeLoaded(); cy.get(ALL_CASES_NAME).click({ force: true }); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/cases.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/cases.ts similarity index 88% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/cases.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/cases.ts index f41f1f40d5493..e75b408089d93 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/cases.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/cases.ts @@ -26,5 +26,5 @@ export const createCase = (newCase: TestCase) => }, owner: newCase.owner, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/connectors.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/connectors.ts similarity index 87% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/connectors.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/connectors.ts index a89e578764eec..38936d78cc360 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/connectors.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/connectors.ts @@ -10,7 +10,7 @@ export const createConnector = (connector: Record) => method: 'POST', url: '/api/actions/action', body: connector, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); const slackConnectorAPIPayload = { diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/elasticsearch.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/elasticsearch.ts similarity index 86% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/elasticsearch.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/elasticsearch.ts index 7312339497f2c..bd4c2c4af873c 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/elasticsearch.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/elasticsearch.ts @@ -10,7 +10,7 @@ export const deleteIndex = (index: string) => { rootRequest({ method: 'DELETE', url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }; @@ -39,7 +39,7 @@ export const waitForNewDocumentToBeIndexed = (index: string, initialNumberOfDocu rootRequest<{ hits: { hits: unknown[] } }>({ method: 'GET', url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_search`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }).then((response) => { if (response.status !== 200) { @@ -58,7 +58,7 @@ export const refreshIndex = (index: string) => { rootRequest({ method: 'POST', url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_refresh`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }).then((response) => { if (response.status !== 200) { diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/exceptions.ts similarity index 84% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/exceptions.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/exceptions.ts index 8b258c79a7edf..622e311fa0fd1 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/exceptions.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/exceptions.ts @@ -16,7 +16,7 @@ export const createEndpointExceptionList = () => rootRequest({ method: 'POST', url: '/api/endpoint_list', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); @@ -33,7 +33,7 @@ export const createExceptionList = ( name: exceptionList.name, type: exceptionList.type, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); @@ -66,7 +66,7 @@ export const createExceptionListItem = ( ], expire_time: exceptionListItem?.expire_time, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); @@ -77,7 +77,7 @@ export const createRuleExceptionItem = (ruleId: string, exceptionListItems: Rule body: { items: exceptionListItems, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); @@ -92,7 +92,7 @@ export const updateExceptionListItem = ( item_id: exceptionListItemId, ...exceptionListItemUpdate, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); @@ -100,6 +100,6 @@ export const deleteExceptionList = (listId: string, namespaceType: string) => rootRequest({ method: 'DELETE', url: `/api/exception_lists?list_id=${listId}&namespace_type=${namespaceType}`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/fleet.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/fleet.ts similarity index 74% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/fleet.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/fleet.ts index 57995a0645388..95647649259dc 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/fleet.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/fleet.ts @@ -25,13 +25,13 @@ const deleteAgentPolicies = () => { return rootRequest<{ items: Array<{ id: string }> }>({ method: 'GET', url: 'api/fleet/agent_policies', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }).then((response) => { response.body.items.forEach((item: { id: string }) => { rootRequest({ method: 'POST', url: `api/fleet/agent_policies/delete`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, body: { agentPolicyId: item.id, }, @@ -44,12 +44,12 @@ const deletePackagePolicies = () => { return rootRequest<{ items: Array<{ id: string }> }>({ method: 'GET', url: 'api/fleet/package_policies', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }).then((response) => { rootRequest({ method: 'POST', url: `api/fleet/package_policies/delete`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, body: { packagePolicyIds: response.body.items.map((item: { id: string }) => item.id), }, @@ -61,14 +61,17 @@ const deletePackages = () => { return rootRequest<{ items: Array<{ status: string; name: string; version: string }> }>({ method: 'GET', url: 'api/fleet/epm/packages', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }).then((response) => { response.body.items.forEach((item) => { if (item.status === 'installed') { rootRequest({ method: 'DELETE', url: `api/fleet/epm/packages/${item.name}/${item.version}`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + }, }); } }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/kibana_advanced_settings.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts similarity index 90% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/kibana_advanced_settings.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts index 6256539beca1d..f86cd0186c8c2 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/kibana_advanced_settings.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts @@ -12,7 +12,7 @@ const kibanaSettings = (body: Cypress.RequestBody) => { method: 'POST', url: 'internal/kibana/settings', body, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/notes.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/notes.ts similarity index 84% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/notes.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/notes.ts index 3efc24bc8083e..d1addc0407900 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/notes.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/notes.ts @@ -17,5 +17,5 @@ export const addNoteToTimeline = ( version: null, note: { note, timelineId }, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/prebuilt_rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/prebuilt_rules.ts similarity index 83% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/prebuilt_rules.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/prebuilt_rules.ts index 7242422355855..c11c1afb01404 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/prebuilt_rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/prebuilt_rules.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { ELASTIC_SECURITY_RULE_ID } from '../../../common/detection_engine/constants'; -import type { PrePackagedRulesStatusResponse } from '../../../public/detection_engine/rule_management/logic/types'; -import { getPrebuiltRuleWithExceptionsMock } from '../../../server/lib/detection_engine/prebuilt_rules/mocks'; +import { ELASTIC_SECURITY_RULE_ID } from '@kbn/security-solution-plugin/common/detection_engine/constants'; +import type { PrePackagedRulesStatusResponse } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types'; +import { getPrebuiltRuleWithExceptionsMock } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/mocks'; import { createRuleAssetSavedObject } from '../../helpers/rules'; export const getPrebuiltRulesStatus = () => { return cy.request({ method: 'GET', url: 'api/detection_engine/rules/prepackaged/_status', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; @@ -34,7 +34,7 @@ export const installAllPrebuiltRulesRequest = () => { return cy.request({ method: 'POST', url: 'internal/detection_engine/prebuilt_rules/installation/_perform', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, body: { mode: 'ALL_RULES', }, @@ -84,7 +84,11 @@ export const waitUntilAllRuleAssetsCreated = ( .request({ method: 'GET', url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_search`, - headers: { 'kbn-xsrf': 'cypress-creds', 'Content-Type': 'application/json' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + 'Content-Type': 'application/json', + }, failOnStatusCode: false, body: { query: { @@ -126,7 +130,11 @@ export const createNewRuleAsset = ({ .request({ method: 'PUT', url, - headers: { 'kbn-xsrf': 'cypress-creds', 'Content-Type': 'application/json' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + 'Content-Type': 'application/json', + }, failOnStatusCode: false, body: rule, }) @@ -166,6 +174,7 @@ export const bulkCreateRuleAssets = ({ }, headers: { 'Content-Type': 'application/json', + 'x-elastic-internal-origin': 'security-solution', }, }); @@ -175,7 +184,11 @@ export const bulkCreateRuleAssets = ({ .request({ method: 'POST', url, - headers: { 'kbn-xsrf': 'cypress-creds', 'Content-Type': 'application/json' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + 'Content-Type': 'application/json', + }, failOnStatusCode: false, body: bulkIndexRequestBody, }) @@ -190,7 +203,11 @@ export const getRuleAssets = (index: string | undefined = '.kibana_security_solu return cy.request({ method: 'GET', url, - headers: { 'kbn-xsrf': 'cypress-creds', 'Content-Type': 'application/json' }, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', + 'Content-Type': 'application/json', + }, failOnStatusCode: false, body: { query: { diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_engine.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_engine.ts similarity index 85% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_engine.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_engine.ts index 2564615f2ccda..7305bef6f0b88 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_engine.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_engine.ts @@ -10,7 +10,7 @@ export const deleteConfiguration = () => { method: 'GET', url: `/api/saved_objects/_find?type=risk-engine-configuration`, failOnStatusCode: false, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }).then((res) => { const savedObjectId = res?.body?.saved_objects?.[0]?.id; if (savedObjectId) { @@ -18,7 +18,7 @@ export const deleteConfiguration = () => { method: 'DELETE', url: `/api/saved_objects/risk-engine-configuration/${savedObjectId}`, failOnStatusCode: false, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); } }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/index.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/index.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/index.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/index.ts index 30c5b5fccefd1..5cadf80cf9674 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/index.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/index.ts @@ -298,7 +298,7 @@ export const installRiskScoreModule = () => { body: { riskScoreEntity: 'host', }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }) .its('status') .should('eql', 200); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/indices.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/indices.ts similarity index 81% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/indices.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/indices.ts index 680159d43156d..f31feb9229648 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/indices.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/indices.ts @@ -17,7 +17,7 @@ export const createIndex = (options: { method: 'put', url: `${INDICES_URL}/create`, body: options, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; @@ -29,7 +29,7 @@ export const deleteRiskScoreIndicies = (riskScoreEntity: RiskScoreEntity, spaceI body: { indices: [getPivotTransformIndex(riskScoreEntity, spaceId)], }, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }) .then(() => { @@ -39,7 +39,7 @@ export const deleteRiskScoreIndicies = (riskScoreEntity: RiskScoreEntity, spaceI body: { indices: [getLatestTransformIndex(riskScoreEntity, spaceId)], }, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/ingest_pipelines.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/ingest_pipelines.ts similarity index 79% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/ingest_pipelines.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/ingest_pipelines.ts index 818b0cf8d18fd..c438baf5c9273 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/ingest_pipelines.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/ingest_pipelines.ts @@ -11,7 +11,7 @@ export const createIngestPipeline = (options: { name: string; processors: Array< return cy.request({ method: 'post', url: `${INGEST_PIPELINES_URL}`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, body: options, }); }; @@ -20,7 +20,7 @@ export const deleteRiskScoreIngestPipelines = (names: string[]) => { return cy.request({ method: 'delete', url: `${INGEST_PIPELINES_URL}/${names.join(',')}`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/saved_objects.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/saved_objects.ts similarity index 83% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/saved_objects.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/saved_objects.ts index 3e96bbcd2cb2c..353e52fea53aa 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/saved_objects.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/saved_objects.ts @@ -17,7 +17,7 @@ export const deleteSavedObjects = (templateName: `${RiskScoreEntity}RiskScoreDas body: { deleteAll: true, }, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; @@ -30,7 +30,7 @@ export const findSavedObjects = (riskScoreEntity: RiskScoreEntity, spaceId = 'de .request({ method: 'get', url: `${SAVED_OBJECTS_URL}/_find?fields=id&type=tag&sort_field=updated_at&search=${search}&search_fields=name`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }) .then((res) => cy.request({ @@ -38,7 +38,7 @@ export const findSavedObjects = (riskScoreEntity: RiskScoreEntity, spaceId = 'de url: `${SAVED_OBJECTS_URL}/_find?fields=id&type=index-pattern&type=tag&type=visualization&type=dashboard&type=lens&sort_field=updated_at&has_reference=${getReference( res.body.saved_objects[0].id )}`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }) ); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/stored_scripts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/stored_scripts.ts similarity index 81% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/stored_scripts.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/stored_scripts.ts index de5a2b3616075..803673f351fc5 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/risk_scores/stored_scripts.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/risk_scores/stored_scripts.ts @@ -12,7 +12,7 @@ export const createStoredScript = (options: { id: string; script: {} }) => { method: 'put', url: `${STORED_SCRIPTS_URL}/create`, body: options, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; @@ -22,7 +22,7 @@ const deleteStoredScript = (id: string) => { url: `${STORED_SCRIPTS_URL}/delete`, body: { id }, failOnStatusCode: false, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/rules.ts similarity index 77% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/rules.ts index 6c87b812046dc..20551524d4340 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/rules.ts @@ -6,14 +6,17 @@ */ import moment from 'moment'; -import { rootRequest } from '../common'; import { DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_RULES_URL_FIND, -} from '../../../common/constants'; -import type { RuleCreateProps, RuleResponse } from '../../../common/api/detection_engine'; +} from '@kbn/security-solution-plugin/common/constants'; +import type { + RuleCreateProps, + RuleResponse, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import type { FetchRulesResponse } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types'; import { internalAlertingSnoozeRule } from '../../urls/routes'; -import type { FetchRulesResponse } from '../../../public/detection_engine/rule_management/logic/types'; +import { rootRequest } from '../common'; export const createRule = ( rule: RuleCreateProps @@ -22,7 +25,7 @@ export const createRule = ( method: 'POST', url: DETECTION_ENGINE_RULES_URL, body: rule, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }; @@ -43,7 +46,7 @@ export const snoozeRule = (id: string, duration: number): Cypress.Chainable => rRule: { dtstart: new Date().toISOString(), count: 1, tzid: moment().format('zz') }, }, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); @@ -51,7 +54,7 @@ export const deleteCustomRule = (ruleId = '1') => { rootRequest({ method: 'DELETE', url: `api/detection_engine/rules?rule_id=${ruleId}`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }; @@ -69,6 +72,7 @@ export const importRule = (ndjsonPath: string) => { headers: { 'kbn-xsrf': 'cypress-creds', 'content-type': 'multipart/form-data', + 'x-elastic-internal-origin': 'security-solution', }, body: formdata, }) @@ -83,6 +87,11 @@ export const waitForRulesToFinishExecution = (ruleIds: string[], afterDate?: Dat rootRequest({ method: 'GET', url: DETECTION_ENGINE_RULES_URL_FIND, + headers: { + 'kbn-xsrf': 'cypress-creds', + 'content-type': 'multipart/form-data', + 'x-elastic-internal-origin': 'security-solution', + }, }).then((response) => { const areAllRulesFinished = ruleIds.every((ruleId) => response.body.data.some((rule) => { diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/saved_queries.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/saved_queries.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/saved_queries.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/saved_queries.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/timelines.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts similarity index 86% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/timelines.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts index ab64ac02698ca..2f555e8a9ed9a 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/timelines.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/timelines.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { TimelineResponse } from '../../../common/api/timeline'; +import type { TimelineResponse } from '@kbn/security-solution-plugin/common/api/timeline'; import type { CompleteTimeline } from '../../objects/timeline'; import { rootRequest } from '../common'; @@ -53,7 +53,7 @@ export const createTimeline = (timeline: CompleteTimeline) => : {}), }, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); export const createTimelineTemplate = (timeline: CompleteTimeline) => @@ -99,14 +99,14 @@ export const createTimelineTemplate = (timeline: CompleteTimeline) => savedQueryId: null, }, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); export const loadPrepackagedTimelineTemplates = () => rootRequest({ method: 'POST', url: 'api/timeline/_prepackaged', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); export const favoriteTimeline = ({ @@ -129,5 +129,5 @@ export const favoriteTimeline = ({ templateTimelineId: templateTimelineId || null, templateTimelineVersion: templateTimelineVersion || null, }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/tour.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/tour.ts similarity index 77% rename from x-pack/plugins/security_solution/cypress/tasks/api_calls/tour.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/api_calls/tour.ts index ee17795a46d52..6b225f5027c6e 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/tour.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/tour.ts @@ -6,7 +6,7 @@ */ import { API_BASE_PATH } from '@kbn/guided-onboarding-plugin/common'; -import { siemGuideId } from '../../../common/guided_onboarding/siem_guide_config'; +import { siemGuideId } from '@kbn/security-solution-plugin/common/guided_onboarding/siem_guide_config'; const alertsGuideActiveState = { isActive: true, @@ -23,7 +23,7 @@ export const startAlertsCasesTour = () => cy.request({ method: 'PUT', url: `${API_BASE_PATH}/state`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, body: { status: 'in_progress', guide: alertsGuideActiveState, @@ -34,7 +34,7 @@ export const quitGlobalTour = () => cy.request({ method: 'PUT', url: `${API_BASE_PATH}/state`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, body: { status: 'quit', guide: { diff --git a/x-pack/plugins/security_solution/cypress/tasks/case_details.ts b/x-pack/test/security_solution_cypress/cypress/tasks/case_details.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/case_details.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/case_details.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/common.ts b/x-pack/test/security_solution_cypress/cypress/tasks/common.ts similarity index 94% rename from x-pack/plugins/security_solution/cypress/tasks/common.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/common.ts index fc6a7096e1814..a1a6cf8a476f8 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/common.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/common.ts @@ -7,11 +7,7 @@ import { DATA_VIEW_PATH, INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { - KIBANA_LOADING_ICON, - LOADING_INDICATOR, - LOADING_INDICATOR_HIDDEN, -} from '../screens/security_header'; +import { KIBANA_LOADING_ICON } from '../screens/security_header'; import { EUI_BASIC_TABLE_LOADING } from '../screens/common/controls'; const primaryButton = 0; @@ -112,7 +108,7 @@ export const deleteAlertsAndRules = () => { action: 'delete', }, failOnStatusCode: false, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, timeout: 300000, }); @@ -254,7 +250,8 @@ export const postDataView = (dataSource: string) => { }, }, headers: { - 'kbn-xsrf': 'cypress-creds-via-config', + 'kbn-xsrf': 'cypress-creds', + 'x-elastic-internal-origin': 'security-solution', [ELASTIC_HTTP_VERSION_HEADER]: [INITIAL_REST_VERSION], }, failOnStatusCode: false, @@ -265,18 +262,13 @@ export const deleteDataView = (dataSource: string) => { rootRequest({ method: 'DELETE', url: `api/data_views/data_view/${dataSource}`, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }; export const scrollToBottom = () => cy.scrollTo('bottom'); -export const waitForPageToBeLoaded = () => { - cy.get(LOADING_INDICATOR_HIDDEN).should('exist'); - cy.get(LOADING_INDICATOR).should('not.exist'); -}; - export const waitForWelcomePanelToBeLoaded = () => { cy.get(KIBANA_LOADING_ICON).should('exist'); cy.get(KIBANA_LOADING_ICON).should('not.exist'); diff --git a/x-pack/plugins/security_solution/cypress/tasks/common/callouts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/common/callouts.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/common/callouts.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/common/callouts.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/common/event_table.ts b/x-pack/test/security_solution_cypress/cypress/tasks/common/event_table.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/common/event_table.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/common/event_table.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/common/filter_group.ts b/x-pack/test/security_solution_cypress/cypress/tasks/common/filter_group.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/common/filter_group.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/common/filter_group.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/common/rule_actions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/common/rule_actions.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/common/rule_actions.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/common/rule_actions.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/configure_cases.ts b/x-pack/test/security_solution_cypress/cypress/tasks/configure_cases.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/configure_cases.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/configure_cases.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_case.ts b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_case.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/create_new_case.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/create_new_case.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts similarity index 99% rename from x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts index 1d33d2f169549..dabd0b89e4fb1 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts @@ -13,6 +13,15 @@ import type { ThreatSubtechnique, ThreatTechnique, } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { + EqlRuleCreateProps, + MachineLearningRuleCreateProps, + NewTermsRuleCreateProps, + QueryRuleCreateProps, + RuleCreateProps, + ThreatMatchRuleCreateProps, + ThresholdRuleCreateProps, +} from '@kbn/security-solution-plugin/common/api/detection_engine/model'; import type { Actions } from '../objects/types'; // For some reason importing these functions from ../../public/detections/pages/detection_engine/rules/helpers // causes a "Webpack Compilation Error" in this file specifically, even though it imports fine in the test files @@ -115,15 +124,6 @@ import { TIMELINE } from '../screens/timelines'; import { EUI_FILTER_SELECT_ITEM, COMBO_BOX_INPUT } from '../screens/common/controls'; import { ruleFields } from '../data/detection_engine'; import { BACK_TO_RULES_TABLE } from '../screens/rule_details'; -import type { - EqlRuleCreateProps, - MachineLearningRuleCreateProps, - NewTermsRuleCreateProps, - QueryRuleCreateProps, - RuleCreateProps, - ThreatMatchRuleCreateProps, - ThresholdRuleCreateProps, -} from '../../common/api/detection_engine/model'; import { waitForAlerts } from './alerts'; import { refreshPage } from './security_header'; import { EMPTY_ALERT_TABLE } from '../screens/alerts'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_runtime_field.ts b/x-pack/test/security_solution_cypress/cypress/tasks/create_runtime_field.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/create_runtime_field.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/create_runtime_field.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/dashboards/common.ts b/x-pack/test/security_solution_cypress/cypress/tasks/dashboards/common.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/dashboards/common.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/dashboards/common.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/date_picker.ts b/x-pack/test/security_solution_cypress/cypress/tasks/date_picker.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/date_picker.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/date_picker.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/edit_rule.ts b/x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/edit_rule.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/edit_rule.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/entity_analytics.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/exceptions.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/exceptions_table.ts b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions_table.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/exceptions_table.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/exceptions_table.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_analyzer_graph_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_entities_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_entities_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_entities_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_entities_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_investigation_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_investigation_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_investigation_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_investigation_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_prevalence_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_prevalence_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_prevalence_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_prevalence_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_response_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_response_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_response_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_response_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_threat_intelligence_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_preview_panel_rule_preview.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_preview_panel_rule_preview.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_preview_panel_rule_preview.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_preview_panel_rule_preview.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_right_panel.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_right_panel.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_right_panel_json_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_json_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_right_panel_json_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_json_tab.ts diff --git a/x-pack/plugins/security_solution/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 similarity index 98% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_right_panel_overview_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_overview_tab.ts index 90b040845812b..c87a3c2afb9fe 100644 --- a/x-pack/plugins/security_solution/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 @@ -10,7 +10,7 @@ import { INSIGHTS_ENTITIES_TITLE_LINK_TEST_ID, INSIGHTS_PREVALENCE_TITLE_LINK_TEST_ID, INSIGHTS_THREAT_INTELLIGENCE_TITLE_LINK_TEST_ID, -} from '../../../public/flyout/right/components/test_ids'; +} from '@kbn/security-solution-plugin/public/flyout/right/components/test_ids'; import { DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_HEADER, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_VISUALIZATIONS_SECTION_HEADER, diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel_table_tab.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/common.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/common.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/expandable_flyout/common.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/common.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/fields_browser.ts b/x-pack/test/security_solution_cypress/cypress/tasks/fields_browser.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/fields_browser.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/fields_browser.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/guided_onboarding.ts b/x-pack/test/security_solution_cypress/cypress/tasks/guided_onboarding.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/guided_onboarding.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/guided_onboarding.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/host_risk.ts b/x-pack/test/security_solution_cypress/cypress/tasks/host_risk.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/host_risk.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/host_risk.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/hosts/all_hosts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/hosts/all_hosts.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/hosts/all_hosts.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/hosts/all_hosts.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/hosts/events.ts b/x-pack/test/security_solution_cypress/cypress/tasks/hosts/events.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/hosts/events.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/hosts/events.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/hosts/main.ts b/x-pack/test/security_solution_cypress/cypress/tasks/hosts/main.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/hosts/main.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/hosts/main.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/hosts/uncommon_processes.ts b/x-pack/test/security_solution_cypress/cypress/tasks/hosts/uncommon_processes.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/hosts/uncommon_processes.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/hosts/uncommon_processes.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/inspect.ts b/x-pack/test/security_solution_cypress/cypress/tasks/inspect.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/inspect.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/inspect.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/integrations.ts b/x-pack/test/security_solution_cypress/cypress/tasks/integrations.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/integrations.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/integrations.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/kibana_navigation.ts b/x-pack/test/security_solution_cypress/cypress/tasks/kibana_navigation.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/kibana_navigation.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/kibana_navigation.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/lists.ts b/x-pack/test/security_solution_cypress/cypress/tasks/lists.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/tasks/lists.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/lists.ts index 1eee68fc38628..d160f4c2deb42 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/lists.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/lists.ts @@ -20,13 +20,17 @@ export const createListsIndex = () => { cy.request({ method: 'POST', url: '/api/lists/index', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }; export const waitForListsIndex = () => { - cy.request({ url: '/api/lists/index', retryOnStatusCodeFailure: true }).then((response) => { + cy.request({ + url: '/api/lists/index', + headers: { 'x-elastic-internal-origin': 'security-solution' }, + retryOnStatusCodeFailure: true, + }).then((response) => { if (response.status !== 200) { // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(7500); @@ -83,7 +87,7 @@ const deleteValueList = (list: string): Cypress.Chainable ({ const postRoleAndUser = (role: ROLES) => { const env = getCurlScriptEnvVars(); - const detectionsRoleScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/post_detections_role.sh`; - const detectionsRoleJsonPath = `./server/lib/detection_engine/scripts/roles_users/${role}/detections_role.json`; - const detectionsUserScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/post_detections_user.sh`; - const detectionsUserJsonPath = `./server/lib/detection_engine/scripts/roles_users/${role}/detections_user.json`; + const detectionsRoleScriptPath = `../../plugins/security_solution/server/lib/detection_engine/scripts/roles_users/${role}/post_detections_role.sh`; + const detectionsRoleJsonPath = `../../plugins/security_solution/server/lib/detection_engine/scripts/roles_users/${role}/detections_role.json`; + const detectionsUserScriptPath = `../../plugins/security_solution/server/lib/detection_engine/scripts/roles_users/${role}/post_detections_user.sh`; + const detectionsUserJsonPath = `../../plugins/security_solution/server/lib/detection_engine/scripts/roles_users/${role}/detections_user.json`; // post the role cy.exec(`bash ${detectionsRoleScriptPath} ${detectionsRoleJsonPath}`, { @@ -128,7 +127,7 @@ const postRoleAndUser = (role: ROLES) => { export const deleteRoleAndUser = (role: ROLES) => { const env = getCurlScriptEnvVars(); - const detectionsUserDeleteScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/delete_detections_user.sh`; + const detectionsUserDeleteScriptPath = `../../plugins/security_solution/server/lib/detection_engine/scripts/roles_users/${role}/delete_detections_user.sh`; // delete the role cy.exec(`bash ${detectionsUserDeleteScriptPath}`, { @@ -148,7 +147,10 @@ export const loginWithUser = (user: User) => { password: user.password, }, }, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-config', + 'x-elastic-internal-origin': 'security-solution', + }, method: 'POST', url: constructUrlWithUser(user, LOGIN_API_ENDPOINT), }); @@ -173,7 +175,10 @@ const loginWithRole = async (role: ROLES) => { password: 'changeme', }, }, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-config', + 'x-elastic-internal-origin': 'security-solution', + }, method: 'POST', url: getUrlWithRoute(role, LOGIN_API_ENDPOINT), }); @@ -231,7 +236,10 @@ const loginViaEnvironmentCredentials = () => { password, }, }, - headers: { 'kbn-xsrf': 'cypress-creds-via-env' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-env', + 'x-elastic-internal-origin': 'security-solution', + }, method: 'POST', url: `${Cypress.config().baseUrl}${LOGIN_API_ENDPOINT}`, }); @@ -263,7 +271,10 @@ const loginViaConfig = () => { password: config.elasticsearch.password, }, }, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-config', + 'x-elastic-internal-origin': 'security-solution', + }, method: 'POST', url: `${Cypress.config().baseUrl}${LOGIN_API_ENDPOINT}`, }); @@ -318,7 +329,6 @@ export const waitForPage = (url: string) => { cy.visit( `${url}?timerange=(global:(linkTo:!(timeline),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)))` ); - waitForPageToBeLoaded(); }; export const visit = (url: string, options: Partial = {}, role?: ROLES) => { @@ -356,21 +366,18 @@ export const visit = (url: string, options: Partial = {}, options.onLoad?.(win); }, }); - waitForPageToBeLoaded(); }; export const visitWithoutDateRange = (url: string, role?: ROLES) => { cy.visit(role ? getUrlWithRoute(role, url) : url, { onBeforeLoad: disableNewFeaturesTours, }); - waitForPageToBeLoaded(); }; export const visitWithUser = (url: string, user: User) => { cy.visit(constructUrlWithUser(user, url), { onBeforeLoad: disableNewFeaturesTours, }); - waitForPageToBeLoaded(); }; export const visitTimeline = (timelineId: string, role?: ROLES) => { @@ -378,7 +385,6 @@ export const visitTimeline = (timelineId: string, role?: ROLES) => { cy.visit(role ? getUrlWithRoute(role, route) : route, { onBeforeLoad: disableNewFeaturesTours, }); - waitForPageToBeLoaded(); }; export const visitHostDetailsPage = (hostName = 'suricata-iowa') => { @@ -393,7 +399,6 @@ export const visitUserDetailsPage = (userName = 'test') => { export const waitForPageWithoutDateRange = (url: string, role?: ROLES) => { cy.visit(role ? getUrlWithRoute(role, url) : url); - waitForPageToBeLoaded(); }; export const logout = () => { diff --git a/x-pack/plugins/security_solution/cypress/tasks/network/flows.ts b/x-pack/test/security_solution_cypress/cypress/tasks/network/flows.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/network/flows.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/network/flows.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/overview.ts b/x-pack/test/security_solution_cypress/cypress/tasks/overview.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/overview.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/overview.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/prebuilt_rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/prebuilt_rules.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/tasks/prebuilt_rules.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/prebuilt_rules.ts index bf9199aa1f81e..e6945c551c965 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/prebuilt_rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/prebuilt_rules.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RULES_ADD_PATH, RULES_UPDATES } from '../../common/constants'; +import { RULES_ADD_PATH, RULES_UPDATES } from '@kbn/security-solution-plugin/common/constants'; import { ADD_ELASTIC_RULES_BTN, ADD_ELASTIC_RULES_TABLE, diff --git a/x-pack/plugins/security_solution/cypress/tasks/privileges.ts b/x-pack/test/security_solution_cypress/cypress/tasks/privileges.ts similarity index 93% rename from x-pack/plugins/security_solution/cypress/tasks/privileges.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/privileges.ts index b0489b14e8a8e..19c056cfba8e3 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/privileges.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/privileges.ts @@ -188,7 +188,7 @@ export const createUsersAndRoles = (users: User[], roles: Role[]) => { cy.log(`Creating role: ${JSON.stringify(role)}`); cy.request({ body: role.privileges, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, method: 'PUT', url: constructUrlWithUser(envUser, `/api/security/role/${role.name}`), }) @@ -207,7 +207,7 @@ export const createUsersAndRoles = (users: User[], roles: Role[]) => { full_name: userInfo.full_name, email: userInfo.email, }, - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, method: 'POST', url: constructUrlWithUser(envUser, `/internal/security/users/${user.username}`), }) @@ -221,7 +221,7 @@ export const deleteUsersAndRoles = (users: User[], roles: Role[]) => { for (const user of users) { cy.log(`Deleting user: ${JSON.stringify(user)}`); cy.request({ - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, method: 'DELETE', url: constructUrlWithUser(envUser, `/internal/security/users/${user.username}`), failOnStatusCode: false, @@ -233,7 +233,7 @@ export const deleteUsersAndRoles = (users: User[], roles: Role[]) => { for (const role of roles) { cy.log(`Deleting role: ${JSON.stringify(role)}`); cy.request({ - headers: { 'kbn-xsrf': 'cypress-creds-via-config' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, method: 'DELETE', url: constructUrlWithUser(envUser, `/api/security/role/${role.name}`), failOnStatusCode: false, diff --git a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/common.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/common.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/risk_scores/common.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/common.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/index.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/index.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/risk_scores/index.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/index.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/indices.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/indices.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/risk_scores/indices.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/indices.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/ingest_pipelines.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/ingest_pipelines.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/risk_scores/ingest_pipelines.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/ingest_pipelines.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/saved_objects.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/saved_objects.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/risk_scores/saved_objects.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/saved_objects.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/stored_scripts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/stored_scripts.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/risk_scores/stored_scripts.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/stored_scripts.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/transforms.ts b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/transforms.ts similarity index 91% rename from x-pack/plugins/security_solution/cypress/tasks/risk_scores/transforms.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/transforms.ts index 334607acc4da2..8e04a4a5ac557 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/risk_scores/transforms.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/risk_scores/transforms.ts @@ -35,7 +35,11 @@ export const getTransformState = (transformId: string) => { return cy.request<{ transforms: Array<{ id: string; state: string }>; count: number }>({ method: 'get', url: `${TRANSFORMS_URL}/transforms/${transformId}/_stats`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config', [ELASTIC_HTTP_VERSION_HEADER]: '1' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-config', + 'x-elastic-internal-origin': 'security-solution', + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, }); }; @@ -43,7 +47,11 @@ export const startTransforms = (transformIds: string[]) => { return cy.request({ method: 'post', url: `${TRANSFORMS_URL}/start_transforms`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config', [ELASTIC_HTTP_VERSION_HEADER]: '1' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-config', + 'x-elastic-internal-origin': 'security-solution', + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, body: transformIds.map((id) => ({ id, })), @@ -57,7 +65,11 @@ const stopTransform = (state: { return cy.request({ method: 'post', url: `${TRANSFORMS_URL}/stop_transforms`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config', [ELASTIC_HTTP_VERSION_HEADER]: '1' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-config', + 'x-elastic-internal-origin': 'security-solution', + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, body: state != null && state.transforms.length > 0 ? [ @@ -74,7 +86,11 @@ export const createTransform = (transformId: string, options: string | Record { return cy.request({ method: 'post', url: `${TRANSFORMS_URL}/delete_transforms`, - headers: { 'kbn-xsrf': 'cypress-creds-via-config', [ELASTIC_HTTP_VERSION_HEADER]: '1' }, + headers: { + 'kbn-xsrf': 'cypress-creds-via-config', + 'x-elastic-internal-origin': 'security-solution', + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, failOnStatusCode: false, body: { transformsInfo: [ diff --git a/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts b/x-pack/test/security_solution_cypress/cypress/tasks/rule_details.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/rule_details.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/rule_details.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/rule_filters.ts b/x-pack/test/security_solution_cypress/cypress/tasks/rule_filters.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/rule_filters.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/rule_filters.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/rule_snoozing.ts b/x-pack/test/security_solution_cypress/cypress/tasks/rule_snoozing.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/rule_snoozing.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/rule_snoozing.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_actions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/rules_bulk_actions.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/rules_bulk_actions.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/rules_bulk_actions.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/saved_objects.ts b/x-pack/test/security_solution_cypress/cypress/tasks/saved_objects.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/saved_objects.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/saved_objects.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/search_bar.ts b/x-pack/test/security_solution_cypress/cypress/tasks/search_bar.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/search_bar.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/search_bar.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/security_header.ts b/x-pack/test/security_solution_cypress/cypress/tasks/security_header.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/security_header.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/security_header.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/security_main.ts b/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/security_main.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/sourcerer.ts b/x-pack/test/security_solution_cypress/cypress/tasks/sourcerer.ts similarity index 96% rename from x-pack/plugins/security_solution/cypress/tasks/sourcerer.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/sourcerer.ts index 00fa6b1152201..131a22fd24a74 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/sourcerer.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/sourcerer.ts @@ -5,11 +5,11 @@ * 2.0. */ +import { DEFAULT_ALERTS_INDEX } from '@kbn/security-solution-plugin/common/constants'; import { HOSTS_STAT, SOURCERER } from '../screens/sourcerer'; import { HOSTS_URL } from '../urls/navigation'; import { visit, waitForPage } from './login'; import { openTimelineUsingToggle } from './security_main'; -import { DEFAULT_ALERTS_INDEX } from '../../common/constants'; import { rootRequest } from './common'; export const openSourcerer = (sourcererScope?: string) => { @@ -137,7 +137,7 @@ export const deleteRuntimeField = (dataView: string, fieldName: string) => { rootRequest({ url: deleteRuntimeFieldPath, method: 'DELETE', - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, failOnStatusCode: false, }); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/table_pagination.ts b/x-pack/test/security_solution_cypress/cypress/tasks/table_pagination.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/table_pagination.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/table_pagination.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/templates.ts b/x-pack/test/security_solution_cypress/cypress/tasks/templates.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/templates.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/templates.ts diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts similarity index 98% rename from x-pack/plugins/security_solution/cypress/tasks/timeline.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts index 05d08ba9702bf..fbec4a495d0fe 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts @@ -336,9 +336,9 @@ export const deleteTimeline = () => { }; export const markAsFavorite = () => { - cy.get(STAR_ICON).should('be.visible').click(); - cy.get(LOADING_INDICATOR).should('exist'); - cy.get(LOADING_INDICATOR).should('not.exist'); + cy.intercept('PATCH', 'api/timeline/_favorite').as('markedAsFavourite'); + cy.get(STAR_ICON).click({ force: true }); + cy.wait('@markedAsFavourite'); }; export const openTimelineFieldsBrowser = () => { @@ -473,7 +473,10 @@ export const setKibanaTimezoneToUTC = () => method: 'POST', url: 'internal/kibana/settings', body: { changes: { 'dateFormat:tz': 'UTC' } }, - headers: { 'kbn-xsrf': 'set-kibana-timezone-utc' }, + headers: { + 'kbn-xsrf': 'set-kibana-timezone-utc', + 'x-elastic-internal-origin': 'security-solution', + }, }) .then(() => { cy.reload(); diff --git a/x-pack/plugins/security_solution/cypress/tasks/timelines.ts b/x-pack/test/security_solution_cypress/cypress/tasks/timelines.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/tasks/timelines.ts rename to x-pack/test/security_solution_cypress/cypress/tasks/timelines.ts diff --git a/x-pack/plugins/security_solution/cypress/tsconfig.json b/x-pack/test/security_solution_cypress/cypress/tsconfig.json similarity index 91% rename from x-pack/plugins/security_solution/cypress/tsconfig.json rename to x-pack/test/security_solution_cypress/cypress/tsconfig.json index 7d674e03fcf4c..8ee21e233a223 100644 --- a/x-pack/plugins/security_solution/cypress/tsconfig.json +++ b/x-pack/test/security_solution_cypress/cypress/tsconfig.json @@ -25,7 +25,7 @@ // in a way that can't be auto-matically deteceted at this time // so we have to force the inclusion of this reference { - "path": "../tsconfig.json", + "path": "../../../plugins/security_solution/tsconfig.json", "force": true }, "@kbn/rison", @@ -42,5 +42,6 @@ "@kbn/tooling-log", "@kbn/fleet-plugin", "@kbn/cases-components", + "@kbn/security-solution-plugin", ] } diff --git a/x-pack/plugins/security_solution/cypress/urls/ml_conditional_links.ts b/x-pack/test/security_solution_cypress/cypress/urls/ml_conditional_links.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/urls/ml_conditional_links.ts rename to x-pack/test/security_solution_cypress/cypress/urls/ml_conditional_links.ts diff --git a/x-pack/plugins/security_solution/cypress/urls/navigation.ts b/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/urls/navigation.ts rename to x-pack/test/security_solution_cypress/cypress/urls/navigation.ts diff --git a/x-pack/plugins/security_solution/cypress/urls/risk_score.ts b/x-pack/test/security_solution_cypress/cypress/urls/risk_score.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/urls/risk_score.ts rename to x-pack/test/security_solution_cypress/cypress/urls/risk_score.ts diff --git a/x-pack/plugins/security_solution/cypress/urls/routes.ts b/x-pack/test/security_solution_cypress/cypress/urls/routes.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/urls/routes.ts rename to x-pack/test/security_solution_cypress/cypress/urls/routes.ts diff --git a/x-pack/plugins/security_solution/cypress/urls/state.ts b/x-pack/test/security_solution_cypress/cypress/urls/state.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/urls/state.ts rename to x-pack/test/security_solution_cypress/cypress/urls/state.ts diff --git a/x-pack/test/security_solution_cypress/package.json b/x-pack/test/security_solution_cypress/package.json new file mode 100644 index 0000000000000..741205b8f7771 --- /dev/null +++ b/x-pack/test/security_solution_cypress/package.json @@ -0,0 +1,26 @@ +{ + "author": "Elastic", + "name": "@kbn/security-solution-plugin", + "version": "1.0.0", + "private": true, + "license": "Elastic License 2.0", + "scripts": { + "cypress": "../../../node_modules/.bin/cypress", + "cypress:open:ess": "TZ=UTC node ../../plugins/security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ../../test/security_solution_cypress/cypress/cypress.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config", + "cypress:run:ess": "yarn cypress:ess --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --browser chrome --spec './cypress/e2e/{,!(investigations,explore)/**/}*.cy.ts'; status=$?; yarn junit:merge && exit $status", + "cypress:run:cases:ess": "yarn cypress:ess --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --browser chrome --spec './cypress/e2e/explore/cases/*.cy.ts' --ftr-config-file ../../test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", + "cypress:ess": "TZ=UTC node ../../plugins/security_solution/scripts/start_cypress_parallel run --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json", + "cypress:run:respops:ess": "yarn cypress:ess --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --browser chrome --spec './cypress/e2e/(detection_alerts|detection_rules|exceptions)/*.cy.ts' --ftr-config-file ../../test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", + "cypress:investigations:run:ess": "yarn cypress:ess --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --browser chrome --spec './cypress/e2e/investigations/**/*.cy.ts' --ftr-config-file ../../test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", + "cypress:explore:run:ess": "yarn cypress:ess --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --browser chrome --spec './cypress/e2e/explore/**/*.cy.ts' --ftr-config-file ../../test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", + "cypress:changed-specs-only:ess": "yarn cypress:ess --changed-specs-only --env burn=2", + "junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-security-solution/cypress/results/mochawesome*.json > ../../../target/kibana-security-solution/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-security-solution/cypress/results/output.json --reportDir ../../../target/kibana-security-solution/cypress/results && yarn junit:transform && mkdir -p ../../../target/junit && cp ../../../target/kibana-security-solution/cypress/results/*.xml ../../../target/junit/", + "junit:transform": "node ../../plugins/security_solution/scripts/junit_transformer --pathPattern '../../../target/kibana-security-solution/cypress/results/*.xml' --rootDirectory ../../../ --reportName 'Security Solution Cypress' --writeInPlace", + "cypress:serverless": "TZ=UTC node ../../plugins/security_solution/scripts/start_cypress_parallel --config-file ../../test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts --ftr-config-file ../../test/security_solution_cypress/serverless_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json", + "cypress:open:serverless": "yarn cypress:serverless open --config-file ../../test/security_solution_cypress/cypress/cypress_serverless.config.ts --spec './cypress/e2e/**/*.cy.ts'", + "cypress:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/{,!(investigations,explore)/**/}*.cy.ts'; status=$?; yarn junit:merge && exit $status", + "cypress:investigations:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/investigations/**/*.cy.ts'; status=$?; yarn junit:merge && exit $status", + "cypress:explore:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/explore/**/*.cy.ts'; status=$?; yarn junit:merge && exit $status", + "cypress:changed-specs-only:serverless": "yarn cypress:serverless --changed-specs-only --env burn=2" + } + } diff --git a/x-pack/test/security_solution_cypress/serverless_config.ts b/x-pack/test/security_solution_cypress/serverless_config.ts new file mode 100644 index 0000000000000..b2917f829384f --- /dev/null +++ b/x-pack/test/security_solution_cypress/serverless_config.ts @@ -0,0 +1,38 @@ +/* + * 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 { FtrConfigProviderContext } from '@kbn/test'; +import { SecuritySolutionConfigurableCypressTestRunner } from './runner'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const svlSharedConfig = await readConfigFile( + require.resolve('../../test_serverless/shared/config.base.ts') + ); + + return { + ...svlSharedConfig.getAll(), + esTestCluster: { + ...svlSharedConfig.get('esTestCluster'), + serverArgs: [ + ...svlSharedConfig.get('esTestCluster.serverArgs'), + // define custom es server here + // API Keys is enabled at the top level + ], + }, + kbnTestServer: { + ...svlSharedConfig.get('kbnTestServer'), + serverArgs: [ + ...svlSharedConfig.get('kbnTestServer.serverArgs'), + '--csp.strict=false', + '--csp.warnLegacyBrowsers=false', + '--serverless=security', + '--xpack.encryptedSavedObjects.encryptionKey="abcdefghijklmnopqrstuvwxyz123456"', + ], + }, + testRunner: SecuritySolutionConfigurableCypressTestRunner, + }; +} diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 7992cf9ba2504..efe7ea1f5e8f8 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -18,7 +18,7 @@ "../../typings/**/*", "../../packages/kbn-test/types/ftr_globals/**/*" ], - "exclude": ["target/**/*", "*/plugins/**/*", "*/packages/**/*", "*/*/packages/**/*"], + "exclude": ["security_solution_cypress/cypress/**/*", "target/**/*", "*/plugins/**/*", "*/packages/**/*", "*/*/packages/**/*" ], "kbn_references": [ { "path": "../../test/tsconfig.json" }, "@kbn/core", @@ -138,7 +138,7 @@ "@kbn/ml-category-validator", "@kbn/observability-ai-assistant-plugin", "@kbn/stack-connectors-plugin", + "@kbn/aiops-utils", "@kbn/stack-alerts-plugin", - "@kbn/aiops-utils" ] }