From 6d3449162d2278cfe3544cc1d643c006486139b5 Mon Sep 17 00:00:00 2001 From: Yara Tercero Date: Fri, 13 Oct 2023 12:34:58 -0700 Subject: [PATCH] [Detection Engine][Cypress] Reenable and reorganize some detection_alerts and data_sources tests (#168426) ## Summary #### Code update: `/detection_engine/routes/signals/set_alert_tags_route.ts` - When enabling the alert tags cypress test, noticed it was failing as the tag updates did not show in the UI until a few seconds later upon a second refresh. I was able to recreate this locally on serverless, not on ESS. I updated the alerts tag route to include `refresh: true` and that seemed to fix this issue. - `/detection_engine/routes/signals/open_close_signals_route.ts` - When testing on serverless, alert status was stale after update. Confirmed this with tests that were failing for ESS. Upon updating route to use `refresh: true`, tests began passing and could see expected behavior. This may make the call a bit heavier so we will want to see if there are any performance impacts. --- .buildkite/pipelines/pull_request/base.yml | 2 +- .github/CODEOWNERS | 5 +- .../signals/open_close_signals_route.ts | 4 +- .../routes/signals/set_alert_tags_route.ts | 2 +- .../data_sources/create_runtime_field.cy.ts | 63 --- .../cypress/e2e/data_sources/sourcerer.cy.ts | 136 ------- .../e2e/data_sources/sourcerer_timeline.ts | 169 -------- .../detection_alerts/cti_enrichments.cy.ts | 197 --------- .../ransomware_detection.cy.ts | 73 ---- .../ransomware_prevention.cy.ts | 79 ---- .../detection_alerts/alert_status.cy.ts | 230 +++++++++++ .../detection_alerts/alert_tags.cy.ts | 21 +- ...ts_detection_callouts_index_outdated.cy.ts | 19 +- .../missing_privileges_callout.cy.ts | 20 +- .../threat_match_enrichments.cy.ts | 201 +++++++++ .../sourcerer/create_runtime_field.cy.ts | 58 +++ .../sourcerer/sourcerer.cy.ts | 115 ++++++ .../sourcerer/sourcerer_permissions.cy.ts | 36 ++ .../sourcerer}/sourcerer_timeline.cy.ts | 18 +- .../value_lists/permissions.cy.ts | 23 ++ .../value_lists/value_lists.cy.ts | 385 ++++++++---------- .../enrichments.cy.ts | 0 .../alerts}/alerts_charts.cy.ts | 20 +- .../alerts/ransomware_detection.cy.ts | 68 ++++ .../alerts/ransomware_prevention.cy.ts | 74 ++++ .../cypress/tasks/alerts.ts | 6 + 26 files changed, 1043 insertions(+), 981 deletions(-) delete mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/data_sources/create_runtime_field.cy.ts delete mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer.cy.ts delete mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer_timeline.ts delete mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/cti_enrichments.cy.ts delete mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_detection.cy.ts delete mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts rename x-pack/test/security_solution_cypress/cypress/e2e/{ => detection_response}/detection_alerts/alert_tags.cy.ts (83%) rename x-pack/test/security_solution_cypress/cypress/e2e/{ => detection_response}/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts (91%) rename x-pack/test/security_solution_cypress/cypress/e2e/{ => detection_response}/detection_alerts/missing_privileges_callout.cy.ts (88%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/threat_match_enrichments.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts rename x-pack/test/security_solution_cypress/cypress/e2e/{data_sources => detection_response/sourcerer}/sourcerer_timeline.cy.ts (92%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts rename x-pack/test/security_solution_cypress/cypress/e2e/{detection_alerts => entity_analytics}/enrichments.cy.ts (100%) rename x-pack/test/security_solution_cypress/cypress/e2e/{detection_alerts => investigations/alerts}/alerts_charts.cy.ts (79%) create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts create mode 100644 x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index fd47dd6c08225..abc6436e7ee0a 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -63,7 +63,7 @@ steps: queue: n2-4-spot depends_on: build timeout_in_minutes: 60 - parallelism: 2 + parallelism: 4 retry: automatic: - exit_status: '*' diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fb5ce6ad466e0..ccb65e643d219 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1159,6 +1159,7 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/common/types/timeline @elastic/security-threat-hunting-investigations /x-pack/test/security_solution_cypress/cypress/e2e/investigations @elastic/security-threat-hunting-investigations +/x-pack/test/security_solution_cypress/cypress/e2e/sourcerer/sourcerer_timeline.cy.ts @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 @@ -1297,8 +1298,8 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals @elastic/security-detection-engine /x-pack/plugins/security_solution/server/lib/sourcerer @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_alerts @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer @elastic/security-detection-engine +/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts @elastic/security-detection-engine /x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions @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/rule_edit @elastic/security-detection-engine diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts index c3060fcc93b88..ce6e19d4706fe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts @@ -131,7 +131,7 @@ const updateSignalsStatusByIds = async ( ) => esClient.updateByQuery({ index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`, - refresh: false, + refresh: true, body: { script: getUpdateSignalStatusScript(status), query: { @@ -158,7 +158,7 @@ const updateSignalsStatusByQuery = async ( esClient.updateByQuery({ index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`, conflicts: options.conflicts, - refresh: false, + refresh: true, body: { script: getUpdateSignalStatusScript(status), query: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts index 36d3e57169cce..8b7e81f9bf812 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts @@ -100,7 +100,7 @@ export const setAlertTagsRoute = (router: SecuritySolutionPluginRouter) => { try { const body = await esClient.updateByQuery({ index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`, - refresh: false, + refresh: true, body: { script: painlessScript, query: { diff --git a/x-pack/test/security_solution_cypress/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 deleted file mode 100644 index 78ed47f878665..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/create_runtime_field.cy.ts +++ /dev/null @@ -1,63 +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 { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; -import { openTimelineUsingToggle } from '../../tasks/security_main'; -import { openTimelineFieldsBrowser, populateTimeline } from '../../tasks/timeline'; - -import { hostsUrl, ALERTS_URL } from '../../urls/navigation'; - -import { createRule } from '../../tasks/api_calls/rules'; - -import { getNewRule } from '../../objects/rule'; -import { refreshPage } from '../../tasks/security_header'; -import { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; -import { createField } from '../../tasks/create_runtime_field'; -import { openAlertsFieldBrowser } from '../../tasks/alerts'; -import { deleteRuntimeField } from '../../tasks/sourcerer'; -import { GET_DATA_GRID_HEADER } from '../../screens/common/data_grid'; -import { GET_TIMELINE_HEADER } from '../../screens/timeline'; - -const alertRunTimeField = 'field.name.alert.page'; -const timelineRuntimeField = 'field.name.timeline'; - -// TODO: https://github.com/elastic/kibana/issues/161539 -describe( - 'Create DataView runtime field', - { tags: ['@ess', '@serverless', '@brokenInServerless'] }, - () => { - before(() => { - deleteRuntimeField('security-solution-default', alertRunTimeField); - deleteRuntimeField('security-solution-default', timelineRuntimeField); - }); - - beforeEach(() => { - login(); - }); - - it('adds field to alert table', () => { - visitWithTimeRange(ALERTS_URL); - createRule(getNewRule()); - refreshPage(); - waitForAlertsToPopulate(); - openAlertsFieldBrowser(); - createField(alertRunTimeField); - cy.get(GET_DATA_GRID_HEADER(alertRunTimeField)).should('exist'); - }); - - it('adds field to timeline', () => { - visitWithTimeRange(hostsUrl('allHosts')); - openTimelineUsingToggle(); - populateTimeline(); - openTimelineFieldsBrowser(); - - createField(timelineRuntimeField); - cy.get(GET_TIMELINE_HEADER(timelineRuntimeField)).should('exist'); - }); - } -); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer.cy.ts deleted file mode 100644 index 0d70bf4dcd3d1..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer.cy.ts +++ /dev/null @@ -1,136 +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 { DEFAULT_INDEX_PATTERN } from '@kbn/security-solution-plugin/common/constants'; - -import { login, loginWithUser } from '../../tasks/login'; -import { visitWithTimeRange, visitWithUser } from '../../tasks/navigation'; - -import { hostsUrl } from '../../urls/navigation'; -import { - addIndexToDefault, - deselectSourcererOptions, - isDataViewSelection, - isHostsStatValue, - isKibanaDataViewOption, - isNotSourcererSelection, - isSourcererOptions, - isSourcererSelection, - openAdvancedSettings, - openDataViewSelection, - openSourcerer, - resetSourcerer, - saveSourcerer, -} from '../../tasks/sourcerer'; -import { postDataView } from '../../tasks/common'; -import { createUsersAndRoles, secReadCasesAll, secReadCasesAllUser } from '../../tasks/privileges'; -import { TOASTER } from '../../screens/configure_cases'; -import { SOURCERER } from '../../screens/sourcerer'; - -const usersToCreate = [secReadCasesAllUser]; -const rolesToCreate = [secReadCasesAll]; -const siemDataViewTitle = 'Security Default Data View'; -const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*']; - -// TODO: https://github.com/elastic/kibana/issues/161539 -describe('Sourcerer', { tags: ['@ess', '@serverless', '@skipInServerless'] }, () => { - before(() => { - cy.task('esArchiverResetKibana'); - dataViews.forEach((dataView: string) => postDataView(dataView)); - }); - - // TODO: https://github.com/elastic/kibana/issues/161539 - describe('permissions', { tags: ['@ess', '@brokenInServerless'] }, () => { - before(() => { - createUsersAndRoles(usersToCreate, rolesToCreate); - }); - it(`role(s) ${secReadCasesAllUser.roles.join()} shows error when user does not have permissions`, () => { - loginWithUser(secReadCasesAllUser); - visitWithUser(hostsUrl('allHosts'), secReadCasesAllUser); - cy.get(TOASTER).should('have.text', 'Write role required to generate data'); - }); - }); - - // TODO: https://github.com/elastic/kibana/issues/161539 - // FLAKY: https://github.com/elastic/kibana/issues/165766 - describe('Default scope', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { - beforeEach(() => { - cy.clearLocalStorage(); - login(); - visitWithTimeRange(hostsUrl('allHosts')); - }); - - it('correctly loads SIEM data view', () => { - openSourcerer(); - isDataViewSelection(siemDataViewTitle); - openAdvancedSettings(); - isSourcererSelection(`auditbeat-*`); - isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*')); - }); - - describe('Modified badge', () => { - it('Selecting new data view does not add a modified badge', () => { - cy.get(SOURCERER.badgeModified).should(`not.exist`); - openSourcerer(); - cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); - openDataViewSelection(); - isKibanaDataViewOption(dataViews); - cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle); - cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click(); - isDataViewSelection(dataViews[1]); - saveSourcerer(); - cy.get(SOURCERER.badgeModified).should(`not.exist`); - openSourcerer(); - cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); - }); - - it('shows modified badge when index patterns change and removes when reset', () => { - openSourcerer(); - openDataViewSelection(); - cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click(); - isDataViewSelection(dataViews[1]); - openAdvancedSettings(); - const patterns = dataViews[1].split(','); - deselectSourcererOptions([patterns[0]]); - saveSourcerer(); - cy.get(SOURCERER.badgeModified).should(`exist`); - openSourcerer(); - cy.get(SOURCERER.badgeModifiedOption).should(`exist`); - resetSourcerer(); - saveSourcerer(); - cy.get(SOURCERER.badgeModified).should(`not.exist`); - openSourcerer(); - cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); - isDataViewSelection(siemDataViewTitle); - }); - }); - - it('disables save when no patterns are selected', () => { - openSourcerer(); - openAdvancedSettings(); - cy.get(SOURCERER.saveButton).should('be.enabled'); - deselectSourcererOptions(['auditbeat-*']); - cy.get(SOURCERER.saveButton).should('be.disabled'); - }); - - it( - 'adds a pattern to the default index and correctly filters out auditbeat-*', - { tags: '@brokenInServerless' }, - () => { - openSourcerer(); - isSourcererSelection(`auditbeat-*`); - isNotSourcererSelection('*beat*'); - addIndexToDefault('*beat*'); - isHostsStatValue('1'); - openSourcerer(); - openAdvancedSettings(); - isSourcererSelection(`auditbeat-*`); - isSourcererSelection('*beat*'); - } - ); - }); -}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer_timeline.ts b/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer_timeline.ts deleted file mode 100644 index 4267944740539..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer_timeline.ts +++ /dev/null @@ -1,169 +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 { - DEFAULT_ALERTS_INDEX, - DEFAULT_INDEX_PATTERN, -} from '@kbn/security-solution-plugin/common/constants'; - -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; - -import { TIMELINES_URL } from '../../urls/navigation'; -import { - clickAlertCheckbox, - deselectSourcererOptions, - isDataViewSelection, - isKibanaDataViewOption, - isNotSourcererOption, - isNotSourcererSelection, - isSourcererOptions, - isSourcererSelection, - openAdvancedSettings, - openDataViewSelection, - openSourcerer, - refreshUntilAlertsIndexExists, - resetSourcerer, - saveSourcerer, -} from '../../tasks/sourcerer'; -import { openTimelineUsingToggle } from '../../tasks/security_main'; -import { SOURCERER } from '../../screens/sourcerer'; -import { createTimeline } from '../../tasks/api_calls/timelines'; -import { getTimeline, getTimelineModifiedSourcerer } from '../../objects/timeline'; -import { closeTimeline, openTimelineById } from '../../tasks/timeline'; - -const siemDataViewTitle = 'Security Default Data View'; -const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*']; - -// TODO: https://github.com/elastic/kibana/issues/161539 -describe('Timeline scope', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { - beforeEach(() => { - cy.clearLocalStorage(); - login(); - visitWithTimeRange(TIMELINES_URL); - }); - - it('correctly loads SIEM data view', () => { - openTimelineUsingToggle(); - openSourcerer('timeline'); - isDataViewSelection(siemDataViewTitle); - openAdvancedSettings(); - isSourcererSelection(`auditbeat-*`); - isSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`); - isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*')); - isNotSourcererOption(`${DEFAULT_ALERTS_INDEX}-default`); - }); - - describe('Modified badge', () => { - it('Selecting new data view does not add a modified badge', () => { - openTimelineUsingToggle(); - cy.get(SOURCERER.badgeModified).should(`not.exist`); - openSourcerer('timeline'); - cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); - openDataViewSelection(); - isKibanaDataViewOption(dataViews); - cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle); - cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click(); - isDataViewSelection(dataViews[1]); - saveSourcerer(); - cy.get(SOURCERER.badgeModified).should(`not.exist`); - openSourcerer('timeline'); - cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); - }); - - it('shows modified badge when index patterns change and removes when reset', () => { - openTimelineUsingToggle(); - openSourcerer('timeline'); - openDataViewSelection(); - cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click(); - isDataViewSelection(dataViews[1]); - openAdvancedSettings(); - const patterns = dataViews[1].split(','); - deselectSourcererOptions([patterns[0]]); - saveSourcerer(); - cy.get(SOURCERER.badgeModified).should(`exist`); - openSourcerer('timeline'); - cy.get(SOURCERER.badgeModifiedOption).should(`exist`); - resetSourcerer(); - saveSourcerer(); - cy.get(SOURCERER.badgeModified).should(`not.exist`); - openSourcerer('timeline'); - cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); - isDataViewSelection(siemDataViewTitle); - }); - }); - describe('Alerts checkbox', () => { - before(() => { - login(); - createTimeline(getTimeline()).then((response) => - cy.wrap(response.body.data.persistTimeline.timeline.savedObjectId).as('timelineId') - ); - createTimeline(getTimelineModifiedSourcerer()).then((response) => - cy.wrap(response.body.data.persistTimeline.timeline.savedObjectId).as('auditbeatTimelineId') - ); - }); - - beforeEach(() => { - login(); - visitWithTimeRange(TIMELINES_URL); - refreshUntilAlertsIndexExists(); - }); - - it('Modifies timeline to alerts only, and switches to different saved timeline without issue', function () { - openTimelineById(this.timelineId).then(() => { - cy.get(SOURCERER.badgeAlerts).should(`not.exist`); - cy.get(SOURCERER.badgeModified).should(`not.exist`); - openSourcerer('timeline'); - clickAlertCheckbox(); - saveSourcerer(); - cy.get(SOURCERER.badgeAlerts).should(`exist`); - cy.get(SOURCERER.badgeModified).should(`not.exist`); - closeTimeline(); - - openTimelineById(this.auditbeatTimelineId).then(() => { - cy.get(SOURCERER.badgeModified).should(`exist`); - cy.get(SOURCERER.badgeAlerts).should(`not.exist`); - openSourcerer('timeline'); - openAdvancedSettings(); - isSourcererSelection(`auditbeat-*`); - }); - }); - }); - - const defaultPatterns = [`auditbeat-*`, `${DEFAULT_ALERTS_INDEX}-default`]; - it('alerts checkbox behaves as expected', () => { - isDataViewSelection(siemDataViewTitle); - defaultPatterns.forEach((pattern) => isSourcererSelection(pattern)); - openDataViewSelection(); - cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click(); - isDataViewSelection(dataViews[1]); - dataViews[1] - .split(',') - .filter((pattern) => pattern !== 'fakebeat-*' && pattern !== 'siem-read*') - .forEach((pattern) => isSourcererSelection(pattern)); - - clickAlertCheckbox(); - isNotSourcererSelection(`auditbeat-*`); - isSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`); - cy.get(SOURCERER.alertCheckbox).uncheck({ force: true }); - defaultPatterns.forEach((pattern) => isSourcererSelection(pattern)); - }); - - it('shows alerts badge when index patterns change and removes when reset', () => { - clickAlertCheckbox(); - saveSourcerer(); - cy.get(SOURCERER.badgeAlerts).should(`exist`); - openSourcerer('timeline'); - cy.get(SOURCERER.badgeAlertsOption).should(`exist`); - resetSourcerer(); - saveSourcerer(); - cy.get(SOURCERER.badgeAlerts).should(`not.exist`); - openSourcerer('timeline'); - cy.get(SOURCERER.badgeAlertsOption).should(`not.exist`); - }); - }); -}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/cti_enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/cti_enrichments.cy.ts deleted file mode 100644 index 04de2c6ac6b35..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/cti_enrichments.cy.ts +++ /dev/null @@ -1,197 +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 { disableExpandableFlyout } from '../../tasks/api_calls/kibana_advanced_settings'; -import { getNewThreatIndicatorRule, indicatorRuleMatchingDoc } from '../../objects/rule'; -import { cleanKibana } from '../../tasks/common'; -import { login } from '../../tasks/login'; -import { - JSON_TEXT, - TABLE_CELL, - TABLE_ROWS, - THREAT_DETAILS_VIEW, - ENRICHMENT_COUNT_NOTIFICATION, - INDICATOR_MATCH_ENRICHMENT_SECTION, - INVESTIGATION_TIME_ENRICHMENT_SECTION, - THREAT_DETAILS_ACCORDION, -} from '../../screens/alerts_details'; -import { TIMELINE_FIELD } from '../../screens/rule_details'; -import { expandFirstAlert, setEnrichmentDates, viewThreatIntelTab } from '../../tasks/alerts'; -import { createRule } from '../../tasks/api_calls/rules'; -import { openJsonView, openThreatIndicatorDetails } from '../../tasks/alerts_details'; -import { addsFieldsToTimeline, visitRuleDetailsPage } from '../../tasks/rule_details'; - -// TODO: https://github.com/elastic/kibana/issues/161539 -describe('CTI Enrichment', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { - before(() => { - cleanKibana(); - // illegal_argument_exception: unknown setting [index.lifecycle.rollover_alias] - cy.task('esArchiverLoad', { archiveName: 'threat_indicator' }); - cy.task('esArchiverLoad', { archiveName: 'suspicious_source_event' }); - login(); - - disableExpandableFlyout(); - }); - - after(() => { - cy.task('esArchiverUnload', 'threat_indicator'); - cy.task('esArchiverUnload', 'suspicious_source_event'); - }); - - beforeEach(() => { - login(); - createRule({ ...getNewThreatIndicatorRule(), rule_id: 'rule_testing', enabled: true }).then( - (rule) => visitRuleDetailsPage(rule.body.id) - ); - }); - - // TODO: https://github.com/elastic/kibana/issues/161539 - // Skipped: https://github.com/elastic/kibana/issues/162818 - it.skip('Displays enrichment matched.* fields on the timeline', () => { - const expectedFields = { - 'threat.enrichments.matched.atomic': indicatorRuleMatchingDoc.atomic, - 'threat.enrichments.matched.type': indicatorRuleMatchingDoc.matchedType, - 'threat.enrichments.matched.field': - getNewThreatIndicatorRule().threat_mapping[0].entries[0].field, - 'threat.enrichments.matched.id': indicatorRuleMatchingDoc.matchedId, - 'threat.enrichments.matched.index': indicatorRuleMatchingDoc.matchedIndex, - }; - const fields = Object.keys(expectedFields) as Array; - - addsFieldsToTimeline('threat.enrichments.matched', fields); - - fields.forEach((field) => { - cy.get(TIMELINE_FIELD(field)).should('have.text', expectedFields[field]); - }); - }); - - it('Displays persisted enrichments on the JSON view', () => { - const expectedEnrichment = [ - { - 'indicator.file.hash.md5': ['9b6c3518a91d23ed77504b5416bfb5b3'], - 'matched.index': ['logs-ti_abusech.malware'], - 'indicator.file.type': ['elf'], - 'indicator.file.hash.tlsh': [ - '6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE', - ], - 'feed.name': ['AbuseCH malware'], - 'indicator.file.hash.ssdeep': [ - '1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL', - ], - 'indicator.file.hash.sha256': [ - 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', - ], - 'indicator.first_seen': ['2021-03-10T08:02:14.000Z'], - 'matched.field': ['myhash.mysha256'], - 'indicator.type': ['file'], - 'matched.type': ['indicator_match_rule'], - 'matched.id': ['84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f'], - 'matched.atomic': ['a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3'], - 'indicator.file.size': [80280], - }, - ]; - - expandFirstAlert(); - openJsonView(); - - cy.get(JSON_TEXT).then((x) => { - const parsed = JSON.parse(x.text()); - expect(parsed.fields['threat.enrichments']).to.deep.equal(expectedEnrichment); - }); - }); - - it('Displays threat indicator details on the threat intel tab', () => { - const expectedThreatIndicatorData = [ - { field: 'feed.name', value: 'AbuseCH malware' }, - { field: 'indicator.file.hash.md5', value: '9b6c3518a91d23ed77504b5416bfb5b3' }, - { - field: 'indicator.file.hash.sha256', - value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', - }, - { - field: 'indicator.file.hash.ssdeep', - value: '1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL', - }, - { - field: 'indicator.file.hash.tlsh', - value: '6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE', - }, - { field: 'indicator.file.size', value: '80280' }, - { field: 'indicator.file.type', value: 'elf' }, - { field: 'indicator.first_seen', value: '2021-03-10T08:02:14.000Z' }, - { field: 'indicator.type', value: 'file' }, - { - field: 'matched.atomic', - value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', - }, - { field: 'matched.field', value: 'myhash.mysha256' }, - { - field: 'matched.id', - value: '84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f', - }, - { field: 'matched.index', value: 'logs-ti_abusech.malware' }, - { field: 'matched.type', value: 'indicator_match_rule' }, - ]; - - expandFirstAlert(); - openThreatIndicatorDetails(); - - cy.get(ENRICHMENT_COUNT_NOTIFICATION).should('have.text', '1'); - cy.get(THREAT_DETAILS_VIEW).within(() => { - cy.get(TABLE_ROWS).should('have.length', expectedThreatIndicatorData.length); - expectedThreatIndicatorData.forEach((row, index) => { - cy.get(TABLE_ROWS) - .eq(index) - .within(() => { - cy.get(TABLE_CELL).eq(0).should('have.text', row.field); - cy.get(TABLE_CELL).eq(1).should('have.text', row.value); - }); - }); - }); - }); - - describe('with additional indicators', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'threat_indicator2' }); - }); - - after(() => { - cy.task('esArchiverUnload', 'threat_indicator2'); - }); - - it('Displays matched fields from both indicator match rules and investigation time enrichments on Threat Intel tab', () => { - const indicatorMatchRuleEnrichment = { - field: 'myhash.mysha256', - value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', - feedName: 'AbuseCH malware', - }; - const investigationTimeEnrichment = { - field: 'source.ip', - value: '192.168.1.1', - feedName: 'feed_name', - }; - - expandFirstAlert(); - viewThreatIntelTab(); - setEnrichmentDates('08/05/2018 10:00 AM'); - - cy.get(`${INDICATOR_MATCH_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`) - .should('exist') - .should( - 'have.text', - `${indicatorMatchRuleEnrichment.field} ${indicatorMatchRuleEnrichment.value} from ${indicatorMatchRuleEnrichment.feedName}` - ); - - cy.get(`${INVESTIGATION_TIME_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`) - .should('exist') - .should( - 'have.text', - `${investigationTimeEnrichment.field} ${investigationTimeEnrichment.value} from ${investigationTimeEnrichment.feedName}` - ); - }); - }); -}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_detection.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_detection.cy.ts deleted file mode 100644 index 3f8da89072da8..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_detection.cy.ts +++ /dev/null @@ -1,73 +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 { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; - -import { ALERTS_URL, TIMELINES_URL } from '../../urls/navigation'; -import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../screens/alerts'; -import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timeline'; -import { selectAlertsHistogram } from '../../tasks/alerts'; -import { createTimeline } from '../../tasks/timelines'; - -// TODO: https://github.com/elastic/kibana/issues/161539 -describe( - 'Ransomware Detection Alerts', - { tags: ['@ess', '@serverless', '@brokenInServerless'] }, - () => { - before(() => { - cy.task('esArchiverLoad', { - archiveName: 'ransomware_detection', - useCreate: true, - docsOnly: true, - }); - }); - - describe('Ransomware display in Alerts Section', () => { - beforeEach(() => { - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - }); - - describe('Alerts table', () => { - it('shows Ransomware Alerts', () => { - cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Detection Alert'); - }); - }); - - describe('Trend Chart', () => { - beforeEach(() => { - selectAlertsHistogram(); - }); - - it('shows Ransomware Detection Alert in the trend chart', () => { - cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Detection Alert'); - }); - }); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/168602 - describe.skip('Ransomware in Timelines', () => { - before(() => { - login(); - visitWithTimeRange(TIMELINES_URL); - createTimeline(); - }); - - it('Renders ransomware entries in timelines table', () => { - cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}'); - - // Wait for grid to load, it should have an analyzer icon - cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist'); - - cy.get(MESSAGE).should('have.text', 'Ransomware Detection Alert'); - }); - }); - } -); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts deleted file mode 100644 index fa4a647ae7f20..0000000000000 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/ransomware_prevention.cy.ts +++ /dev/null @@ -1,79 +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 { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; - -import { ALERTS_URL, TIMELINES_URL } from '../../urls/navigation'; -import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../screens/alerts'; -import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timeline'; -import { selectAlertsHistogram } from '../../tasks/alerts'; -import { createTimeline } from '../../tasks/timelines'; -import { cleanKibana } from '../../tasks/common'; - -// TODO: https://github.com/elastic/kibana/issues/161539 -describe( - 'Ransomware Prevention Alerts', - { tags: ['@ess', '@serverless', '@brokenInServerless'] }, - () => { - before(() => { - cleanKibana(); - cy.task('esArchiverLoad', { - archiveName: 'ransomware_prevention', - useCreate: true, - docsOnly: true, - }); - }); - - after(() => { - cy.task('esArchiverUnload', 'ransomware_prevention'); - }); - - describe('Ransomware display in Alerts Section', () => { - beforeEach(() => { - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - }); - - describe('Alerts table', () => { - it('shows Ransomware Alerts', () => { - cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Prevention Alert'); - }); - }); - - describe('Trend Chart', () => { - beforeEach(() => { - selectAlertsHistogram(); - }); - - it('shows Ransomware Prevention Alert in the trend chart', () => { - cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Prevention Alert'); - }); - }); - }); - - describe('Ransomware in Timelines', () => { - beforeEach(() => { - login(); - visitWithTimeRange(TIMELINES_URL); - - createTimeline(); - }); - - it('Renders ransomware entries in timelines table', () => { - cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}'); - - // Wait for grid to load, it should have an analyzer icon - cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist'); - - cy.get(MESSAGE).should('have.text', 'Ransomware Prevention Alert'); - }); - }); - } -); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts new file mode 100644 index 0000000000000..5d56239e74c99 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts @@ -0,0 +1,230 @@ +/* + * 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, SELECTED_ALERTS } from '../../../screens/alerts'; + +import { + selectNumberOfAlerts, + waitForAlerts, + markAcknowledgedFirstAlert, + markAlertsAcknowledged, + goToAcknowledgedAlerts, + closeFirstAlert, + closeAlerts, + goToClosedAlerts, + goToOpenedAlerts, + openAlerts, + openFirstAlert, +} from '../../../tasks/alerts'; +import { createRule } from '../../../tasks/api_calls/rules'; +import { deleteAlertsAndRules } from '../../../tasks/common'; +import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; + +import { ALERTS_URL } from '../../../urls/navigation'; + +describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' }); + }); + + context('Opening alerts', () => { + beforeEach(() => { + login(); + deleteAlertsAndRules(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + selectNumberOfAlerts(3); + cy.get(SELECTED_ALERTS).should('have.text', `Selected 3 alerts`); + closeAlerts(); + waitForAlerts(); + }); + + after(() => { + cy.task('esArchiverUnload', 'auditbeat_big'); + }); + + it('can mark a closed alert as open', () => { + waitForAlertsToPopulate(); + cy.get(ALERTS_COUNT) + .invoke('text') + .then((numberOfOpenedAlertsText) => { + const numberOfOpenedAlerts = parseInt(numberOfOpenedAlertsText, 10); + goToClosedAlerts(); + waitForAlerts(); + cy.get(ALERTS_COUNT) + .invoke('text') + .then((alertNumberString) => { + const numberOfAlerts = alertNumberString.split(' ')[0]; + const numberOfAlertsToBeOpened = 1; + + openFirstAlert(); + waitForAlerts(); + + const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeOpened; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts); + + goToOpenedAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).contains(`${numberOfOpenedAlerts + numberOfAlertsToBeOpened}`); + }); + }); + }); + + it('can bulk open alerts', () => { + waitForAlertsToPopulate(); + cy.get(ALERTS_COUNT) + .invoke('text') + .then((numberOfOpenedAlertsText) => { + const numberOfOpenedAlerts = parseInt(numberOfOpenedAlertsText, 10); + goToClosedAlerts(); + waitForAlerts(); + cy.get(ALERTS_COUNT) + .invoke('text') + .then((alertNumberString) => { + const numberOfAlerts = alertNumberString.split(' ')[0]; + const numberOfAlertsToBeOpened = 2; + const numberOfAlertsToBeSelected = 2; + + selectNumberOfAlerts(numberOfAlertsToBeSelected); + cy.get(SELECTED_ALERTS).should( + 'have.text', + `Selected ${numberOfAlertsToBeSelected} alerts` + ); + + openAlerts(); + waitForAlerts(); + + const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeOpened; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts); + + goToOpenedAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).contains(`${numberOfOpenedAlerts + numberOfAlertsToBeOpened}`); + }); + }); + }); + }); + + context('Marking alerts as acknowledged', () => { + beforeEach(() => { + login(); + deleteAlertsAndRules(); + createRule(getNewRule()); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + it('can mark alert as acknowledged', () => { + cy.get(ALERTS_COUNT) + .invoke('text') + .then((alertNumberString) => { + const numberOfAlerts = alertNumberString.split(' ')[0]; + const numberOfAlertsToBeMarkedAcknowledged = 1; + + markAcknowledgedFirstAlert(); + waitForAlerts(); + const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeMarkedAcknowledged; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts); + + goToAcknowledgedAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).contains(`${numberOfAlertsToBeMarkedAcknowledged}`); + }); + }); + + it('can bulk mark alerts as acknowledged', () => { + cy.get(ALERTS_COUNT) + .invoke('text') + .then((alertNumberString) => { + const numberOfAlerts = alertNumberString.split(' ')[0]; + const numberOfAlertsToBeMarkedAcknowledged = 2; + const numberOfAlertsToBeSelected = 2; + + selectNumberOfAlerts(numberOfAlertsToBeSelected); + + markAlertsAcknowledged(); + waitForAlerts(); + const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeMarkedAcknowledged; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts); + + goToAcknowledgedAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).contains(numberOfAlertsToBeMarkedAcknowledged); + }); + }); + }); + + context('Closing alerts', () => { + beforeEach(() => { + login(); + deleteAlertsAndRules(); + createRule(getNewRule({ rule_id: '1', max_signals: 100 })); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + }); + it('can close an alert', () => { + const numberOfAlertsToBeClosed = 1; + cy.get(ALERTS_COUNT) + .invoke('text') + .then((alertNumberString) => { + const numberOfAlerts = alertNumberString.split(' ')[0]; + cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`); + + selectNumberOfAlerts(numberOfAlertsToBeClosed); + + cy.get(SELECTED_ALERTS).should('have.text', `Selected ${numberOfAlertsToBeClosed} alert`); + + closeFirstAlert(); + waitForAlerts(); + + const expectedNumberOfAlertsAfterClosing = +numberOfAlerts - numberOfAlertsToBeClosed; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlertsAfterClosing); + + goToClosedAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).contains(numberOfAlertsToBeClosed); + }); + }); + + it('can bulk close alerts', () => { + const numberOfAlertsToBeClosed = 2; + cy.get(ALERTS_COUNT) + .invoke('text') + .then((alertNumberString) => { + const numberOfAlerts = alertNumberString.split(' ')[0]; + cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`); + + selectNumberOfAlerts(numberOfAlertsToBeClosed); + + cy.get(SELECTED_ALERTS).should( + 'have.text', + `Selected ${numberOfAlertsToBeClosed} alerts` + ); + + closeAlerts(); + waitForAlerts(); + + const expectedNumberOfAlertsAfterClosing = +numberOfAlerts - numberOfAlertsToBeClosed; + cy.get(ALERTS_COUNT).contains(expectedNumberOfAlertsAfterClosing); + + goToClosedAlerts(); + waitForAlerts(); + + cy.get(ALERTS_COUNT).contains(numberOfAlertsToBeClosed); + }); + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alert_tags.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts similarity index 83% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alert_tags.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts index ff8e890ab9966..c7b6b16a45c2f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alert_tags.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts @@ -5,28 +5,27 @@ * 2.0. */ -import { getNewRule } from '../../objects/rule'; +import { getNewRule } from '../../../objects/rule'; import { clickAlertTag, openAlertTaggingBulkActionMenu, selectNumberOfAlerts, updateAlertTags, -} from '../../tasks/alerts'; -import { createRule } from '../../tasks/api_calls/rules'; -import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common'; -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; -import { ALERTS_URL } from '../../urls/navigation'; -import { waitForAlertsToPopulate } from '../../tasks/create_new_rule'; +} from '../../../tasks/alerts'; +import { createRule } from '../../../tasks/api_calls/rules'; +import { cleanKibana, deleteAlertsAndRules } from '../../../tasks/common'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; +import { ALERTS_URL } from '../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; import { ALERTS_TABLE_ROW_LOADER, MIXED_ALERT_TAG, SELECTED_ALERT_TAG, UNSELECTED_ALERT_TAG, -} from '../../screens/alerts'; +} from '../../../screens/alerts'; -// TODO: https://github.com/elastic/kibana/issues/161539 -describe('Alert tagging', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +describe('Alert tagging', { tags: ['@ess', '@serverless'] }, () => { before(() => { cleanKibana(); cy.task('esArchiverResetKibana'); 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_response/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts similarity index 91% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts index 686edd1bf4f81..bbdba453351bb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alerts_detection_callouts_index_outdated.cy.ts @@ -7,21 +7,21 @@ import { ROLES } from '@kbn/security-solution-plugin/common/test'; -import { ALERTS_URL } from '../../urls/navigation'; -import { RULES_MANAGEMENT_URL } from '../../urls/rules_management'; -import { ruleDetailsUrl } from '../../urls/rule_details'; -import { getNewRule } from '../../objects/rule'; -import { PAGE_TITLE } from '../../screens/common/page'; +import { ALERTS_URL } from '../../../urls/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; +import { ruleDetailsUrl } from '../../../urls/rule_details'; +import { getNewRule } from '../../../objects/rule'; +import { PAGE_TITLE } from '../../../screens/common/page'; -import { login } from '../../tasks/login'; -import { visit } from '../../tasks/navigation'; +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; -import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { createRule, deleteCustomRule } from '../../../tasks/api_calls/rules'; import { getCallOut, NEED_ADMIN_FOR_UPDATE_CALLOUT, waitForCallOutToBeShown, -} from '../../tasks/common/callouts'; +} from '../../../tasks/common/callouts'; const loadPageAsPlatformEngineerUser = (url: string) => { login(ROLES.soc_manager); @@ -33,7 +33,6 @@ const waitForPageTitleToBeShown = () => { cy.get(PAGE_TITLE).should('be.visible'); }; -// TODO: https://github.com/elastic/kibana/issues/161539 Does it need to run in Serverless? describe( 'Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', { tags: ['@ess', '@skipInServerless'] }, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/missing_privileges_callout.cy.ts similarity index 88% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/missing_privileges_callout.cy.ts index e12dabe044598..f38899300ed7f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/missing_privileges_callout.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/missing_privileges_callout.cy.ts @@ -7,21 +7,21 @@ import { ROLES } from '@kbn/security-solution-plugin/common/test'; -import { ALERTS_URL } from '../../urls/navigation'; -import { RULES_MANAGEMENT_URL } from '../../urls/rules_management'; -import { getNewRule } from '../../objects/rule'; -import { PAGE_TITLE } from '../../screens/common/page'; - -import { login } from '../../tasks/login'; -import { visit } from '../../tasks/navigation'; -import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules'; +import { ALERTS_URL } from '../../../urls/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; +import { getNewRule } from '../../../objects/rule'; +import { PAGE_TITLE } from '../../../screens/common/page'; + +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; +import { createRule, deleteCustomRule } from '../../../tasks/api_calls/rules'; import { getCallOut, waitForCallOutToBeShown, dismissCallOut, MISSING_PRIVILEGES_CALLOUT, -} from '../../tasks/common/callouts'; -import { ruleDetailsUrl } from '../../urls/rule_details'; +} from '../../../tasks/common/callouts'; +import { ruleDetailsUrl } from '../../../urls/rule_details'; const loadPageAsReadOnlyUser = (url: string) => { login(ROLES.reader); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/threat_match_enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/threat_match_enrichments.cy.ts new file mode 100644 index 0000000000000..2bda5a6acadc2 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/threat_match_enrichments.cy.ts @@ -0,0 +1,201 @@ +/* + * 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 { disableExpandableFlyout } from '../../../tasks/api_calls/kibana_advanced_settings'; +import { getNewThreatIndicatorRule, indicatorRuleMatchingDoc } from '../../../objects/rule'; +import { cleanKibana } from '../../../tasks/common'; +import { login } from '../../../tasks/login'; +import { + JSON_TEXT, + TABLE_CELL, + TABLE_ROWS, + THREAT_DETAILS_VIEW, + ENRICHMENT_COUNT_NOTIFICATION, + INDICATOR_MATCH_ENRICHMENT_SECTION, + INVESTIGATION_TIME_ENRICHMENT_SECTION, + THREAT_DETAILS_ACCORDION, +} from '../../../screens/alerts_details'; +import { TIMELINE_FIELD } from '../../../screens/rule_details'; +import { expandFirstAlert, setEnrichmentDates, viewThreatIntelTab } from '../../../tasks/alerts'; +import { createRule } from '../../../tasks/api_calls/rules'; +import { openJsonView, openThreatIndicatorDetails } from '../../../tasks/alerts_details'; +import { addsFieldsToTimeline, visitRuleDetailsPage } from '../../../tasks/rule_details'; + +// TODO: https://github.com/elastic/kibana/issues/161539 +describe( + 'Threat Match Enrichment', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + before(() => { + cleanKibana(); + // illegal_argument_exception: unknown setting [index.lifecycle.rollover_alias] + cy.task('esArchiverLoad', { archiveName: 'threat_indicator' }); + cy.task('esArchiverLoad', { archiveName: 'suspicious_source_event' }); + login(); + + disableExpandableFlyout(); + }); + + after(() => { + cy.task('esArchiverUnload', 'threat_indicator'); + cy.task('esArchiverUnload', 'suspicious_source_event'); + }); + + beforeEach(() => { + login(); + createRule({ ...getNewThreatIndicatorRule(), rule_id: 'rule_testing', enabled: true }).then( + (rule) => visitRuleDetailsPage(rule.body.id) + ); + }); + + // TODO: https://github.com/elastic/kibana/issues/161539 + // Skipped: https://github.com/elastic/kibana/issues/162818 + it.skip('Displays enrichment matched.* fields on the timeline', () => { + const expectedFields = { + 'threat.enrichments.matched.atomic': indicatorRuleMatchingDoc.atomic, + 'threat.enrichments.matched.type': indicatorRuleMatchingDoc.matchedType, + 'threat.enrichments.matched.field': + getNewThreatIndicatorRule().threat_mapping[0].entries[0].field, + 'threat.enrichments.matched.id': indicatorRuleMatchingDoc.matchedId, + 'threat.enrichments.matched.index': indicatorRuleMatchingDoc.matchedIndex, + }; + const fields = Object.keys(expectedFields) as Array; + + addsFieldsToTimeline('threat.enrichments.matched', fields); + + fields.forEach((field) => { + cy.get(TIMELINE_FIELD(field)).should('have.text', expectedFields[field]); + }); + }); + + it('Displays persisted enrichments on the JSON view', () => { + const expectedEnrichment = [ + { + 'indicator.file.hash.md5': ['9b6c3518a91d23ed77504b5416bfb5b3'], + 'matched.index': ['logs-ti_abusech.malware'], + 'indicator.file.type': ['elf'], + 'indicator.file.hash.tlsh': [ + '6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE', + ], + 'feed.name': ['AbuseCH malware'], + 'indicator.file.hash.ssdeep': [ + '1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL', + ], + 'indicator.file.hash.sha256': [ + 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', + ], + 'indicator.first_seen': ['2021-03-10T08:02:14.000Z'], + 'matched.field': ['myhash.mysha256'], + 'indicator.type': ['file'], + 'matched.type': ['indicator_match_rule'], + 'matched.id': ['84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f'], + 'matched.atomic': ['a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3'], + 'indicator.file.size': [80280], + }, + ]; + + expandFirstAlert(); + openJsonView(); + + cy.get(JSON_TEXT).then((x) => { + const parsed = JSON.parse(x.text()); + expect(parsed.fields['threat.enrichments']).to.deep.equal(expectedEnrichment); + }); + }); + + it('Displays threat indicator details on the threat intel tab', () => { + const expectedThreatIndicatorData = [ + { field: 'feed.name', value: 'AbuseCH malware' }, + { field: 'indicator.file.hash.md5', value: '9b6c3518a91d23ed77504b5416bfb5b3' }, + { + field: 'indicator.file.hash.sha256', + value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', + }, + { + field: 'indicator.file.hash.ssdeep', + value: '1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL', + }, + { + field: 'indicator.file.hash.tlsh', + value: '6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE', + }, + { field: 'indicator.file.size', value: '80280' }, + { field: 'indicator.file.type', value: 'elf' }, + { field: 'indicator.first_seen', value: '2021-03-10T08:02:14.000Z' }, + { field: 'indicator.type', value: 'file' }, + { + field: 'matched.atomic', + value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', + }, + { field: 'matched.field', value: 'myhash.mysha256' }, + { + field: 'matched.id', + value: '84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f', + }, + { field: 'matched.index', value: 'logs-ti_abusech.malware' }, + { field: 'matched.type', value: 'indicator_match_rule' }, + ]; + + expandFirstAlert(); + openThreatIndicatorDetails(); + + cy.get(ENRICHMENT_COUNT_NOTIFICATION).should('have.text', '1'); + cy.get(THREAT_DETAILS_VIEW).within(() => { + cy.get(TABLE_ROWS).should('have.length', expectedThreatIndicatorData.length); + expectedThreatIndicatorData.forEach((row, index) => { + cy.get(TABLE_ROWS) + .eq(index) + .within(() => { + cy.get(TABLE_CELL).eq(0).should('have.text', row.field); + cy.get(TABLE_CELL).eq(1).should('have.text', row.value); + }); + }); + }); + }); + + describe('with additional indicators', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'threat_indicator2' }); + }); + + after(() => { + cy.task('esArchiverUnload', 'threat_indicator2'); + }); + + it('Displays matched fields from both indicator match rules and investigation time enrichments on Threat Intel tab', () => { + const indicatorMatchRuleEnrichment = { + field: 'myhash.mysha256', + value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3', + feedName: 'AbuseCH malware', + }; + const investigationTimeEnrichment = { + field: 'source.ip', + value: '192.168.1.1', + feedName: 'feed_name', + }; + + expandFirstAlert(); + viewThreatIntelTab(); + setEnrichmentDates('08/05/2018 10:00 AM'); + + cy.get(`${INDICATOR_MATCH_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`) + .should('exist') + .should( + 'have.text', + `${indicatorMatchRuleEnrichment.field} ${indicatorMatchRuleEnrichment.value} from ${indicatorMatchRuleEnrichment.feedName}` + ); + + cy.get(`${INVESTIGATION_TIME_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`) + .should('exist') + .should( + 'have.text', + `${investigationTimeEnrichment.field} ${investigationTimeEnrichment.value} from ${investigationTimeEnrichment.feedName}` + ); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts new file mode 100644 index 0000000000000..2fd13f8b6696d --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/create_runtime_field.cy.ts @@ -0,0 +1,58 @@ +/* + * 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 { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; +import { openTimelineUsingToggle } from '../../../tasks/security_main'; +import { openTimelineFieldsBrowser, populateTimeline } from '../../../tasks/timeline'; + +import { hostsUrl, ALERTS_URL } from '../../../urls/navigation'; + +import { createRule } from '../../../tasks/api_calls/rules'; + +import { getNewRule } from '../../../objects/rule'; +import { refreshPage } from '../../../tasks/security_header'; +import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; +import { createField } from '../../../tasks/create_runtime_field'; +import { openAlertsFieldBrowser } from '../../../tasks/alerts'; +import { deleteRuntimeField } from '../../../tasks/sourcerer'; +import { GET_DATA_GRID_HEADER } from '../../../screens/common/data_grid'; +import { GET_TIMELINE_HEADER } from '../../../screens/timeline'; + +const alertRunTimeField = 'field.name.alert.page'; +const timelineRuntimeField = 'field.name.timeline'; + +describe('Create DataView runtime field', { tags: ['@ess', '@serverless'] }, () => { + before(() => { + deleteRuntimeField('security-solution-default', alertRunTimeField); + deleteRuntimeField('security-solution-default', timelineRuntimeField); + }); + + beforeEach(() => { + login(); + }); + + it('adds field to alert table', () => { + visitWithTimeRange(ALERTS_URL); + createRule(getNewRule()); + refreshPage(); + waitForAlertsToPopulate(); + openAlertsFieldBrowser(); + createField(alertRunTimeField); + cy.get(GET_DATA_GRID_HEADER(alertRunTimeField)).should('exist'); + }); + + it('adds field to timeline', () => { + visitWithTimeRange(hostsUrl('allHosts')); + openTimelineUsingToggle(); + populateTimeline(); + openTimelineFieldsBrowser(); + + createField(timelineRuntimeField); + cy.get(GET_TIMELINE_HEADER(timelineRuntimeField)).should('exist'); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts new file mode 100644 index 0000000000000..d26543bea97f7 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer.cy.ts @@ -0,0 +1,115 @@ +/* + * 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 { DEFAULT_INDEX_PATTERN } from '@kbn/security-solution-plugin/common/constants'; + +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; + +import { hostsUrl } from '../../../urls/navigation'; +import { + addIndexToDefault, + deselectSourcererOptions, + isDataViewSelection, + isHostsStatValue, + isKibanaDataViewOption, + isNotSourcererSelection, + isSourcererOptions, + isSourcererSelection, + openAdvancedSettings, + openDataViewSelection, + openSourcerer, + resetSourcerer, + saveSourcerer, +} from '../../../tasks/sourcerer'; +import { postDataView } from '../../../tasks/common'; +import { SOURCERER } from '../../../screens/sourcerer'; + +const siemDataViewTitle = 'Security Default Data View'; +const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*']; + +describe('Sourcerer', { tags: ['@ess', '@serverless'] }, () => { + before(() => { + cy.task('esArchiverResetKibana'); + dataViews.forEach((dataView: string) => postDataView(dataView)); + }); + + beforeEach(() => { + cy.clearLocalStorage(); + login(); + visitWithTimeRange(hostsUrl('allHosts')); + }); + + it('correctly loads SIEM data view', () => { + openSourcerer(); + isDataViewSelection(siemDataViewTitle); + openAdvancedSettings(); + isSourcererSelection(`auditbeat-*`); + isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*')); + }); + + describe('Modified badge', () => { + it('Selecting new data view does not add a modified badge', () => { + cy.get(SOURCERER.badgeModified).should(`not.exist`); + openSourcerer(); + cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); + openDataViewSelection(); + isKibanaDataViewOption(dataViews); + cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle); + cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click(); + isDataViewSelection(dataViews[1]); + saveSourcerer(); + cy.get(SOURCERER.badgeModified).should(`not.exist`); + openSourcerer(); + cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); + }); + + it('shows modified badge when index patterns change and removes when reset', () => { + openSourcerer(); + openDataViewSelection(); + cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click(); + isDataViewSelection(dataViews[1]); + openAdvancedSettings(); + const patterns = dataViews[1].split(','); + deselectSourcererOptions([patterns[0]]); + saveSourcerer(); + cy.get(SOURCERER.badgeModified).should(`exist`); + openSourcerer(); + cy.get(SOURCERER.badgeModifiedOption).should(`exist`); + resetSourcerer(); + saveSourcerer(); + cy.get(SOURCERER.badgeModified).should(`not.exist`); + openSourcerer(); + cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`); + isDataViewSelection(siemDataViewTitle); + }); + }); + + it('disables save when no patterns are selected', () => { + openSourcerer(); + openAdvancedSettings(); + cy.get(SOURCERER.saveButton).should('be.enabled'); + deselectSourcererOptions(['auditbeat-*']); + cy.get(SOURCERER.saveButton).should('be.disabled'); + }); + + it( + 'adds a pattern to the default index and correctly filters out auditbeat-*', + { tags: '@brokenInServerless' }, + () => { + openSourcerer(); + isSourcererSelection(`auditbeat-*`); + isNotSourcererSelection('*beat*'); + addIndexToDefault('*beat*'); + isHostsStatValue('1'); + openSourcerer(); + openAdvancedSettings(); + isSourcererSelection(`auditbeat-*`); + isSourcererSelection('*beat*'); + } + ); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts new file mode 100644 index 0000000000000..fa4bf2d27061b --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_permissions.cy.ts @@ -0,0 +1,36 @@ +/* + * 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 { loginWithUser } from '../../../tasks/login'; +import { visitWithUser } from '../../../tasks/navigation'; + +import { hostsUrl } from '../../../urls/navigation'; +import { postDataView } from '../../../tasks/common'; +import { + createUsersAndRoles, + secReadCasesAll, + secReadCasesAllUser, +} from '../../../tasks/privileges'; +import { TOASTER } from '../../../screens/configure_cases'; + +const usersToCreate = [secReadCasesAllUser]; +const rolesToCreate = [secReadCasesAll]; +const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*']; + +describe('Sourcerer permissions', { tags: ['@ess', '@skipInServerless'] }, () => { + before(() => { + cy.task('esArchiverResetKibana'); + dataViews.forEach((dataView: string) => postDataView(dataView)); + createUsersAndRoles(usersToCreate, rolesToCreate); + }); + + it(`role(s) ${secReadCasesAllUser.roles.join()} shows error when user does not have permissions`, () => { + loginWithUser(secReadCasesAllUser); + visitWithUser(hostsUrl('allHosts'), secReadCasesAllUser); + cy.get(TOASTER).should('have.text', 'Write role required to generate data'); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_timeline.cy.ts similarity index 92% rename from x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer_timeline.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_timeline.cy.ts index 22729c9e7661e..64a4e7224f820 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/data_sources/sourcerer_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer/sourcerer_timeline.cy.ts @@ -10,10 +10,10 @@ import { DEFAULT_INDEX_PATTERN, } from '@kbn/security-solution-plugin/common/constants'; -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; -import { TIMELINES_URL } from '../../urls/navigation'; +import { TIMELINES_URL } from '../../../urls/navigation'; import { clickAlertCheckbox, deselectSourcererOptions, @@ -29,12 +29,12 @@ import { refreshUntilAlertsIndexExists, resetSourcerer, saveSourcerer, -} from '../../tasks/sourcerer'; -import { openTimelineUsingToggle } from '../../tasks/security_main'; -import { SOURCERER } from '../../screens/sourcerer'; -import { createTimeline } from '../../tasks/api_calls/timelines'; -import { getTimeline, getTimelineModifiedSourcerer } from '../../objects/timeline'; -import { closeTimeline, openTimelineById } from '../../tasks/timeline'; +} from '../../../tasks/sourcerer'; +import { openTimelineUsingToggle } from '../../../tasks/security_main'; +import { SOURCERER } from '../../../screens/sourcerer'; +import { createTimeline } from '../../../tasks/api_calls/timelines'; +import { getTimeline, getTimelineModifiedSourcerer } from '../../../objects/timeline'; +import { closeTimeline, openTimelineById } from '../../../tasks/timeline'; const siemDataViewTitle = 'Security Default Data View'; const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*']; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts new file mode 100644 index 0000000000000..ddc1f939c08fe --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/permissions.cy.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ROLES } from '@kbn/security-solution-plugin/common/test'; + +import { login } from '../../../tasks/login'; +import { visit } from '../../../tasks/navigation'; +import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; +import { VALUE_LISTS_MODAL_ACTIVATOR } from '../../../screens/lists'; + +describe('value list permissions', { tags: ['@ess', '@skipInServerless'] }, () => { + describe('user with restricted access role', () => { + it('Does not allow a t1 analyst user to upload a value list', () => { + login(ROLES.t1_analyst); + visit(RULES_MANAGEMENT_URL, { role: ROLES.t1_analyst }); + cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled'); + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/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 index faa82b4fc6cdf..4b1c3e93f631e 100644 --- a/x-pack/test/security_solution_cypress/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,6 @@ * 2.0. */ -import { ROLES } from '@kbn/security-solution-plugin/common/test'; - import { login } from '../../../tasks/login'; import { visit } from '../../../tasks/navigation'; import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; @@ -25,253 +23,224 @@ import { deleteValueLists, KNOWN_VALUE_LIST_FILES, } from '../../../tasks/lists'; -import { - VALUE_LISTS_TABLE, - VALUE_LISTS_ROW, - VALUE_LISTS_MODAL_ACTIVATOR, -} from '../../../screens/lists'; +import { VALUE_LISTS_TABLE, VALUE_LISTS_ROW } from '../../../screens/lists'; import { refreshIndex } from '../../../tasks/api_calls/elasticsearch'; -// TODO: https://github.com/elastic/kibana/issues/161539 -// FLAKY: https://github.com/elastic/kibana/issues/165699 -describe('value lists', { tags: ['@ess', '@serverless', '@skipInServerless'] }, () => { - // TODO: https://github.com/elastic/kibana/issues/161539 - describe('management modal', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { - beforeEach(() => { - login(); - deleteValueLists([ - KNOWN_VALUE_LIST_FILES.TEXT, - KNOWN_VALUE_LIST_FILES.IPs, - KNOWN_VALUE_LIST_FILES.CIDRs, - ]); - createListsIndex(); - visit(RULES_MANAGEMENT_URL); - waitForListsIndex(); - waitForValueListsModalToBeLoaded(); - }); +describe('value lists management modal', { tags: ['@ess', '@serverless'] }, () => { + beforeEach(() => { + login(); + deleteValueLists([ + KNOWN_VALUE_LIST_FILES.TEXT, + KNOWN_VALUE_LIST_FILES.IPs, + KNOWN_VALUE_LIST_FILES.CIDRs, + ]); + createListsIndex(); + visit(RULES_MANAGEMENT_URL); + waitForListsIndex(); + waitForValueListsModalToBeLoaded(); + }); + + it('can open and close the modal', () => { + openValueListsModal(); + closeValueListsModal(); + }); - it('can open and close the modal', () => { + describe('create list types', () => { + beforeEach(() => { openValueListsModal(); - closeValueListsModal(); }); - // TODO: https://github.com/elastic/kibana/issues/161539 - // Flaky in serverless tests - describe('create list types', { tags: ['@brokenInServerless'] }, () => { - beforeEach(() => { - openValueListsModal(); - }); - - it('creates a "keyword" list from an uploaded file', () => { - selectValueListType('keyword'); - selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); - uploadValueList(); + it('creates a "keyword" list from an uploaded file', () => { + selectValueListType('keyword'); + selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); + uploadValueList(); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT); - expect($row.text()).to.contain('Keywords'); - }); - }); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT); + expect($row.text()).to.contain('Keywords'); + }); + }); - it('creates a "text" list from an uploaded file', () => { - selectValueListType('text'); - selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); - uploadValueList(); + it('creates a "text" list from an uploaded file', () => { + selectValueListType('text'); + selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); + uploadValueList(); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT); - expect($row.text()).to.contain('Text'); - }); - }); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT); + expect($row.text()).to.contain('Text'); + }); + }); - it('creates a "ip" list from an uploaded file', () => { - selectValueListType('ip'); - selectValueListsFile(KNOWN_VALUE_LIST_FILES.IPs); - uploadValueList(); + it('creates a "ip" list from an uploaded file', () => { + selectValueListType('ip'); + selectValueListsFile(KNOWN_VALUE_LIST_FILES.IPs); + uploadValueList(); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.IPs); - expect($row.text()).to.contain('IP addresses'); - }); - }); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.IPs); + expect($row.text()).to.contain('IP addresses'); + }); + }); - it('creates a "ip_range" list from an uploaded file', () => { - selectValueListType('ip_range'); - selectValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs); - uploadValueList(); + it('creates a "ip_range" list from an uploaded file', () => { + selectValueListType('ip_range'); + selectValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs); + uploadValueList(); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.CIDRs); - expect($row.text()).to.contain('IP ranges'); - }); - }); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.CIDRs); + expect($row.text()).to.contain('IP ranges'); + }); }); + }); - // TODO: https://github.com/elastic/kibana/issues/161539 - // Flaky in serverless tests - describe('delete list types', { tags: ['@brokenInServerless'] }, () => { - it('deletes a "keyword" list from an uploaded file', () => { - importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword'); - openValueListsModal(); - deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT); - }); - }); + describe('delete list types', () => { + it('deletes a "keyword" list from an uploaded file', () => { + importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword'); + openValueListsModal(); + deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT); + }); + }); - it('deletes a "text" list from an uploaded file', () => { - importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text'); - openValueListsModal(); - deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT); - }); - }); + it('deletes a "text" list from an uploaded file', () => { + importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text'); + openValueListsModal(); + deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT); + }); + }); - it('deletes a "ip" from an uploaded file', () => { - importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip'); - openValueListsModal(); - deleteValueListsFile(KNOWN_VALUE_LIST_FILES.IPs); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.IPs); - }); - }); + it('deletes a "ip" from an uploaded file', () => { + importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip'); + openValueListsModal(); + deleteValueListsFile(KNOWN_VALUE_LIST_FILES.IPs); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.IPs); + }); + }); - it('deletes a "ip_range" from an uploaded file', () => { - importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']); - openValueListsModal(); - deleteValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs); - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.CIDRs); - }); - }); + it('deletes a "ip_range" from an uploaded file', () => { + importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']); + openValueListsModal(); + deleteValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.CIDRs); + }); }); + }); - // TODO: https://github.com/elastic/kibana/issues/161539 - // Flaky in serverless tests - describe('export list types', { tags: ['@brokenInServerless'] }, () => { - it('exports a "keyword" list from an uploaded file', () => { - cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as( - 'exportList' - ); - importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword'); + describe('export list types', () => { + it('exports a "keyword" list from an uploaded file', () => { + cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as( + 'exportList' + ); + importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword'); - // Importing value lists includes bulk creation of list items with refresh=wait_for - // While it should wait for data update and return after that it's not always a case with bulk operations. - // Sometimes list items are empty making this test flaky. - // To fix it refresh used list items index (for the default space) - refreshIndex('.items-default'); + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); - openValueListsModal(); - exportValueList(); + openValueListsModal(); + exportValueList(); - cy.wait('@exportList').then(({ response }) => { - cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => { - const [lineOne, lineTwo] = list.split('\n'); - expect(response?.body).to.contain(lineOne); - expect(response?.body).to.contain(lineTwo); - }); + cy.wait('@exportList').then(({ response }) => { + cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => { + const [lineOne, lineTwo] = list.split('\n'); + expect(response?.body).to.contain(lineOne); + expect(response?.body).to.contain(lineTwo); }); }); + }); - it('exports a "text" list from an uploaded file', () => { - cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as( - 'exportList' - ); - importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text'); + it('exports a "text" list from an uploaded file', () => { + cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as( + 'exportList' + ); + importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text'); - // Importing value lists includes bulk creation of list items with refresh=wait_for - // While it should wait for data update and return after that it's not always a case with bulk operations. - // Sometimes list items are empty making this test flaky. - // To fix it refresh used list items index (for the default space) - refreshIndex('.items-default'); + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); - openValueListsModal(); - exportValueList(); + openValueListsModal(); + exportValueList(); - cy.wait('@exportList').then(({ response }) => { - cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => { - const [lineOne, lineTwo] = list.split('\n'); - expect(response?.body).to.contain(lineOne); - expect(response?.body).to.contain(lineTwo); - }); + cy.wait('@exportList').then(({ response }) => { + cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => { + const [lineOne, lineTwo] = list.split('\n'); + expect(response?.body).to.contain(lineOne); + expect(response?.body).to.contain(lineTwo); }); }); + }); - it('exports a "ip" list from an uploaded file', () => { - cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.IPs}`).as( - 'exportList' - ); - importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip'); + it('exports a "ip" list from an uploaded file', () => { + cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.IPs}`).as( + 'exportList' + ); + importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip'); - // Importing value lists includes bulk creation of list items with refresh=wait_for - // While it should wait for data update and return after that it's not always a case with bulk operations. - // Sometimes list items are empty making this test flaky. - // To fix it refresh used list items index (for the default space) - refreshIndex('.items-default'); + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); - openValueListsModal(); - exportValueList(); - cy.wait('@exportList').then(({ response }) => { - cy.fixture(KNOWN_VALUE_LIST_FILES.IPs).then((list: string) => { - const [lineOne, lineTwo] = list.split('\n'); - expect(response?.body).to.contain(lineOne); - expect(response?.body).to.contain(lineTwo); - }); + openValueListsModal(); + exportValueList(); + cy.wait('@exportList').then(({ response }) => { + cy.fixture(KNOWN_VALUE_LIST_FILES.IPs).then((list: string) => { + const [lineOne, lineTwo] = list.split('\n'); + expect(response?.body).to.contain(lineOne); + expect(response?.body).to.contain(lineTwo); }); }); + }); - it('exports a "ip_range" list from an uploaded file', () => { - cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.CIDRs}`).as( - 'exportList' - ); - importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']); + it('exports a "ip_range" list from an uploaded file', () => { + cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.CIDRs}`).as( + 'exportList' + ); + importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']); - // Importing value lists includes bulk creation of list items with refresh=wait_for - // While it should wait for data update and return after that it's not always a case with bulk operations. - // Sometimes list items are empty making this test flaky. - // To fix it refresh used list items index (for the default space) - refreshIndex('.items-default'); + // Importing value lists includes bulk creation of list items with refresh=wait_for + // While it should wait for data update and return after that it's not always a case with bulk operations. + // Sometimes list items are empty making this test flaky. + // To fix it refresh used list items index (for the default space) + refreshIndex('.items-default'); - openValueListsModal(); - exportValueList(); - cy.wait('@exportList').then(({ response }) => { - cy.fixture(KNOWN_VALUE_LIST_FILES.CIDRs).then((list: string) => { - const [lineOne] = list.split('\n'); - expect(response?.body).to.contain(lineOne); - }); + openValueListsModal(); + exportValueList(); + cy.wait('@exportList').then(({ response }) => { + cy.fixture(KNOWN_VALUE_LIST_FILES.CIDRs).then((list: string) => { + const [lineOne] = list.split('\n'); + expect(response?.body).to.contain(lineOne); }); }); }); }); - - // TODO: https://github.com/elastic/kibana/issues/164451 We should find a way to make this spec work in Serverless - // TODO: https://github.com/elastic/kibana/issues/161539 - describe( - 'user with restricted access role', - { tags: ['@ess', '@serverless', '@skipInServerless'] }, - () => { - it('Does not allow a t1 analyst user to upload a value list', () => { - login(ROLES.t1_analyst); - visit(RULES_MANAGEMENT_URL, { role: ROLES.t1_analyst }); - cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled'); - }); - } - ); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts similarity index 100% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/enrichments.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_charts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts similarity index 79% rename from x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_charts.cy.ts rename to x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts index f5055f7c8770c..86dd58889a0a8 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts/alerts_charts.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts @@ -5,25 +5,25 @@ * 2.0. */ -import { getNewRule } from '../../objects/rule'; -import { ALERTS_COUNT } from '../../screens/alerts'; +import { getNewRule } from '../../../objects/rule'; +import { ALERTS_COUNT } from '../../../screens/alerts'; import { clickAlertsHistogramLegend, clickAlertsHistogramLegendAddToTimeline, clickAlertsHistogramLegendFilterFor, clickAlertsHistogramLegendFilterOut, selectAlertsHistogram, -} from '../../tasks/alerts'; -import { createRule } from '../../tasks/api_calls/rules'; -import { cleanKibana } from '../../tasks/common'; -import { login } from '../../tasks/login'; -import { visitWithTimeRange } from '../../tasks/navigation'; -import { ALERTS_URL } from '../../urls/navigation'; +} from '../../../tasks/alerts'; +import { createRule } from '../../../tasks/api_calls/rules'; +import { cleanKibana } from '../../../tasks/common'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; +import { ALERTS_URL } from '../../../urls/navigation'; import { GLOBAL_SEARCH_BAR_FILTER_ITEM, GLOBAL_SEARCH_BAR_FILTER_ITEM_DELETE, -} from '../../screens/search_bar'; -import { TOASTER } from '../../screens/alerts_detection_rules'; +} from '../../../screens/search_bar'; +import { TOASTER } from '../../../screens/alerts_detection_rules'; // TODO: https://github.com/elastic/kibana/issues/161539 describe( diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts new file mode 100644 index 0000000000000..bc0e3469b9c7e --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts @@ -0,0 +1,68 @@ +/* + * 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 { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; + +import { ALERTS_URL, TIMELINES_URL } from '../../../urls/navigation'; +import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../../screens/alerts'; +import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../../screens/timeline'; +import { selectAlertsHistogram } from '../../../tasks/alerts'; +import { createTimeline } from '../../../tasks/timelines'; + +describe('Ransomware Detection Alerts', { tags: ['@ess', '@serverless'] }, () => { + before(() => { + cy.task('esArchiverLoad', { + archiveName: 'ransomware_detection', + useCreate: true, + docsOnly: true, + }); + }); + + describe('Ransomware display in Alerts Section', () => { + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + describe('Alerts table', () => { + it('shows Ransomware Alerts', () => { + cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Detection Alert'); + }); + }); + + describe('Trend Chart', () => { + beforeEach(() => { + selectAlertsHistogram(); + }); + + it('shows Ransomware Detection Alert in the trend chart', () => { + cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Detection Alert'); + }); + }); + }); + + // FLAKY: https://github.com/elastic/kibana/issues/168602 + describe.skip('Ransomware in Timelines', () => { + before(() => { + login(); + visitWithTimeRange(TIMELINES_URL); + createTimeline(); + }); + + it('Renders ransomware entries in timelines table', () => { + cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}'); + + // Wait for grid to load, it should have an analyzer icon + cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist'); + + cy.get(MESSAGE).should('have.text', 'Ransomware Detection Alert'); + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts new file mode 100644 index 0000000000000..f3fc88f6518ac --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_prevention.cy.ts @@ -0,0 +1,74 @@ +/* + * 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 { waitForAlertsToPopulate } from '../../../tasks/create_new_rule'; +import { login } from '../../../tasks/login'; +import { visitWithTimeRange } from '../../../tasks/navigation'; + +import { ALERTS_URL, TIMELINES_URL } from '../../../urls/navigation'; +import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../../screens/alerts'; +import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../../screens/timeline'; +import { selectAlertsHistogram } from '../../../tasks/alerts'; +import { createTimeline } from '../../../tasks/timelines'; +import { cleanKibana } from '../../../tasks/common'; + +describe('Ransomware Prevention Alerts', { tags: ['@ess', '@serverless'] }, () => { + before(() => { + cleanKibana(); + cy.task('esArchiverLoad', { + archiveName: 'ransomware_prevention', + useCreate: true, + docsOnly: true, + }); + }); + + after(() => { + cy.task('esArchiverUnload', 'ransomware_prevention'); + }); + + describe('Ransomware display in Alerts Section', () => { + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + }); + + describe('Alerts table', () => { + it('shows Ransomware Alerts', () => { + cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Prevention Alert'); + }); + }); + + describe('Trend Chart', () => { + beforeEach(() => { + selectAlertsHistogram(); + }); + + it('shows Ransomware Prevention Alert in the trend chart', () => { + cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Prevention Alert'); + }); + }); + }); + + describe('Ransomware in Timelines', () => { + beforeEach(() => { + login(); + visitWithTimeRange(TIMELINES_URL); + + createTimeline(); + }); + + it('Renders ransomware entries in timelines table', () => { + cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}'); + + // Wait for grid to load, it should have an analyzer icon + cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist'); + + cy.get(MESSAGE).should('have.text', 'Ransomware Prevention Alert'); + }); + }); +}); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts index 1bbdc9eac1539..4950f2c65fab2 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts @@ -304,6 +304,12 @@ export const goToAcknowledgedAlerts = () => { cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist'); }; +export const markAlertsAcknowledged = () => { + cy.get(TAKE_ACTION_POPOVER_BTN).click({ force: true }); + cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).should('be.visible'); + cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).click(); +}; + export const markAcknowledgedFirstAlert = () => { expandFirstAlertActions(); cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).should('be.visible');