mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution][Serverless] Reusing Cypress tests for Serverless infrastructure (#162698)
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Patryk Kopycinski <contact@patrykkopycinski.com> Co-authored-by: Georgii Gorbachev <georgii.gorbachev@elastic.co>
This commit is contained in:
parent
e09de7dda4
commit
f9c9722c6f
374 changed files with 4332 additions and 3679 deletions
|
@ -46,6 +46,7 @@ disabled:
|
|||
- x-pack/plugins/apm/ftr_e2e/ftr_config.ts
|
||||
- x-pack/test_serverless/functional/test_suites/observability/cypress/config_headless.ts
|
||||
- x-pack/test_serverless/functional/test_suites/observability/cypress/config_runner.ts
|
||||
- x-pack/test/security_solution_cypress/serverless_config.ts
|
||||
- x-pack/plugins/profiling/e2e/ftr_config_open.ts
|
||||
- x-pack/plugins/profiling/e2e/ftr_config_runner.ts
|
||||
- x-pack/plugins/profiling/e2e/ftr_config.ts
|
||||
|
|
|
@ -94,13 +94,14 @@ steps:
|
|||
automatic:
|
||||
- exit_status: '-1'
|
||||
limit: 3
|
||||
|
||||
|
||||
- command: .buildkite/scripts/steps/functional/security_serverless.sh
|
||||
label: 'Serverless Security Cypress Tests'
|
||||
agents:
|
||||
queue: n2-4-spot
|
||||
depends_on: build
|
||||
timeout_in_minutes: 40
|
||||
parallelism: 10
|
||||
soft_fail:
|
||||
- exit_status: 10
|
||||
retry:
|
||||
|
@ -110,8 +111,60 @@ steps:
|
|||
- exit_status: '*'
|
||||
limit: 1
|
||||
artifact_paths:
|
||||
- "target/kibana-security-serverless/**/*"
|
||||
- "target/kibana-security-solution/**/*"
|
||||
|
||||
- command: .buildkite/scripts/steps/functional/security_serverless_defend_workflows.sh
|
||||
label: 'Serverless Security Defend Workflows Cypress Tests'
|
||||
agents:
|
||||
queue: n2-4-spot
|
||||
depends_on: build
|
||||
timeout_in_minutes: 40
|
||||
soft_fail:
|
||||
- exit_status: 10
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: '-1'
|
||||
limit: 3
|
||||
- exit_status: '*'
|
||||
limit: 1
|
||||
artifact_paths:
|
||||
- "target/kibana-security-solution/**/*"
|
||||
|
||||
- command: .buildkite/scripts/steps/functional/security_serverless_investigations.sh
|
||||
label: 'Serverless Security Investigations Cypress Tests'
|
||||
agents:
|
||||
queue: n2-4-spot
|
||||
depends_on: build
|
||||
timeout_in_minutes: 40
|
||||
parallelism: 4
|
||||
soft_fail:
|
||||
- exit_status: 10
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: '-1'
|
||||
limit: 3
|
||||
- exit_status: '*'
|
||||
limit: 1
|
||||
artifact_paths:
|
||||
- "target/kibana-security-solution/**/*"
|
||||
|
||||
- command: .buildkite/scripts/steps/functional/security_serverless_explore.sh
|
||||
label: 'Serverless Security Explore Cypress Tests'
|
||||
agents:
|
||||
queue: n2-4-spot
|
||||
depends_on: build
|
||||
timeout_in_minutes: 40
|
||||
parallelism: 2
|
||||
soft_fail:
|
||||
- exit_status: 10
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: '-1'
|
||||
limit: 3
|
||||
- exit_status: '*'
|
||||
limit: 1
|
||||
artifact_paths:
|
||||
- "target/kibana-security-solution/**/*"
|
||||
|
||||
- command: .buildkite/scripts/steps/lint.sh
|
||||
label: 'Linting'
|
||||
|
|
|
@ -11,15 +11,4 @@ steps:
|
|||
- exit_status: '*'
|
||||
limit: 1
|
||||
artifact_paths:
|
||||
- "target/kibana-security-solution/**/*"
|
||||
|
||||
- command: .buildkite/scripts/steps/functional/security_solution_burn.sh
|
||||
label: 'Security Solution Cypress tests, burning changed specs'
|
||||
agents:
|
||||
queue: n2-4-spot
|
||||
depends_on: build
|
||||
timeout_in_minutes: 120
|
||||
parallelism: 1
|
||||
soft_fail: true
|
||||
artifact_paths:
|
||||
- "target/kibana-security-solution/**/*"
|
||||
- "target/kibana-security-solution/**/*"
|
|
@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
|||
|
||||
echo "--- Response Ops Cypress Tests on Security Solution"
|
||||
|
||||
yarn --cwd x-pack/plugins/security_solution cypress:run:respops
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:run:respops:ess
|
||||
|
|
|
@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
|||
|
||||
echo "--- Response Ops Cases Cypress Tests on Security Solution"
|
||||
|
||||
yarn --cwd x-pack/plugins/security_solution cypress:run:cases
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:run:cases:ess
|
||||
|
|
|
@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
|||
|
||||
echo "--- Security Serverless Cypress"
|
||||
|
||||
yarn --cwd x-pack/test_serverless/functional/test_suites/security/cypress cypress:run
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:run:serverless
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source .buildkite/scripts/steps/functional/common.sh
|
||||
source .buildkite/scripts/steps/functional/common_cypress.sh
|
||||
|
||||
export JOB=kibana-serverless-security-cypress
|
||||
export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
||||
|
||||
echo "--- Security Defend Workflows Serverless Cypress"
|
||||
|
||||
yarn --cwd x-pack/test_serverless/functional/test_suites/security/cypress cypress:run
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source .buildkite/scripts/steps/functional/common.sh
|
||||
source .buildkite/scripts/steps/functional/common_cypress.sh
|
||||
|
||||
export JOB=kibana-security-solution-chrome
|
||||
export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
||||
|
||||
echo "--- Explore Cypress Tests on Serverless"
|
||||
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:explore:run:serverless
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source .buildkite/scripts/steps/functional/common.sh
|
||||
source .buildkite/scripts/steps/functional/common_cypress.sh
|
||||
|
||||
export JOB=kibana-security-solution-chrome
|
||||
export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
||||
|
||||
echo "--- Investigations Cypress Tests on Serverless"
|
||||
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:investigations:run:serverless
|
|
@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
|||
|
||||
echo "--- Security Solution Cypress tests (Chrome)"
|
||||
|
||||
yarn --cwd x-pack/plugins/security_solution cypress:run
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:run:ess
|
||||
|
|
|
@ -12,4 +12,4 @@ buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" 'fals
|
|||
|
||||
echo "--- Security Solution Cypress tests, burning changed specs (Chrome)"
|
||||
|
||||
yarn --cwd x-pack/plugins/security_solution cypress:changed-specs-only
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:changed-specs-only:ess
|
||||
|
|
|
@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
|||
|
||||
echo "--- Explore Cypress Tests on Security Solution"
|
||||
|
||||
yarn --cwd x-pack/plugins/security_solution cypress:explore:run
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:explore:run:ess
|
||||
|
|
|
@ -10,4 +10,4 @@ export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
|
|||
|
||||
echo "--- Investigations Cypress Tests on Security Solution"
|
||||
|
||||
yarn --cwd x-pack/plugins/security_solution cypress:investigations:run
|
||||
yarn --cwd x-pack/test/security_solution_cypress cypress:investigations:run:ess
|
||||
|
|
49
.github/CODEOWNERS
vendored
49
.github/CODEOWNERS
vendored
|
@ -1087,7 +1087,7 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
/x-pack/plugins/security_solution/common/search_strategy/timeline @elastic/security-threat-hunting-investigations
|
||||
/x-pack/plugins/security_solution/common/types/timeline @elastic/security-threat-hunting-investigations
|
||||
|
||||
/x-pack/plugins/security_solution/cypress/e2e/investigations @elastic/security-threat-hunting-investigations
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/investigations @elastic/security-threat-hunting-investigations
|
||||
|
||||
/x-pack/plugins/security_solution/public/common/components/alerts_viewer @elastic/security-threat-hunting-investigations
|
||||
/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_action @elastic/security-threat-hunting-investigations
|
||||
|
@ -1111,12 +1111,11 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
/x-pack/plugins/security_solution/common/search_strategy/security_solution/network @elastic/security-threat-hunting-explore
|
||||
/x-pack/plugins/security_solution/common/search_strategy/security_solution/user @elastic/security-threat-hunting-explore
|
||||
|
||||
/x-pack/plugins/security_solution/cypress/e2e/explore @elastic/security-threat-hunting-explore
|
||||
/x-pack/plugins/security_solution/cypress/screens/hosts @elastic/security-threat-hunting-explore
|
||||
/x-pack/plugins/security_solution/cypress/screens/network @elastic/security-threat-hunting-explore
|
||||
/x-pack/plugins/security_solution/cypress/tasks/hosts @elastic/security-threat-hunting-explore
|
||||
/x-pack/plugins/security_solution/cypress/tasks/network @elastic/security-threat-hunting-explore
|
||||
/x-pack/plugins/security_solution/cypress/upgrade_e2e/threat_hunting/cases @elastic/security-threat-hunting-explore
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/explore @elastic/security-threat-hunting-explore
|
||||
/x-pack/test/security_solution_cypress/cypress/screens/hosts @elastic/security-threat-hunting-explore
|
||||
/x-pack/test/security_solution_cypress/cypress/screens/network @elastic/security-threat-hunting-explore
|
||||
/x-pack/test/security_solution_cypress/cypress/tasks/hosts @elastic/security-threat-hunting-explore
|
||||
/x-pack/test/security_solution_cypress/cypress/tasks/network @elastic/security-threat-hunting-explore
|
||||
|
||||
/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour @elastic/security-threat-hunting-explore
|
||||
/x-pack/plugins/security_solution/public/common/components/charts @elastic/security-threat-hunting-explore
|
||||
|
@ -1168,8 +1167,8 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
/x-pack/plugins/security_solution/common/detection_engine/rule_management @elastic/security-detection-rule-management
|
||||
/x-pack/plugins/security_solution/common/detection_engine/rule_monitoring @elastic/security-detection-rule-management
|
||||
|
||||
/x-pack/plugins/security_solution/cypress/e2e/detection_response/prebuilt_rules @elastic/security-detection-rule-management
|
||||
/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_management @elastic/security-detection-rule-management
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/prebuilt_rules @elastic/security-detection-rule-management
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management @elastic/security-detection-rule-management
|
||||
|
||||
/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules @elastic/security-detection-rule-management
|
||||
/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/rule_management @elastic/security-detection-rule-management
|
||||
|
@ -1216,12 +1215,12 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals @elastic/security-detection-engine
|
||||
|
||||
/x-pack/plugins/security_solution/cypress/e2e/data_sources @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/cypress/e2e/detection_response/rule_creation @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/cypress/e2e/detection_response/value_lists @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/cypress/e2e/entity_analytics @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/cypress/e2e/exceptions @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/cypress/e2e/overview @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/data_sources @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/exceptions @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/overview @elastic/security-detection-engine
|
||||
|
||||
/x-pack/plugins/security_solution/common/detection_engine/rule_exceptions @elastic/security-detection-engine
|
||||
|
||||
|
@ -1240,14 +1239,14 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
/x-pack/plugins/security_solution/public/common/components/threat_match @elastic/security-detection-engine
|
||||
|
||||
## Security Solution cross teams ownership
|
||||
/x-pack/plugins/security_solution/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/plugins/security_solution/cypress/helpers @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/plugins/security_solution/cypress/e2e/detection_rules @elastic/security-detection-rule-management @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/cypress/objects @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/plugins/security_solution/cypress/plugins @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/plugins/security_solution/cypress/screens/common @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/plugins/security_solution/cypress/support @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/plugins/security_solution/cypress/urls @elastic/security-threat-hunting-investigations @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/test/security_solution_cypress/cypress/helpers @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_rules @elastic/security-detection-rule-management @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/objects @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/test/security_solution_cypress/cypress/plugins @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/test/security_solution_cypress/cypress/screens/common @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/test/security_solution_cypress/cypress/support @elastic/security-detections-response @elastic/security-threat-hunting
|
||||
/x-pack/test/security_solution_cypress/cypress/urls @elastic/security-threat-hunting-investigations @elastic/security-detection-engine
|
||||
|
||||
/x-pack/plugins/security_solution/common/ecs @elastic/security-threat-hunting-investigations
|
||||
/x-pack/plugins/security_solution/common/test @elastic/security-detection-rule-management @elastic/security-detection-engine
|
||||
|
@ -1283,9 +1282,7 @@ x-pack/plugins/security_solution/server/usage/ @elastic/security-data-analytics
|
|||
x-pack/plugins/security_solution/server/lib/telemetry/ @elastic/security-data-analytics
|
||||
|
||||
## Security Solution sub teams - security-engineering-productivity
|
||||
x-pack/plugins/security_solution/cypress/ccs_e2e @elastic/security-engineering-productivity
|
||||
x-pack/plugins/security_solution/cypress/upgrade_e2e @elastic/security-engineering-productivity
|
||||
x-pack/plugins/security_solution/cypress/README.md @elastic/security-engineering-productivity
|
||||
x-pack/test/security_solution_cypress/cypress/README.md @elastic/security-engineering-productivity
|
||||
x-pack/test/security_solution_cypress @elastic/security-engineering-productivity
|
||||
|
||||
## Security Solution sub teams - adaptive-workload-protection
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
"private": true,
|
||||
"license": "Elastic License 2.0",
|
||||
"scripts": {
|
||||
"cypress:open": "node ../security_solution/scripts/start_cypress_parallel open --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/osquery_cypress/cli_config",
|
||||
"cypress:run": "node ../security_solution/scripts/start_cypress_parallel run --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/osquery_cypress/cli_config --concurrency 1",
|
||||
"cypress:open": "node ../security_solution/scripts/start_cypress_parallel open --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../x-pack/test/osquery_cypress/cli_config",
|
||||
"cypress:run": "node ../security_solution/scripts/start_cypress_parallel run --config-file ../osquery/cypress.config.ts --ftr-config-file ../../../x-pack/test/osquery_cypress/cli_config --concurrency 1",
|
||||
"nyc": "../../../node_modules/.bin/nyc report --reporter=text-summary"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ROLES } from '../../../common/test';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL, ALERTS_URL } from '../../urls/navigation';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { PAGE_TITLE } from '../../screens/common/page';
|
||||
|
||||
import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../tasks/login';
|
||||
import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts';
|
||||
|
||||
const loadPageAsPlatformEngineerUser = (url: string) => {
|
||||
login(ROLES.soc_manager);
|
||||
waitForPageWithoutDateRange(url, ROLES.soc_manager);
|
||||
waitForPageTitleToBeShown();
|
||||
};
|
||||
|
||||
const waitForPageTitleToBeShown = () => {
|
||||
cy.get(PAGE_TITLE).should('be.visible');
|
||||
};
|
||||
|
||||
describe('Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set', () => {
|
||||
const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules';
|
||||
|
||||
before(() => {
|
||||
// First, we have to open the app on behalf of a privileged user in order to initialize it.
|
||||
// Otherwise the app will be disabled and show a "welcome"-like page.
|
||||
login();
|
||||
visitWithoutDateRange(ALERTS_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
});
|
||||
|
||||
context(
|
||||
'The users index_mapping_outdated is "true" and their admin callouts should show up',
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
// Index mapping outdated is forced to return true as being outdated so that we get the
|
||||
// need admin callouts being shown.
|
||||
cy.intercept('GET', '/api/detection_engine/index', (req) => {
|
||||
req.reply((res) => {
|
||||
res.send(200, {
|
||||
index_mapping_outdated: true,
|
||||
name: '.alerts-security.alerts-default',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('On Detections home page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(ALERTS_URL);
|
||||
});
|
||||
|
||||
it('We show the need admin primary callout', () => {
|
||||
waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rules Management page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
it('We show 1 primary callout of need admin', () => {
|
||||
waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createRule(getNewRule({ rule_id: 'rule_testing' }));
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
deleteCustomRule();
|
||||
});
|
||||
|
||||
it('We show 1 primary callout', () => {
|
||||
waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
context(
|
||||
'The users index_mapping_outdated is "false" and their admin callouts should not show up ',
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
// Index mapping outdated is forced to return true as being outdated so that we get the
|
||||
// need admin callouts being shown.
|
||||
cy.intercept('GET', '/api/detection_engine/index', {
|
||||
index_mapping_outdated: false,
|
||||
name: '.alerts-security.alerts-default',
|
||||
});
|
||||
});
|
||||
context('On Detections home page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(ALERTS_URL);
|
||||
});
|
||||
|
||||
it('We show the need admin primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rules Management page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
it('We show 1 primary callout of need admin', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createRule(getNewRule({ rule_id: 'rule_testing' }));
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
deleteCustomRule();
|
||||
});
|
||||
|
||||
it('We show 1 primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
context(
|
||||
'The users index_mapping_outdated is "null" and their admin callouts should not show up ',
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
// Index mapping outdated is forced to return true as being outdated so that we get the
|
||||
// need admin callouts being shown.
|
||||
cy.intercept('GET', '/api/detection_engine/index', {
|
||||
index_mapping_outdated: null,
|
||||
name: '.alerts-security.alerts-default',
|
||||
});
|
||||
});
|
||||
context('On Detections home page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(ALERTS_URL);
|
||||
});
|
||||
|
||||
it('We show the need admin primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rules Management page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
it('We show 1 primary callout of need admin', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createRule(getNewRule({ rule_id: 'rule_testing' }));
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
deleteCustomRule();
|
||||
});
|
||||
|
||||
it('We show 1 primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { APP_PATH, RULES_ADD_PATH, RULES_UPDATES } from '../../../../common/constants';
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules';
|
||||
import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import { login, waitForPageWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
import { ROLES } from '../../../../common/test';
|
||||
import {
|
||||
ADD_ELASTIC_RULES_BTN,
|
||||
getInstallSingleRuleButtonByRuleId,
|
||||
getUpgradeSingleRuleButtonByRuleId,
|
||||
INSTALL_ALL_RULES_BUTTON,
|
||||
RULES_UPDATES_TAB,
|
||||
RULE_CHECKBOX,
|
||||
UPGRADE_ALL_RULES_BUTTON,
|
||||
} from '../../../screens/alerts_detection_rules';
|
||||
|
||||
const RULE_1_ID = 'rule_1';
|
||||
const RULE_2_ID = 'rule_2';
|
||||
const OUTDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 2,
|
||||
});
|
||||
const OUTDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 2,
|
||||
});
|
||||
|
||||
const loadPageAsReadOnlyUser = (url: string) => {
|
||||
login(ROLES.reader);
|
||||
waitForPageWithoutDateRange(url, ROLES.reader);
|
||||
};
|
||||
|
||||
describe('Detection rules, Prebuilt Rules Installation and Update - Authorization/RBAC', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
waitForRulesTableToBeLoaded();
|
||||
createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
});
|
||||
|
||||
describe('User with read privileges on Security Solution', () => {
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
beforeEach(() => {
|
||||
// Now login with read-only user in preparation for test
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
|
||||
loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('should not be able to install prebuilt rules', () => {
|
||||
// Check that Add Elastic Rules button is disabled
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.disabled');
|
||||
|
||||
// Navigate to Add Elastic Rules page anyways via URL
|
||||
// and assert that rules cannot be selected and all
|
||||
// installation buttons are disabled
|
||||
cy.visit(`${APP_PATH}${RULES_ADD_PATH}`);
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).should('be.disabled');
|
||||
cy.get(getInstallSingleRuleButtonByRuleId(RULE_1['security-rule'].rule_id)).should(
|
||||
'not.exist'
|
||||
);
|
||||
cy.get(RULE_CHECKBOX).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('User with read privileges on Security Solution', () => {
|
||||
beforeEach(() => {
|
||||
/* Create a second version of the rule, making it available for update */
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
|
||||
installToKibana: false,
|
||||
});
|
||||
// Now login with read-only user in preparation for test
|
||||
loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('should not be able to upgrade prebuilt rules', () => {
|
||||
// Check that Rule Update tab is not shown
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
|
||||
// Navigate to Rule Update tab anyways via URL
|
||||
// and assert that rules cannot be selected and all
|
||||
// upgrade buttons are disabled
|
||||
cy.visit(`${APP_PATH}${RULES_UPDATES}`);
|
||||
cy.get(UPGRADE_ALL_RULES_BUTTON).should('be.disabled');
|
||||
cy.get(getUpgradeSingleRuleButtonByRuleId(OUTDATED_RULE_1['security-rule'].rule_id)).should(
|
||||
'not.exist'
|
||||
);
|
||||
cy.get(RULE_CHECKBOX).should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules';
|
||||
import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
addElasticRulesButtonClick,
|
||||
assertRuleAvailableForInstallAndInstallOne,
|
||||
assertRuleAvailableForInstallAndInstallSelected,
|
||||
assertRuleAvailableForInstallAndInstallAllInPage,
|
||||
assertRuleAvailableForInstallAndInstallAll,
|
||||
assertRuleUpgradeAvailableAndUpgradeOne,
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected,
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage,
|
||||
assertRuleUpgradeAvailableAndUpgradeAll,
|
||||
ruleUpdatesTabClick,
|
||||
} from '../../../tasks/prebuilt_rules';
|
||||
|
||||
describe('Detection rules, Prebuilt Rules Installation and Update - Error handling', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
});
|
||||
|
||||
describe('Installation of prebuilt rules - Should fail gracefully with toast error message when', () => {
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
beforeEach(() => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('installing prebuilt rules one by one', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1], didRequestFail: true });
|
||||
});
|
||||
|
||||
it('installing multiple selected prebuilt rules by selecting them individually', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallSelected({
|
||||
rules: [RULE_1, RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('installing multiple selected prebuilt rules by selecting all in page', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAllInPage({
|
||||
rules: [RULE_1, RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('installing all available rules at once', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAll({ rules: [RULE_1, RULE_2], didRequestFail: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update of prebuilt rules - Should fail gracefully with toast error message when', () => {
|
||||
const RULE_1_ID = 'rule_1';
|
||||
const RULE_2_ID = 'rule_2';
|
||||
const OUTDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 2,
|
||||
});
|
||||
const OUTDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 2,
|
||||
});
|
||||
beforeEach(() => {
|
||||
/* Create a new rule and install it */
|
||||
createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
/* Create a second version of the rule, making it available for update */
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
|
||||
installToKibana: false,
|
||||
});
|
||||
waitForRulesTableToBeLoaded();
|
||||
reload();
|
||||
});
|
||||
|
||||
it('upgrading prebuilt rules one by one', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1], didRequestFail: true });
|
||||
});
|
||||
|
||||
it('upgrading multiple selected prebuilt rules by selecting them individually', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected({
|
||||
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('upgrading multiple selected prebuilt rules by selecting all in page', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage({
|
||||
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('upgrading all rules with available upgrades at once', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAll({
|
||||
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { BulkInstallPackageInfo } from '@kbn/fleet-plugin/common';
|
||||
import type { Rule } from '../../../../public/detection_engine/rule_management/logic/types';
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import {
|
||||
GO_BACK_TO_RULES_TABLE_BUTTON,
|
||||
INSTALL_ALL_RULES_BUTTON,
|
||||
INSTALL_SELECTED_RULES_BUTTON,
|
||||
NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE,
|
||||
NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE,
|
||||
RULES_UPDATES_TAB,
|
||||
RULE_CHECKBOX,
|
||||
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
|
||||
TOASTER,
|
||||
} from '../../../screens/alerts_detection_rules';
|
||||
import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
getRuleAssets,
|
||||
createAndInstallMockedPrebuiltRules,
|
||||
} from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
addElasticRulesButtonClick,
|
||||
assertRuleAvailableForInstallAndInstallOne,
|
||||
assertRuleAvailableForInstallAndInstallSelected,
|
||||
assertRuleAvailableForInstallAndInstallAllInPage,
|
||||
assertRuleAvailableForInstallAndInstallAll,
|
||||
assertRuleUpgradeAvailableAndUpgradeOne,
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected,
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage,
|
||||
assertRuleUpgradeAvailableAndUpgradeAll,
|
||||
ruleUpdatesTabClick,
|
||||
} from '../../../tasks/prebuilt_rules';
|
||||
|
||||
describe('Detection rules, Prebuilt Rules Installation and Update workflow', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
});
|
||||
|
||||
describe('Installation of prebuilt rules package via Fleet', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', '/api/fleet/epm/packages/_bulk*').as('installPackageBulk');
|
||||
cy.intercept('POST', '/api/fleet/epm/packages/security_detection_engine/*').as(
|
||||
'installPackage'
|
||||
);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('should install package from Fleet in the background', () => {
|
||||
/* Assert that the package in installed from Fleet */
|
||||
cy.wait('@installPackageBulk', {
|
||||
timeout: 60000,
|
||||
}).then(({ response: bulkResponse }) => {
|
||||
cy.wrap(bulkResponse?.statusCode).should('eql', 200);
|
||||
|
||||
const packages = bulkResponse?.body.items.map(
|
||||
({ name, result }: BulkInstallPackageInfo) => ({
|
||||
name,
|
||||
})
|
||||
);
|
||||
|
||||
const packagesBulkInstalled = packages.map(({ name }: { name: string }) => name);
|
||||
|
||||
// Under normal flow the package is installed via the Fleet bulk install API.
|
||||
// However, for testing purposes the package can be installed via the Fleet individual install API,
|
||||
// so we need to intercept and wait for that request as well.
|
||||
if (!packagesBulkInstalled.includes('security_detection_engine')) {
|
||||
// Should happen only during testing when the `xpack.securitySolution.prebuiltRulesPackageVersion` flag is set
|
||||
cy.wait('@installPackage').then(({ response }) => {
|
||||
cy.wrap(response?.statusCode).should('eql', 200);
|
||||
cy.wrap(response?.body)
|
||||
.should('have.property', 'items')
|
||||
.should('have.length.greaterThan', 0);
|
||||
});
|
||||
} else {
|
||||
// Normal flow, install via the Fleet bulk install API
|
||||
expect(packages.length).to.have.greaterThan(0);
|
||||
// At least one of the packages installed should be the security_detection_engine package
|
||||
expect(packages).to.satisfy((pckgs: BulkInstallPackageInfo[]) =>
|
||||
pckgs.some((pkg) => pkg.name === 'security_detection_engine')
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should install rules from the Fleet package when user clicks on CTA', () => {
|
||||
const getRulesAndAssertNumberInstalled = () => {
|
||||
getRuleAssets().then((response) => {
|
||||
const ruleIds = response.body.hits.hits.map(
|
||||
(hit: { _source: { ['security-rule']: Rule } }) => hit._source['security-rule'].rule_id
|
||||
);
|
||||
|
||||
const numberOfRulesToInstall = new Set(ruleIds).size;
|
||||
addElasticRulesButtonClick();
|
||||
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).should('be.enabled').click();
|
||||
cy.get(TOASTER)
|
||||
.should('be.visible')
|
||||
.should('have.text', `${numberOfRulesToInstall} rules installed successfully.`);
|
||||
});
|
||||
};
|
||||
/* Retrieve how many rules were installed from the Fleet package */
|
||||
/* See comments in test above for more details */
|
||||
cy.wait('@installPackageBulk', {
|
||||
timeout: 60000,
|
||||
}).then(({ response: bulkResponse }) => {
|
||||
cy.wrap(bulkResponse?.statusCode).should('eql', 200);
|
||||
|
||||
const packagesBulkInstalled = bulkResponse?.body.items.map(
|
||||
({ name }: { name: string }) => name
|
||||
);
|
||||
|
||||
if (!packagesBulkInstalled.includes('security_detection_engine')) {
|
||||
cy.wait('@installPackage').then(() => {
|
||||
getRulesAndAssertNumberInstalled();
|
||||
});
|
||||
} else {
|
||||
getRulesAndAssertNumberInstalled();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Installation of prebuilt rules', () => {
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
beforeEach(() => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
|
||||
waitForRulesTableToBeLoaded();
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform').as(
|
||||
'installPrebuiltRules'
|
||||
);
|
||||
});
|
||||
|
||||
it('should install prebuilt rules one by one', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1] });
|
||||
});
|
||||
|
||||
it('should install multiple selected prebuilt rules by selecting them individually', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallSelected({ rules: [RULE_1, RULE_2] });
|
||||
});
|
||||
|
||||
it('should install multiple selected prebuilt rules by selecting all in page', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAllInPage({ rules: [RULE_1, RULE_2] });
|
||||
});
|
||||
|
||||
it('should install all available rules at once', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAll({ rules: [RULE_1, RULE_2] });
|
||||
});
|
||||
|
||||
it('should display an empty screen when all available prebuilt rules have been installed', () => {
|
||||
addElasticRulesButtonClick();
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).click();
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', `2 rules installed successfully.`);
|
||||
cy.get(RULE_CHECKBOX).should('not.exist');
|
||||
cy.get(NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE).should('exist');
|
||||
cy.get(GO_BACK_TO_RULES_TABLE_BUTTON).should('exist');
|
||||
});
|
||||
|
||||
it('should fail gracefully with toast error message when request to install rules fails', () => {
|
||||
/* Stub request to force rules installation to fail */
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform', {
|
||||
statusCode: 500,
|
||||
}).as('installPrebuiltRules');
|
||||
addElasticRulesButtonClick();
|
||||
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click();
|
||||
cy.get(INSTALL_SELECTED_RULES_BUTTON).click();
|
||||
cy.wait('@installPrebuiltRules');
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', 'Rule installation failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Upgrade of prebuilt rules', () => {
|
||||
const RULE_1_ID = 'rule_1';
|
||||
const RULE_2_ID = 'rule_2';
|
||||
const OUTDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 2,
|
||||
});
|
||||
const OUTDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 2,
|
||||
});
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/upgrade/_perform').as(
|
||||
'updatePrebuiltRules'
|
||||
);
|
||||
/* Create a new rule and install it */
|
||||
createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
/* Create a second version of the rule, making it available for update */
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
|
||||
installToKibana: false,
|
||||
});
|
||||
waitForRulesTableToBeLoaded();
|
||||
reload();
|
||||
});
|
||||
|
||||
it('should upgrade prebuilt rules one by one', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1] });
|
||||
});
|
||||
|
||||
it('should upgrade multiple selected prebuilt rules by selecting them individually', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
});
|
||||
|
||||
it('should upgrade multiple selected prebuilt rules by selecting all in page', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
});
|
||||
|
||||
it('should upgrade all rules with available upgrades at once', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
|
||||
it('should display an empty screen when all rules with available updates have been upgraded', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
cy.get(NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE).should('exist');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import { ADD_ELASTIC_RULES_BTN, RULES_UPDATES_TAB } from '../../../screens/alerts_detection_rules';
|
||||
import {
|
||||
deleteFirstRule,
|
||||
waitForRulesTableToBeLoaded,
|
||||
} from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
installAllPrebuiltRulesRequest,
|
||||
createAndInstallMockedPrebuiltRules,
|
||||
} from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import {
|
||||
resetRulesTableState,
|
||||
deleteAlertsAndRules,
|
||||
reload,
|
||||
deletePrebuiltRulesAssets,
|
||||
} from '../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
|
||||
describe('Detection rules, Prebuilt Rules Installation and Update Notifications', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
/* Make sure persisted rules table state is cleared */
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
deletePrebuiltRulesAssets();
|
||||
});
|
||||
|
||||
describe('No notifications', () => {
|
||||
it('should NOT display install or update notifications when no prebuilt assets and no rules are installed', () => {
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
// TODO: test plan asserts "should NOT see a CTA to install prebuilt rules"
|
||||
// but current behavior is to always show the CTA, even with no prebuilt rule assets installed
|
||||
// Update that behaviour and then update this test.
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
|
||||
it('should NOT display install or update notifications when latest rules are installed', () => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: true });
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
|
||||
/* Assert that there are no installation or update notifications */
|
||||
/* Add Elastic Rules button should not contain a number badge */
|
||||
/* and Rule Upgrade tab should not be displayed */
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', 'Add Elastic rules');
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Notifications', () => {
|
||||
beforeEach(() => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: false });
|
||||
});
|
||||
|
||||
describe('Rules installation notification when no rules have been installed', () => {
|
||||
beforeEach(() => {
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules available for installation', () => {
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible');
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`);
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rule installation notification when at least one rule already installed', () => {
|
||||
beforeEach(() => {
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
/* Create new rule assets with a different rule_id as the one that was */
|
||||
/* installed before in order to trigger the installation notification */
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
const RULE_3 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 3',
|
||||
rule_id: 'rule_3',
|
||||
});
|
||||
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_2, RULE_3], installToKibana: false });
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules available for installation', () => {
|
||||
const numberOfAvailableRules = 2;
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible');
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should(
|
||||
'have.text',
|
||||
`Add Elastic rules${numberOfAvailableRules}`
|
||||
);
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
|
||||
it('should notify user a rule is again available for installation if it is deleted', () => {
|
||||
/* Install available rules, assert that the notification is gone */
|
||||
/* then delete one rule and assert that the notification is back */
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
reload();
|
||||
deleteFirstRule();
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible');
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rule update notification', () => {
|
||||
beforeEach(() => {
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
/* Create new rule asset with the same rule_id as the one that was installed */
|
||||
/* but with a higher version, in order to trigger the update notification */
|
||||
const UPDATED_RULE = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1.1 (updated)',
|
||||
rule_id: 'rule_1',
|
||||
version: 2,
|
||||
});
|
||||
createAndInstallMockedPrebuiltRules({ rules: [UPDATED_RULE], installToKibana: false });
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
reload();
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules package available for update', () => {
|
||||
// No rules available for installation
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules`);
|
||||
// But 1 rule available for update
|
||||
cy.get(RULES_UPDATES_TAB).should('be.visible');
|
||||
cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rule installation available and rule update available notifications', () => {
|
||||
beforeEach(() => {
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
/* Create new rule assets with a different rule_id as the one that was */
|
||||
/* installed before in order to trigger the installation notification */
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
/* Create new rule asset with the same rule_id as the one that was installed */
|
||||
/* but with a higher version, in order to trigger the update notification */
|
||||
const UPDATED_RULE = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1.1 (updated)',
|
||||
rule_id: 'rule_1',
|
||||
version: 2,
|
||||
});
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [RULE_2, UPDATED_RULE],
|
||||
installToKibana: false,
|
||||
});
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules available for installation and for upgrade', () => {
|
||||
// 1 rule available for installation
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`);
|
||||
// 1 rule available for update
|
||||
cy.get(RULES_UPDATES_TAB).should('be.visible');
|
||||
cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getIndexConnector } from '../../../objects/connector';
|
||||
import { getSimpleCustomQueryRule } from '../../../objects/rule';
|
||||
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import { deleteIndex, waitForNewDocumentToBeIndexed } from '../../../tasks/api_calls/elasticsearch';
|
||||
import {
|
||||
cleanKibana,
|
||||
deleteAlertsAndRules,
|
||||
deleteConnectors,
|
||||
deleteDataView,
|
||||
} from '../../../tasks/common';
|
||||
import {
|
||||
createAndEnableRule,
|
||||
fillAboutRuleAndContinue,
|
||||
fillDefineCustomRuleAndContinue,
|
||||
fillRuleAction,
|
||||
fillScheduleRuleAndContinue,
|
||||
} from '../../../tasks/create_new_rule';
|
||||
import { login, visit } from '../../../tasks/login';
|
||||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe('Rule actions during detection rule creation', () => {
|
||||
const indexConnector = getIndexConnector();
|
||||
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
deleteConnectors();
|
||||
deleteIndex(indexConnector.index);
|
||||
deleteDataView(indexConnector.index);
|
||||
});
|
||||
|
||||
const rule = getSimpleCustomQueryRule();
|
||||
const actions = { connectors: [indexConnector] };
|
||||
const index = actions.connectors[0].index;
|
||||
const initialNumberOfDocuments = 0;
|
||||
const expectedJson = JSON.parse(actions.connectors[0].document);
|
||||
|
||||
it('Indexes a new document after the index action is triggered ', function () {
|
||||
visit(RULE_CREATION);
|
||||
fillDefineCustomRuleAndContinue(rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
fillRuleAction(actions);
|
||||
createAndEnableRule();
|
||||
goToRuleDetails();
|
||||
|
||||
/* When the rule is executed, the action is triggered. We wait for the new document to be indexed */
|
||||
waitForNewDocumentToBeIndexed(index, initialNumberOfDocuments);
|
||||
|
||||
/* We assert that the new indexed document is the one set on the index action */
|
||||
cy.request({
|
||||
method: 'GET',
|
||||
url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_search`,
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
}).then((response) => {
|
||||
expect(response.body.hits.hits[0]._source).to.deep.equal(expectedJson);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,221 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import { ROLES } from '../../../../../../common/test';
|
||||
|
||||
import {
|
||||
RULES_BULK_EDIT_ACTIONS_INFO,
|
||||
RULES_BULK_EDIT_ACTIONS_WARNING,
|
||||
ADD_RULE_ACTIONS_MENU_ITEM,
|
||||
} from '../../../../../screens/rules_bulk_actions';
|
||||
import { actionFormSelector } from '../../../../../screens/common/rule_actions';
|
||||
|
||||
import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common';
|
||||
import type { RuleActionCustomFrequency } from '../../../../../tasks/common/rule_actions';
|
||||
import {
|
||||
addSlackRuleAction,
|
||||
assertSlackRuleAction,
|
||||
addEmailConnectorAndRuleAction,
|
||||
assertEmailRuleAction,
|
||||
assertSelectedCustomFrequencyOption,
|
||||
assertSelectedPerRuleRunFrequencyOption,
|
||||
assertSelectedSummaryOfAlertsOption,
|
||||
pickCustomFrequencyOption,
|
||||
pickPerRuleRunFrequencyOption,
|
||||
pickSummaryOfAlertsOption,
|
||||
} from '../../../../../tasks/common/rule_actions';
|
||||
import {
|
||||
waitForRulesTableToBeLoaded,
|
||||
selectNumberOfRules,
|
||||
goToEditRuleActionsSettingsOf,
|
||||
} from '../../../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
waitForBulkEditActionToFinish,
|
||||
submitBulkEditForm,
|
||||
checkOverwriteRuleActionsCheckbox,
|
||||
openBulkEditRuleActionsForm,
|
||||
openBulkActionsMenu,
|
||||
} from '../../../../../tasks/rules_bulk_actions';
|
||||
import { login, visitWithoutDateRange } from '../../../../../tasks/login';
|
||||
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation';
|
||||
|
||||
import { createRule } from '../../../../../tasks/api_calls/rules';
|
||||
import { createSlackConnector } from '../../../../../tasks/api_calls/connectors';
|
||||
|
||||
import {
|
||||
getEqlRule,
|
||||
getNewThreatIndicatorRule,
|
||||
getNewRule,
|
||||
getNewThresholdRule,
|
||||
getMachineLearningRule,
|
||||
getNewTermsRule,
|
||||
} from '../../../../../objects/rule';
|
||||
import { excessivelyInstallAllPrebuiltRules } from '../../../../../tasks/api_calls/prebuilt_rules';
|
||||
|
||||
const ruleNameToAssert = 'Custom rule name with actions';
|
||||
const expectedNumberOfCustomRulesToBeEdited = 7;
|
||||
// 7 custom rules of different types + 3 prebuilt.
|
||||
// number of selected rules doesn't matter, we only want to make sure they will be edited an no modal window displayed as for other actions
|
||||
const expectedNumberOfRulesToBeEdited = expectedNumberOfCustomRulesToBeEdited + 3;
|
||||
|
||||
const expectedExistingSlackMessage = 'Existing slack action';
|
||||
const expectedSlackMessage = 'Slack action test message';
|
||||
|
||||
// TODO: Fix flakiness and unskip https://github.com/elastic/kibana/issues/154721
|
||||
describe.skip('Detection rules, bulk edit of rule actions', () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
deleteConnectors();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
createSlackConnector().then(({ body }) => {
|
||||
const actions: RuleActionArray = [
|
||||
{
|
||||
id: body.id,
|
||||
action_type_id: '.slack',
|
||||
group: 'default',
|
||||
params: {
|
||||
message: expectedExistingSlackMessage,
|
||||
},
|
||||
frequency: {
|
||||
summary: true,
|
||||
throttle: null,
|
||||
notifyWhen: 'onActiveAlert',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
createRule(getNewRule({ name: ruleNameToAssert, rule_id: '1', max_signals: 500, actions }));
|
||||
});
|
||||
|
||||
createRule(getEqlRule({ rule_id: '2' }));
|
||||
createRule(getMachineLearningRule({ rule_id: '3' }));
|
||||
createRule(getNewThreatIndicatorRule({ rule_id: '4' }));
|
||||
createRule(getNewThresholdRule({ rule_id: '5' }));
|
||||
createRule(getNewTermsRule({ rule_id: '6' }));
|
||||
createRule(getNewRule({ saved_id: 'mocked', rule_id: '7' }));
|
||||
|
||||
createSlackConnector();
|
||||
});
|
||||
|
||||
context('Restricted action privileges', () => {
|
||||
it("User with no privileges can't add rule actions", () => {
|
||||
login(ROLES.hunter_no_actions);
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL, ROLES.hunter_no_actions);
|
||||
waitForRulesTableToBeLoaded();
|
||||
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkActionsMenu();
|
||||
|
||||
cy.get(ADD_RULE_ACTIONS_MENU_ITEM).should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
context('All actions privileges', () => {
|
||||
beforeEach(() => {
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('Add a rule action to rules (existing connector)', () => {
|
||||
const expectedActionFrequency: RuleActionCustomFrequency = {
|
||||
throttle: 1,
|
||||
throttleUnit: 'd',
|
||||
};
|
||||
|
||||
excessivelyInstallAllPrebuiltRules();
|
||||
|
||||
// select both custom and prebuilt rules
|
||||
selectNumberOfRules(expectedNumberOfRulesToBeEdited);
|
||||
openBulkEditRuleActionsForm();
|
||||
|
||||
// ensure rule actions info callout displayed on the form
|
||||
cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible');
|
||||
|
||||
addSlackRuleAction(expectedSlackMessage);
|
||||
pickSummaryOfAlertsOption();
|
||||
pickCustomFrequencyOption(expectedActionFrequency);
|
||||
|
||||
submitBulkEditForm();
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated
|
||||
goToEditRuleActionsSettingsOf(ruleNameToAssert);
|
||||
|
||||
assertSelectedSummaryOfAlertsOption();
|
||||
assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
|
||||
assertSlackRuleAction(expectedExistingSlackMessage, 0);
|
||||
assertSlackRuleAction(expectedSlackMessage, 1);
|
||||
// ensure there is no third action
|
||||
cy.get(actionFormSelector(2)).should('not.exist');
|
||||
});
|
||||
|
||||
it('Overwrite rule actions in rules', () => {
|
||||
excessivelyInstallAllPrebuiltRules();
|
||||
|
||||
// select both custom and prebuilt rules
|
||||
selectNumberOfRules(expectedNumberOfRulesToBeEdited);
|
||||
openBulkEditRuleActionsForm();
|
||||
|
||||
addSlackRuleAction(expectedSlackMessage);
|
||||
pickSummaryOfAlertsOption();
|
||||
pickPerRuleRunFrequencyOption();
|
||||
|
||||
// check overwrite box, ensure warning is displayed
|
||||
checkOverwriteRuleActionsCheckbox();
|
||||
cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains(
|
||||
`You're about to overwrite rule actions for ${expectedNumberOfRulesToBeEdited} selected rules`
|
||||
);
|
||||
|
||||
submitBulkEditForm();
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated
|
||||
goToEditRuleActionsSettingsOf(ruleNameToAssert);
|
||||
|
||||
assertSelectedSummaryOfAlertsOption();
|
||||
assertSelectedPerRuleRunFrequencyOption();
|
||||
assertSlackRuleAction(expectedSlackMessage);
|
||||
// ensure existing action was overwritten
|
||||
cy.get(actionFormSelector(1)).should('not.exist');
|
||||
});
|
||||
|
||||
it('Add a rule action to rules (new connector)', () => {
|
||||
const expectedActionFrequency: RuleActionCustomFrequency = {
|
||||
throttle: 2,
|
||||
throttleUnit: 'h',
|
||||
};
|
||||
const expectedEmail = 'test@example.com';
|
||||
const expectedSubject = 'Subject';
|
||||
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
openBulkEditRuleActionsForm();
|
||||
|
||||
addEmailConnectorAndRuleAction(expectedEmail, expectedSubject);
|
||||
pickSummaryOfAlertsOption();
|
||||
pickCustomFrequencyOption(expectedActionFrequency);
|
||||
|
||||
submitBulkEditForm();
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated
|
||||
goToEditRuleActionsSettingsOf(ruleNameToAssert);
|
||||
|
||||
assertSelectedSummaryOfAlertsOption();
|
||||
assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
|
||||
assertEmailRuleAction(expectedEmail, expectedSubject);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
RULES_BULK_EDIT_DATA_VIEWS_WARNING,
|
||||
RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX,
|
||||
} from '../../../../../screens/rules_bulk_actions';
|
||||
|
||||
import { DATA_VIEW_DETAILS, INDEX_PATTERNS_DETAILS } from '../../../../../screens/rule_details';
|
||||
|
||||
import {
|
||||
waitForRulesTableToBeLoaded,
|
||||
goToRuleDetails,
|
||||
selectNumberOfRules,
|
||||
goToTheRuleDetailsOf,
|
||||
} from '../../../../../tasks/alerts_detection_rules';
|
||||
|
||||
import {
|
||||
typeIndexPatterns,
|
||||
waitForBulkEditActionToFinish,
|
||||
submitBulkEditForm,
|
||||
checkOverwriteDataViewCheckbox,
|
||||
checkOverwriteIndexPatternsCheckbox,
|
||||
openBulkEditAddIndexPatternsForm,
|
||||
openBulkEditDeleteIndexPatternsForm,
|
||||
} from '../../../../../tasks/rules_bulk_actions';
|
||||
|
||||
import {
|
||||
hasIndexPatterns,
|
||||
getDetails,
|
||||
assertDetailsNotExist,
|
||||
} from '../../../../../tasks/rule_details';
|
||||
import { login, visitWithoutDateRange } from '../../../../../tasks/login';
|
||||
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation';
|
||||
import { createRule } from '../../../../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules, postDataView } from '../../../../../tasks/common';
|
||||
|
||||
import {
|
||||
getEqlRule,
|
||||
getNewThreatIndicatorRule,
|
||||
getNewRule,
|
||||
getNewThresholdRule,
|
||||
getNewTermsRule,
|
||||
} from '../../../../../objects/rule';
|
||||
|
||||
const DATA_VIEW_ID = 'auditbeat';
|
||||
|
||||
const expectedIndexPatterns = ['index-1-*', 'index-2-*'];
|
||||
|
||||
const expectedNumberOfCustomRulesToBeEdited = 6;
|
||||
|
||||
describe('Bulk editing index patterns of rules with a data view only', () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
login();
|
||||
|
||||
postDataView(DATA_VIEW_ID);
|
||||
|
||||
createRule(getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '1' }));
|
||||
createRule(getEqlRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '2' }));
|
||||
createRule(
|
||||
getNewThreatIndicatorRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '3' })
|
||||
);
|
||||
createRule(getNewThresholdRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '4' }));
|
||||
createRule(getNewTermsRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '5' }));
|
||||
createRule(
|
||||
getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, saved_id: 'mocked', rule_id: '6' })
|
||||
);
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules with configured data view: all rules are skipped', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
skippedCount: expectedNumberOfCustomRulesToBeEdited,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules with configured data view when data view checkbox is checked: rules are updated', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
|
||||
// click on data view overwrite checkbox, ensure warning is displayed
|
||||
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('not.exist');
|
||||
checkOverwriteDataViewCheckbox();
|
||||
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('be.visible');
|
||||
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated with index patterns and data view does not exist
|
||||
goToRuleDetails();
|
||||
hasIndexPatterns(expectedIndexPatterns.join(''));
|
||||
assertDetailsNotExist(DATA_VIEW_DETAILS);
|
||||
});
|
||||
|
||||
it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is NOT checked:: rules are skipped', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
checkOverwriteIndexPatternsCheckbox();
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
skippedCount: expectedNumberOfCustomRulesToBeEdited,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
|
||||
});
|
||||
|
||||
it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is checked: rules are updated', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
checkOverwriteIndexPatternsCheckbox();
|
||||
checkOverwriteDataViewCheckbox();
|
||||
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
|
||||
|
||||
// check if rule has been overwritten with index patterns and data view does not exist
|
||||
goToRuleDetails();
|
||||
hasIndexPatterns(expectedIndexPatterns.join(''));
|
||||
assertDetailsNotExist(DATA_VIEW_DETAILS);
|
||||
});
|
||||
|
||||
it('Delete index patterns in custom rules with configured data view: rules are skipped', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditDeleteIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
|
||||
// in delete form data view checkbox is absent
|
||||
cy.get(RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX).should('not.exist');
|
||||
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
skippedCount: expectedNumberOfCustomRulesToBeEdited,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Bulk editing index patterns of rules with index patterns and rules with a data view', () => {
|
||||
const customRulesNumber = 2;
|
||||
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
postDataView(DATA_VIEW_ID);
|
||||
|
||||
createRule(
|
||||
getNewRule({ name: 'with dataview', index: [], data_view_id: DATA_VIEW_ID, rule_id: '1' })
|
||||
);
|
||||
createRule(getNewRule({ name: 'no data view', index: ['test-index-1-*'], rule_id: '2' }));
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules: one rule is updated, one rule is skipped', () => {
|
||||
selectNumberOfRules(customRulesNumber);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
updatedCount: 1,
|
||||
skippedCount: 1,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToTheRuleDetailsOf('with dataview');
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules when overwrite data view checkbox is checked: all rules are updated', () => {
|
||||
selectNumberOfRules(customRulesNumber);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
checkOverwriteDataViewCheckbox();
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
updatedCount: 2,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
assertDetailsNotExist(DATA_VIEW_DETAILS);
|
||||
});
|
||||
});
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import {
|
||||
expandFirstAlert,
|
||||
goToClosedAlertsOnRuleDetailsPage,
|
||||
openAddEndpointExceptionFromAlertActionButton,
|
||||
openAddEndpointExceptionFromFirstAlert,
|
||||
waitForAlerts,
|
||||
} from '../../../tasks/alerts';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { getEndpointRule } from '../../../objects/rule';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import {
|
||||
waitForAlertsToPopulate,
|
||||
waitForTheRuleToBeExecuted,
|
||||
} from '../../../tasks/create_new_rule';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
addExceptionEntryFieldValueAndSelectSuggestion,
|
||||
addExceptionEntryFieldValueValue,
|
||||
addExceptionFlyoutItemName,
|
||||
editExceptionFlyoutItemName,
|
||||
selectCloseSingleAlerts,
|
||||
submitNewExceptionItem,
|
||||
validateExceptionConditionField,
|
||||
} from '../../../tasks/exceptions';
|
||||
import { ALERTS_COUNT } from '../../../screens/alerts';
|
||||
import {
|
||||
ADD_AND_BTN,
|
||||
EXCEPTION_CARD_ITEM_CONDITIONS,
|
||||
EXCEPTION_CARD_ITEM_NAME,
|
||||
EXCEPTION_ITEM_VIEWER_CONTAINER,
|
||||
} from '../../../screens/exceptions';
|
||||
import { goToEndpointExceptionsTab } from '../../../tasks/rule_details';
|
||||
|
||||
describe('Endpoint Exceptions workflows from Alert', () => {
|
||||
const ITEM_NAME = 'Sample Exception List Item';
|
||||
const ITEM_NAME_EDIT = 'Sample Exception List Item';
|
||||
const ADDITIONAL_ENTRY = 'host.hostname';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
cy.task('esArchiverResetKibana');
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverLoad', 'endpoint');
|
||||
createRule(getEndpointRule());
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForTheRuleToBeExecuted();
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
});
|
||||
|
||||
it('Should be able to create and close single Endpoint exception from overflow menu', () => {
|
||||
// The Endpoint will populated with predefined fields
|
||||
openAddEndpointExceptionFromFirstAlert();
|
||||
|
||||
// As the endpoint.alerts-* is used to trigger the alert the
|
||||
// file.Ext.code_signature will be auto-populated
|
||||
validateExceptionConditionField('file.Ext.code_signature');
|
||||
|
||||
selectCloseSingleAlerts();
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
submitNewExceptionItem();
|
||||
|
||||
// Instead of immediately checking if the Opened Alert has moved to the closed tab,
|
||||
// use the waitForAlerts method to create a buffer, allowing the alerts some time to
|
||||
// be moved to the Closed Alert tab.
|
||||
waitForAlerts();
|
||||
|
||||
// Closed alert should appear in table
|
||||
goToClosedAlertsOnRuleDetailsPage();
|
||||
cy.get(ALERTS_COUNT).should('exist');
|
||||
});
|
||||
|
||||
it('Should be able to create Endpoint exception from Alerts take action button, and change multiple exception items without resetting to initial auto-prefilled entries', () => {
|
||||
// Open first Alert Summary
|
||||
expandFirstAlert();
|
||||
|
||||
// The Endpoint should populated with predefined fields
|
||||
openAddEndpointExceptionFromAlertActionButton();
|
||||
|
||||
// As the endpoint.alerts-* is used to trigger the alert the
|
||||
// file.Ext.code_signature will be auto-populated
|
||||
validateExceptionConditionField('file.Ext.code_signature');
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
|
||||
cy.get(ADD_AND_BTN).click();
|
||||
// edit conditions
|
||||
addExceptionEntryFieldValueAndSelectSuggestion(ADDITIONAL_ENTRY, 6);
|
||||
addExceptionEntryFieldValueValue('foo', 4);
|
||||
|
||||
// Change the name again
|
||||
editExceptionFlyoutItemName(ITEM_NAME_EDIT);
|
||||
|
||||
// validate the condition is still "agent.name" or got rest after the name is changed
|
||||
validateExceptionConditionField(ADDITIONAL_ENTRY);
|
||||
|
||||
selectCloseSingleAlerts();
|
||||
submitNewExceptionItem();
|
||||
|
||||
// Endpoint Exception will move to Endpoint List under Exception tab of rule
|
||||
goToEndpointExceptionsTab();
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', ADDITIONAL_ENTRY);
|
||||
});
|
||||
});
|
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { LOADING_INDICATOR } from '../../../../screens/security_header';
|
||||
import { getEndpointRule } from '../../../../objects/rule';
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
addExceptionFromFirstAlert,
|
||||
expandFirstAlert,
|
||||
openAddRuleExceptionFromAlertActionButton,
|
||||
} from '../../../../tasks/alerts';
|
||||
import {
|
||||
addExceptionEntryFieldValue,
|
||||
addExceptionEntryFieldValueValue,
|
||||
addExceptionFlyoutItemName,
|
||||
submitNewExceptionItem,
|
||||
validateExceptionConditionField,
|
||||
validateExceptionCommentCountAndText,
|
||||
editExceptionFlyoutItemName,
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions,
|
||||
validateEmptyExceptionConditionField,
|
||||
} from '../../../../tasks/exceptions';
|
||||
import { login, visitWithoutDateRange } from '../../../../tasks/login';
|
||||
import { goToExceptionsTab } from '../../../../tasks/rule_details';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation';
|
||||
import { deleteAlertsAndRules } from '../../../../tasks/common';
|
||||
import {
|
||||
ADD_AND_BTN,
|
||||
ENTRY_DELETE_BTN,
|
||||
EXCEPTION_CARD_ITEM_CONDITIONS,
|
||||
EXCEPTION_CARD_ITEM_NAME,
|
||||
EXCEPTION_ITEM_VIEWER_CONTAINER,
|
||||
} from '../../../../screens/exceptions';
|
||||
import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule';
|
||||
|
||||
describe('Auto populate exception with Alert data', () => {
|
||||
const ITEM_NAME = 'Sample Exception Item';
|
||||
const ITEM_NAME_EDIT = 'Sample Exception Item Edit';
|
||||
const ADDITIONAL_ENTRY = 'host.hostname';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
cy.task('esArchiverResetKibana');
|
||||
cy.task('esArchiverLoad', 'endpoint');
|
||||
login();
|
||||
createRule(getEndpointRule());
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
deleteAlertsAndRules();
|
||||
});
|
||||
afterEach(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
});
|
||||
|
||||
it('Should create a Rule exception item from alert actions overflow menu and auto populate the conditions using alert Highlighted fields', () => {
|
||||
cy.get(LOADING_INDICATOR).should('not.exist');
|
||||
addExceptionFromFirstAlert();
|
||||
|
||||
const highlightedFieldsBasedOnAlertDoc = [
|
||||
'host.name',
|
||||
'agent.id',
|
||||
'user.name',
|
||||
'process.executable',
|
||||
'file.path',
|
||||
];
|
||||
|
||||
/**
|
||||
* Validate the highlighted fields are auto populated, these
|
||||
* fields are based on the alert document that should be generated
|
||||
* when the endpoint rule runs
|
||||
*/
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc);
|
||||
|
||||
/**
|
||||
* Validate that the comments are opened by default with one comment added
|
||||
* showing a text contains information about the pre-filled conditions
|
||||
*/
|
||||
validateExceptionCommentCountAndText(
|
||||
1,
|
||||
'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):'
|
||||
);
|
||||
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
submitNewExceptionItem();
|
||||
});
|
||||
it('Should create a Rule exception from Alerts take action button and change multiple exception items without resetting to initial auto-prefilled entries', () => {
|
||||
cy.get(LOADING_INDICATOR).should('not.exist');
|
||||
|
||||
// Open first Alert Summary
|
||||
expandFirstAlert();
|
||||
|
||||
// The Rule exception should populated with highlighted fields
|
||||
openAddRuleExceptionFromAlertActionButton();
|
||||
|
||||
const highlightedFieldsBasedOnAlertDoc = [
|
||||
'host.name',
|
||||
'agent.id',
|
||||
'user.name',
|
||||
'process.executable',
|
||||
'file.path',
|
||||
];
|
||||
|
||||
/**
|
||||
* Validate the highlighted fields are auto populated, these
|
||||
* fields are based on the alert document that should be generated
|
||||
* when the endpoint rule runs
|
||||
*/
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc);
|
||||
|
||||
/**
|
||||
* Validate that the comments are opened by default with one comment added
|
||||
* showing a text contains information about the pre-filled conditions
|
||||
*/
|
||||
validateExceptionCommentCountAndText(
|
||||
1,
|
||||
'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):'
|
||||
);
|
||||
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
|
||||
cy.get(ADD_AND_BTN).click();
|
||||
|
||||
// edit conditions
|
||||
addExceptionEntryFieldValue(ADDITIONAL_ENTRY, 5);
|
||||
addExceptionEntryFieldValueValue('foo', 5);
|
||||
|
||||
// Change the name again
|
||||
editExceptionFlyoutItemName(ITEM_NAME_EDIT);
|
||||
|
||||
// validate the condition is still 'host.hostname' or got rest after the name is changed
|
||||
validateExceptionConditionField(ADDITIONAL_ENTRY);
|
||||
|
||||
submitNewExceptionItem();
|
||||
|
||||
goToExceptionsTab();
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', 'host.hostname');
|
||||
});
|
||||
it('Should delete all prefilled exception entries when creating a Rule exception from Alerts take action button without resetting to initial auto-prefilled entries', () => {
|
||||
cy.get(LOADING_INDICATOR).should('not.exist');
|
||||
|
||||
// Open first Alert Summary
|
||||
expandFirstAlert();
|
||||
|
||||
// The Rule exception should populated with highlighted fields
|
||||
openAddRuleExceptionFromAlertActionButton();
|
||||
|
||||
const highlightedFieldsBasedOnAlertDoc = [
|
||||
'host.name',
|
||||
'agent.id',
|
||||
'user.name',
|
||||
'process.executable',
|
||||
'file.path',
|
||||
];
|
||||
|
||||
/**
|
||||
* Validate the highlighted fields are auto populated, these
|
||||
* fields are based on the alert document that should be generated
|
||||
* when the endpoint rule runs
|
||||
*/
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc);
|
||||
|
||||
/**
|
||||
* Delete all the highlighted fields to see if any condition
|
||||
* will prefuilled again.
|
||||
*/
|
||||
const highlightedFieldsCount = highlightedFieldsBasedOnAlertDoc.length - 1;
|
||||
highlightedFieldsBasedOnAlertDoc.forEach((_, index) =>
|
||||
cy
|
||||
.get(ENTRY_DELETE_BTN)
|
||||
.eq(highlightedFieldsCount - index)
|
||||
.click()
|
||||
);
|
||||
|
||||
/**
|
||||
* Validate that there are no highlighted fields are auto populated
|
||||
* after the deletion
|
||||
*/
|
||||
validateEmptyExceptionConditionField();
|
||||
});
|
||||
});
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { ALERTS_COUNT, EMPTY_ALERT_TABLE } from '../../../screens/alerts';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
goToClosedAlertsOnRuleDetailsPage,
|
||||
goToOpenedAlertsOnRuleDetailsPage,
|
||||
} from '../../../tasks/alerts';
|
||||
import {
|
||||
editException,
|
||||
editExceptionFlyoutItemName,
|
||||
submitEditedExceptionItem,
|
||||
} from '../../../tasks/exceptions';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import {
|
||||
addFirstExceptionFromRuleDetails,
|
||||
goToAlertsTab,
|
||||
goToExceptionsTab,
|
||||
openEditException,
|
||||
removeException,
|
||||
waitForTheRuleToBeExecuted,
|
||||
} from '../../../tasks/rule_details';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
||||
import { postDataView, deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import {
|
||||
NO_EXCEPTIONS_EXIST_PROMPT,
|
||||
EXCEPTION_ITEM_VIEWER_CONTAINER,
|
||||
EXCEPTION_CARD_ITEM_NAME,
|
||||
EXCEPTION_CARD_ITEM_CONDITIONS,
|
||||
EXCEPTION_ITEM_CONTAINER,
|
||||
VALUES_INPUT,
|
||||
FIELD_INPUT_PARENT,
|
||||
} from '../../../screens/exceptions';
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
|
||||
describe('Add exception using data views from rule details', () => {
|
||||
const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert';
|
||||
const ITEM_NAME = 'Sample Exception List Item';
|
||||
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
cy.task('esArchiverLoad', 'exceptions');
|
||||
login();
|
||||
postDataView('exceptions-*');
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'exceptions');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createRule(
|
||||
getNewRule({
|
||||
query: 'agent.name:*',
|
||||
data_view_id: 'exceptions-*',
|
||||
interval: '10s',
|
||||
rule_id: 'rule_testing',
|
||||
})
|
||||
);
|
||||
login();
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.task('esArchiverUnload', 'exceptions_2');
|
||||
});
|
||||
|
||||
it('Creates an exception item and close all matching alerts', () => {
|
||||
goToExceptionsTab();
|
||||
// when no exceptions exist, empty component shows with action to add exception
|
||||
cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist');
|
||||
|
||||
// clicks prompt button to add first exception that will also select to close
|
||||
// all matching alerts
|
||||
addFirstExceptionFromRuleDetails(
|
||||
{
|
||||
field: 'agent.name',
|
||||
operator: 'is',
|
||||
values: ['foo'],
|
||||
},
|
||||
ITEM_NAME
|
||||
);
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
|
||||
// Alerts table should now be empty from having added exception and closed
|
||||
// matching alert
|
||||
goToAlertsTab();
|
||||
cy.get(EMPTY_ALERT_TABLE).should('exist');
|
||||
|
||||
// Closed alert should appear in table
|
||||
goToClosedAlertsOnRuleDetailsPage();
|
||||
cy.get(ALERTS_COUNT).should('exist');
|
||||
cy.get(ALERTS_COUNT).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`);
|
||||
|
||||
// Remove the exception and load an event that would have matched that exception
|
||||
// to show that said exception now starts to show up again
|
||||
goToExceptionsTab();
|
||||
|
||||
// when removing exception and again, no more exist, empty screen shows again
|
||||
removeException();
|
||||
cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist');
|
||||
|
||||
// load more docs
|
||||
cy.task('esArchiverLoad', 'exceptions_2');
|
||||
|
||||
// now that there are no more exceptions, the docs should match and populate alerts
|
||||
goToAlertsTab();
|
||||
goToOpenedAlertsOnRuleDetailsPage();
|
||||
waitForTheRuleToBeExecuted();
|
||||
waitForAlertsToPopulate();
|
||||
|
||||
cy.get(ALERTS_COUNT).should('exist');
|
||||
cy.get(ALERTS_COUNT).should('have.text', '2 alerts');
|
||||
});
|
||||
|
||||
it('Edits an exception item', () => {
|
||||
const NEW_ITEM_NAME = 'Exception item-EDITED';
|
||||
const ITEM_FIELD = 'unique_value.test';
|
||||
const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name';
|
||||
|
||||
goToExceptionsTab();
|
||||
// add item to edit
|
||||
addFirstExceptionFromRuleDetails(
|
||||
{
|
||||
field: ITEM_FIELD,
|
||||
operator: 'is',
|
||||
values: ['foo'],
|
||||
},
|
||||
ITEM_NAME
|
||||
);
|
||||
|
||||
// displays existing exception items
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist');
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' unique_value.testIS foo');
|
||||
|
||||
// open edit exception modal
|
||||
openEditException();
|
||||
|
||||
// edit exception item name
|
||||
editExceptionFlyoutItemName(NEW_ITEM_NAME);
|
||||
|
||||
// check that the existing item's field is being populated
|
||||
cy.get(EXCEPTION_ITEM_CONTAINER)
|
||||
.eq(0)
|
||||
.find(FIELD_INPUT_PARENT)
|
||||
.eq(0)
|
||||
.should('have.text', ITEM_FIELD);
|
||||
cy.get(VALUES_INPUT).should('have.text', 'foo');
|
||||
|
||||
// edit conditions
|
||||
editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0);
|
||||
|
||||
// submit
|
||||
submitEditedExceptionItem();
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
|
||||
// check that updates stuck
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.nameIS foo');
|
||||
});
|
||||
});
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { getExceptionList, expectedExportedExceptionList } from '../../../../objects/exception';
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../../../tasks/login';
|
||||
|
||||
import { EXCEPTIONS_URL } from '../../../../urls/navigation';
|
||||
import {
|
||||
deleteExceptionListWithoutRuleReferenceByListId,
|
||||
deleteExceptionListWithRuleReferenceByListId,
|
||||
exportExceptionList,
|
||||
waitForExceptionsTableToBeLoaded,
|
||||
createSharedExceptionList,
|
||||
linkRulesToExceptionList,
|
||||
assertNumberLinkedRules,
|
||||
} from '../../../../tasks/exceptions_table';
|
||||
import {
|
||||
EXCEPTIONS_LIST_MANAGEMENT_NAME,
|
||||
EXCEPTIONS_TABLE_SHOWING_LISTS,
|
||||
} from '../../../../screens/exceptions';
|
||||
import { createExceptionList } from '../../../../tasks/api_calls/exceptions';
|
||||
|
||||
import { TOASTER } from '../../../../screens/alerts_detection_rules';
|
||||
|
||||
const EXCEPTION_LIST_NAME = 'My test list';
|
||||
const EXCEPTION_LIST_TO_DUPLICATE_NAME = 'A test list 2';
|
||||
|
||||
const getExceptionList1 = () => ({
|
||||
...getExceptionList(),
|
||||
name: EXCEPTION_LIST_NAME,
|
||||
list_id: 'exception_list_1',
|
||||
});
|
||||
|
||||
const getExceptionList2 = () => ({
|
||||
...getExceptionList(),
|
||||
name: EXCEPTION_LIST_TO_DUPLICATE_NAME,
|
||||
list_id: 'exception_list_2',
|
||||
});
|
||||
|
||||
describe('Manage lists from "Shared Exception Lists" page', () => {
|
||||
describe('Create/Export/Delete List', () => {
|
||||
before(() => {
|
||||
createRule(getNewRule({ name: 'Another rule' }));
|
||||
|
||||
// Create exception list associated with a rule
|
||||
createExceptionList(getExceptionList2(), getExceptionList2().list_id).then((response) =>
|
||||
createRule(
|
||||
getNewRule({
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: getExceptionList2().list_id,
|
||||
type: getExceptionList2().type,
|
||||
namespace_type: getExceptionList2().namespace_type,
|
||||
},
|
||||
],
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// Create exception list not used by any rules
|
||||
createExceptionList(getExceptionList1(), getExceptionList1().list_id).as(
|
||||
'exceptionListResponse'
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithoutDateRange(EXCEPTIONS_URL);
|
||||
waitForExceptionsTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('Export exception list', function () {
|
||||
cy.intercept(/(\/api\/exception_lists\/_export)/).as('export');
|
||||
|
||||
exportExceptionList(getExceptionList1().list_id);
|
||||
|
||||
cy.wait('@export').then(({ response }) => {
|
||||
cy.wrap(response?.body).should(
|
||||
'eql',
|
||||
expectedExportedExceptionList(this.exceptionListResponse)
|
||||
);
|
||||
|
||||
cy.get(TOASTER).should(
|
||||
'have.text',
|
||||
`Exception list "${EXCEPTION_LIST_NAME}" exported successfully`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('Link rules to shared exception list', function () {
|
||||
assertNumberLinkedRules(getExceptionList2().list_id, '1');
|
||||
linkRulesToExceptionList(getExceptionList2().list_id, 1);
|
||||
assertNumberLinkedRules(getExceptionList2().list_id, '2');
|
||||
});
|
||||
|
||||
it('Create exception list', function () {
|
||||
createSharedExceptionList(
|
||||
{ name: 'Newly created list', description: 'This is my list.' },
|
||||
true
|
||||
);
|
||||
|
||||
// After creation - directed to list detail page
|
||||
cy.get(EXCEPTIONS_LIST_MANAGEMENT_NAME).should('have.text', 'Newly created list');
|
||||
});
|
||||
|
||||
it('Delete exception list without rule reference', () => {
|
||||
// Using cy.contains because we do not care about the exact text,
|
||||
// just checking number of lists shown
|
||||
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '4');
|
||||
|
||||
deleteExceptionListWithoutRuleReferenceByListId(getExceptionList1().list_id);
|
||||
|
||||
// Using cy.contains because we do not care about the exact text,
|
||||
// just checking number of lists shown
|
||||
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3');
|
||||
});
|
||||
|
||||
it('Deletes exception list with rule reference', () => {
|
||||
waitForPageWithoutDateRange(EXCEPTIONS_URL);
|
||||
waitForExceptionsTableToBeLoaded();
|
||||
|
||||
// Using cy.contains because we do not care about the exact text,
|
||||
// just checking number of lists shown
|
||||
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '3');
|
||||
|
||||
deleteExceptionListWithRuleReferenceByListId(getExceptionList2().list_id);
|
||||
|
||||
// Using cy.contains because we do not care about the exact text,
|
||||
// just checking number of lists shown
|
||||
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
import {
|
||||
CORRELATIONS_ANCESTRY_SECTION,
|
||||
CORRELATIONS_ANCESTRY_TABLE,
|
||||
CORRELATIONS_CASES_SECTION,
|
||||
CORRELATIONS_SESSION_SECTION,
|
||||
CORRELATIONS_SOURCE_SECTION,
|
||||
DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON,
|
||||
} from '../../../../screens/expandable_flyout/alert_details_left_panel_correlations_tab';
|
||||
import {
|
||||
DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB,
|
||||
DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP,
|
||||
} from '../../../../screens/expandable_flyout/alert_details_left_panel';
|
||||
import {
|
||||
expandCorrelationsSection,
|
||||
openCorrelationsTab,
|
||||
} from '../../../../tasks/expandable_flyout/alert_details_left_panel_correlations_tab';
|
||||
import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel';
|
||||
import { expandDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel';
|
||||
import {
|
||||
createNewCaseFromExpandableFlyout,
|
||||
expandFirstAlertExpandableFlyout,
|
||||
} from '../../../../tasks/expandable_flyout/common';
|
||||
import { cleanKibana } from '../../../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule';
|
||||
import { login, visit } from '../../../../tasks/login';
|
||||
import { ALERTS_URL } from '../../../../urls/navigation';
|
||||
|
||||
describe('Expandable flyout left panel correlations', () => {
|
||||
beforeEach(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createRule(getNewRule());
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
expandFirstAlertExpandableFlyout();
|
||||
expandDocumentDetailsExpandableFlyoutLeftSection();
|
||||
createNewCaseFromExpandableFlyout();
|
||||
openInsightsTab();
|
||||
openCorrelationsTab();
|
||||
});
|
||||
|
||||
it('should render correlations details correctly', () => {
|
||||
cy.log('link the alert to a new case');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).scrollIntoView();
|
||||
|
||||
cy.log('should render the Insights header');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).should('be.visible').and('have.text', 'Insights');
|
||||
|
||||
cy.log('should render the inner tab switch');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_BUTTON_GROUP).should('be.visible');
|
||||
|
||||
cy.log('should render correlations tab activator / button');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Correlations');
|
||||
|
||||
cy.log('should render all the correlations sections');
|
||||
|
||||
cy.get(CORRELATIONS_ANCESTRY_SECTION)
|
||||
.should('be.visible')
|
||||
.and('have.text', '1 alert related by ancestry');
|
||||
|
||||
cy.get(CORRELATIONS_SOURCE_SECTION)
|
||||
.should('be.visible')
|
||||
.and('have.text', '0 alerts related by source event');
|
||||
|
||||
cy.get(CORRELATIONS_SESSION_SECTION)
|
||||
.should('be.visible')
|
||||
.and('have.text', '1 alert related by session');
|
||||
|
||||
cy.get(CORRELATIONS_CASES_SECTION).should('be.visible').and('have.text', '1 related case');
|
||||
|
||||
expandCorrelationsSection(CORRELATIONS_ANCESTRY_SECTION);
|
||||
|
||||
cy.get(CORRELATIONS_ANCESTRY_TABLE).should('be.visible');
|
||||
});
|
||||
});
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { upperFirst } from 'lodash';
|
||||
import {
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_CREATE_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_DESCRIPTION_INPUT,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_NAME_INPUT,
|
||||
EXISTING_CASE_SELECT_BUTTON,
|
||||
VIEW_CASE_TOASTER_LINK,
|
||||
} from '../../../../screens/expandable_flyout/common';
|
||||
import {
|
||||
createNewCaseFromCases,
|
||||
expandFirstAlertExpandableFlyout,
|
||||
navigateToAlertsPage,
|
||||
navigateToCasesPage,
|
||||
} from '../../../../tasks/expandable_flyout/common';
|
||||
import { ALERT_CHECKBOX } from '../../../../screens/alerts';
|
||||
import { CASE_DETAILS_PAGE_TITLE } from '../../../../screens/case_details';
|
||||
import {
|
||||
DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND,
|
||||
DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_HEADER_CHAT_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE,
|
||||
DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE,
|
||||
DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY,
|
||||
DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE,
|
||||
DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS,
|
||||
DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE,
|
||||
DOCUMENT_DETAILS_FLYOUT_JSON_TAB,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB,
|
||||
DOCUMENT_DETAILS_FLYOUT_TABLE_TAB,
|
||||
} from '../../../../screens/expandable_flyout/alert_details_right_panel';
|
||||
import {
|
||||
collapseDocumentDetailsExpandableFlyoutLeftSection,
|
||||
expandDocumentDetailsExpandableFlyoutLeftSection,
|
||||
openJsonTab,
|
||||
openTableTab,
|
||||
openTakeActionButton,
|
||||
openTakeActionButtonAndSelectItem,
|
||||
selectTakeActionItem,
|
||||
} from '../../../../tasks/expandable_flyout/alert_details_right_panel';
|
||||
import { cleanKibana } from '../../../../tasks/common';
|
||||
import { login, visit } from '../../../../tasks/login';
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
import { ALERTS_URL } from '../../../../urls/navigation';
|
||||
import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule';
|
||||
|
||||
describe('Alert details expandable flyout right panel', () => {
|
||||
const rule = getNewRule();
|
||||
|
||||
beforeEach(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createRule(rule);
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
it('should display header and footer basics', () => {
|
||||
expandFirstAlertExpandableFlyout();
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).should('be.visible').and('have.text', rule.name);
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_CHAT_BUTTON).should('be.visible');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_STATUS).should('be.visible');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE).should('be.visible');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_RISK_SCORE_VALUE)
|
||||
.should('be.visible')
|
||||
.and('have.text', rule.risk_score);
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY).should('be.visible');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_SEVERITY_VALUE)
|
||||
.should('be.visible')
|
||||
.and('have.text', upperFirst(rule.severity));
|
||||
|
||||
cy.log('Verify all 3 tabs are visible');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB).should('be.visible').and('have.text', 'Overview');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB).should('be.visible').and('have.text', 'Table');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB).should('be.visible').and('have.text', 'JSON');
|
||||
|
||||
cy.log('Verify the expand/collapse button is visible and functionality works');
|
||||
|
||||
expandDocumentDetailsExpandableFlyoutLeftSection();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_COLLAPSE_DETAILS_BUTTON)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Collapse details');
|
||||
|
||||
collapseDocumentDetailsExpandableFlyoutLeftSection();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_EXPAND_DETAILS_BUTTON)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Expand details');
|
||||
|
||||
cy.log('Verify the take action button is visible on all tabs');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible');
|
||||
|
||||
openTableTab();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible');
|
||||
|
||||
openJsonTab();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible');
|
||||
});
|
||||
|
||||
// TODO this will change when add to existing case is improved
|
||||
// https://github.com/elastic/security-team/issues/6298
|
||||
it('should add to existing case', () => {
|
||||
navigateToCasesPage();
|
||||
createNewCaseFromCases();
|
||||
|
||||
cy.get(CASE_DETAILS_PAGE_TITLE).should('be.visible').and('have.text', 'case');
|
||||
navigateToAlertsPage();
|
||||
expandFirstAlertExpandableFlyout();
|
||||
openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_EXISTING_CASE);
|
||||
|
||||
cy.get(EXISTING_CASE_SELECT_BUTTON).should('be.visible').contains('Select').click();
|
||||
cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case');
|
||||
});
|
||||
|
||||
// TODO this will change when add to new case is improved
|
||||
// https://github.com/elastic/security-team/issues/6298
|
||||
it('should add to new case', () => {
|
||||
expandFirstAlertExpandableFlyout();
|
||||
openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE);
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_NAME_INPUT).type('case');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_DESCRIPTION_INPUT).type(
|
||||
'case description'
|
||||
);
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_TO_NEW_CASE_CREATE_BUTTON).click();
|
||||
|
||||
cy.get(VIEW_CASE_TOASTER_LINK).should('be.visible').and('contain.text', 'View case');
|
||||
});
|
||||
|
||||
it('should mark as acknowledged', () => {
|
||||
cy.get(ALERT_CHECKBOX).should('have.length', 2);
|
||||
|
||||
expandFirstAlertExpandableFlyout();
|
||||
openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_MARK_AS_ACKNOWLEDGED);
|
||||
|
||||
// TODO figure out how to verify the toasts pops up
|
||||
// cy.get(KIBANA_TOAST)
|
||||
// .should('be.visible')
|
||||
// .and('have.text', 'Successfully marked 1 alert as acknowledged.');
|
||||
cy.get(ALERT_CHECKBOX).should('have.length', 1);
|
||||
});
|
||||
|
||||
it('should mark as closed', () => {
|
||||
cy.get(ALERT_CHECKBOX).should('have.length', 2);
|
||||
|
||||
expandFirstAlertExpandableFlyout();
|
||||
openTakeActionButtonAndSelectItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_MARK_AS_CLOSED);
|
||||
|
||||
// TODO figure out how to verify the toasts pops up
|
||||
// cy.get(KIBANA_TOAST).should('be.visible').and('have.text', 'Successfully closed 1 alert.');
|
||||
cy.get(ALERT_CHECKBOX).should('have.length', 1);
|
||||
});
|
||||
|
||||
// these actions are now grouped together as we're not really testing their functionality but just the existence of the option in the dropdown
|
||||
it('should test other action within take action dropdown', () => {
|
||||
expandFirstAlertExpandableFlyout();
|
||||
|
||||
cy.log('should add endpoint exception');
|
||||
|
||||
// TODO figure out why this option is disabled in Cypress but not running the app locally
|
||||
// https://github.com/elastic/security-team/issues/6300
|
||||
openTakeActionButton();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_ENDPOINT_EXCEPTION).should('be.disabled');
|
||||
|
||||
cy.log('should add rule exception');
|
||||
|
||||
// TODO this isn't fully testing the add rule exception yet
|
||||
// https://github.com/elastic/security-team/issues/6301
|
||||
selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION);
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_HEADER).should('be.visible');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ADD_RULE_EXCEPTION_FLYOUT_CANCEL_BUTTON)
|
||||
.should('be.visible')
|
||||
.click();
|
||||
|
||||
// cy.log('should isolate host');
|
||||
|
||||
// TODO figure out why isolate host isn't showing up in the dropdown
|
||||
// https://github.com/elastic/security-team/issues/6302
|
||||
// openTakeActionButton();
|
||||
// cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST).should('be.visible');
|
||||
|
||||
cy.log('should respond');
|
||||
|
||||
// TODO this will change when respond is improved
|
||||
// https://github.com/elastic/security-team/issues/6303
|
||||
openTakeActionButton();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_RESPOND).should('be.disabled');
|
||||
|
||||
cy.log('should investigate in timeline');
|
||||
|
||||
selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE);
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION)
|
||||
.first()
|
||||
.within(() =>
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_ENTRY).should('be.visible')
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,351 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { collapseDocumentDetailsExpandableFlyoutLeftSection } from '../../../../tasks/expandable_flyout/alert_details_right_panel';
|
||||
import { DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT } from '../../../../screens/expandable_flyout/alert_details_left_panel_investigation_tab';
|
||||
import {
|
||||
createNewCaseFromExpandableFlyout,
|
||||
expandFirstAlertExpandableFlyout,
|
||||
} from '../../../../tasks/expandable_flyout/common';
|
||||
import {
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_HEADER,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_RULE_PREVIEW_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_HEADER,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL,
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_SECTION_EMPTY_RESPONSE,
|
||||
} from '../../../../screens/expandable_flyout/alert_details_right_panel_overview_tab';
|
||||
import {
|
||||
navigateToCorrelationsDetails,
|
||||
clickInvestigationGuideButton,
|
||||
navigateToPrevalenceDetails,
|
||||
toggleOverviewTabAboutSection,
|
||||
toggleOverviewTabInsightsSection,
|
||||
toggleOverviewTabInvestigationSection,
|
||||
toggleOverviewTabResponseSection,
|
||||
toggleOverviewTabVisualizationsSection,
|
||||
} from '../../../../tasks/expandable_flyout/alert_details_right_panel_overview_tab';
|
||||
import { cleanKibana } from '../../../../tasks/common';
|
||||
import { login, visit } from '../../../../tasks/login';
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
import { ALERTS_URL } from '../../../../urls/navigation';
|
||||
import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule';
|
||||
import {
|
||||
DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT,
|
||||
DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS,
|
||||
DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS,
|
||||
} from '../../../../screens/expandable_flyout/alert_details_left_panel_entities_tab';
|
||||
|
||||
describe('Alert details expandable flyout right panel overview tab', () => {
|
||||
const rule = getNewRule();
|
||||
|
||||
beforeEach(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createRule(rule);
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
expandFirstAlertExpandableFlyout();
|
||||
});
|
||||
|
||||
describe('about section', () => {
|
||||
it('should display about section', () => {
|
||||
cy.log('header and content');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_HEADER)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'About');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_CONTENT).should('be.visible');
|
||||
|
||||
cy.log('description');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE)
|
||||
.should('be.visible')
|
||||
.and('contain.text', 'Rule description');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_TITLE)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_OPEN_RULE_PREVIEW_BUTTON)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Rule summary');
|
||||
});
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_DESCRIPTION_DETAILS)
|
||||
.should('be.visible')
|
||||
.and('have.text', rule.description);
|
||||
|
||||
cy.log('reason');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_TITLE)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Alert reason');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_REASON_DETAILS)
|
||||
.should('be.visible')
|
||||
.and('contain.text', rule.name);
|
||||
|
||||
cy.log('mitre attack');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_TITLE)
|
||||
.should('be.visible')
|
||||
// @ts-ignore
|
||||
.and('contain.text', rule.threat[0].framework);
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS)
|
||||
.should('be.visible')
|
||||
// @ts-ignore
|
||||
.and('contain.text', rule.threat[0].technique[0].name)
|
||||
// @ts-ignore
|
||||
.and('contain.text', rule.threat[0].tactic.name);
|
||||
});
|
||||
});
|
||||
|
||||
describe('visualizations section', () => {
|
||||
it('should display analyzer and session previews', () => {
|
||||
toggleOverviewTabAboutSection();
|
||||
toggleOverviewTabVisualizationsSection();
|
||||
|
||||
cy.log('analyzer graph preview');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_PREVIEW_CONTENT).should('be.visible');
|
||||
|
||||
cy.log('session view preview');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_CONTENT).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe('investigation section', () => {
|
||||
it('should display investigation section', () => {
|
||||
toggleOverviewTabAboutSection();
|
||||
|
||||
cy.log('header and content');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_HEADER)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Investigation');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_CONTENT).should(
|
||||
'be.visible'
|
||||
);
|
||||
|
||||
cy.log('investigation guide button');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Investigation guide');
|
||||
|
||||
cy.log('should navigate to left Investigation tab');
|
||||
|
||||
clickInvestigationGuideButton();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INVESTIGATION_TAB_CONTENT).should('be.visible');
|
||||
|
||||
cy.log('highlighted fields');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_HEADER_TITLE)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Highlighted fields');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_DETAILS).should('be.visible');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL)
|
||||
.should('be.visible')
|
||||
.and('contain.text', 'host.name');
|
||||
const hostNameCell =
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('siem-kibana');
|
||||
cy.get(hostNameCell).should('be.visible').and('have.text', 'siem-kibana');
|
||||
|
||||
cy.get(hostNameCell).click();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('be.visible');
|
||||
|
||||
collapseDocumentDetailsExpandableFlyoutLeftSection();
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL)
|
||||
.should('be.visible')
|
||||
.and('contain.text', 'user.name');
|
||||
const userNameCell =
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('test');
|
||||
cy.get(userNameCell).should('be.visible').and('have.text', 'test');
|
||||
|
||||
cy.get(userNameCell).click();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe('insights section', () => {
|
||||
it('should display entities section', () => {
|
||||
toggleOverviewTabAboutSection();
|
||||
toggleOverviewTabInvestigationSection();
|
||||
toggleOverviewTabInsightsSection();
|
||||
|
||||
cy.log('header and content');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Entities');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_CONTENT).should('be.visible');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER).should('be.visible');
|
||||
|
||||
cy.log('should navigate to left panel Entities tab');
|
||||
|
||||
// TODO: skipping this section as Cypress can't seem to find the element (though it's in the DOM)
|
||||
// navigateToEntitiesDetails();
|
||||
// cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible');
|
||||
});
|
||||
|
||||
it('should display threat intelligence section', () => {
|
||||
toggleOverviewTabAboutSection();
|
||||
toggleOverviewTabInvestigationSection();
|
||||
toggleOverviewTabInsightsSection();
|
||||
|
||||
cy.log('header and content');
|
||||
|
||||
cy.get(
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER
|
||||
).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Threat Intelligence');
|
||||
cy.get(
|
||||
DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT
|
||||
).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
// threat match detected
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES)
|
||||
.eq(0)
|
||||
.should('be.visible')
|
||||
.and('have.text', '0 threat match detected'); // TODO work on getting proper IoC data to get proper data here
|
||||
|
||||
// field with threat enrichement
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES)
|
||||
.eq(1)
|
||||
.should('be.visible')
|
||||
.and('have.text', '0 field enriched with threat intelligence'); // TODO work on getting proper IoC data to get proper data here
|
||||
});
|
||||
|
||||
cy.log('should navigate to left panel Threat Intelligence tab');
|
||||
|
||||
// TODO: skipping this section as Cypress can't seem to find the element (though it's in the DOM)
|
||||
// navigateToThreatIntelligenceDetails();
|
||||
// cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Threat Intelligence sub tab directly
|
||||
});
|
||||
|
||||
// TODO: skipping this due to flakiness
|
||||
it.skip('should display correlations section', () => {
|
||||
cy.log('link the alert to a new case');
|
||||
|
||||
createNewCaseFromExpandableFlyout();
|
||||
|
||||
toggleOverviewTabAboutSection();
|
||||
toggleOverviewTabInvestigationSection();
|
||||
toggleOverviewTabInsightsSection();
|
||||
|
||||
cy.log('header and content');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Correlations');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
// TODO the order in which these appear is not deterministic currently, hence this can cause flakiness
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES)
|
||||
.eq(0)
|
||||
.should('be.visible')
|
||||
.and('have.text', '1 alert related by ancestry');
|
||||
// cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES)
|
||||
// .eq(2)
|
||||
// .should('be.visible')
|
||||
// .and('have.text', '1 alert related by the same source event'); // TODO work on getting proper data to display some same source data here
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES)
|
||||
.eq(2)
|
||||
.should('be.visible')
|
||||
.and('have.text', '1 alert related by session');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES)
|
||||
.eq(1)
|
||||
.should('be.visible')
|
||||
.and('have.text', '1 related case');
|
||||
});
|
||||
|
||||
cy.log('should navigate to left panel Correlations tab');
|
||||
|
||||
navigateToCorrelationsDetails();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Correlations sub tab directly
|
||||
});
|
||||
|
||||
// TODO work on getting proper data to make the prevalence section work here
|
||||
// we need to generate enough data to have at least one field with prevalence
|
||||
it.skip('should display prevalence section', () => {
|
||||
toggleOverviewTabAboutSection();
|
||||
toggleOverviewTabInvestigationSection();
|
||||
toggleOverviewTabInsightsSection();
|
||||
|
||||
cy.log('header and content');
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'Prevalence');
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT).scrollIntoView();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT)
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES)
|
||||
.should('be.visible')
|
||||
.and('have.text', 'is uncommon');
|
||||
});
|
||||
|
||||
cy.log('should navigate to left panel Prevalence tab');
|
||||
|
||||
navigateToPrevalenceDetails();
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); // TODO update when we can navigate to Prevalence sub tab directly
|
||||
});
|
||||
});
|
||||
|
||||
describe('response section', () => {
|
||||
it('should display empty message', () => {
|
||||
toggleOverviewTabAboutSection();
|
||||
toggleOverviewTabInvestigationSection();
|
||||
toggleOverviewTabResponseSection();
|
||||
|
||||
cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_SECTION_EMPTY_RESPONSE).should(
|
||||
'be.visible'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Timeline } from '../../../objects/timeline';
|
||||
import {
|
||||
MODAL_CONFIRMATION_BTN,
|
||||
MODAL_CONFIRMATION_CANCEL_BTN,
|
||||
} from '../../../screens/alerts_detection_rules';
|
||||
import {
|
||||
ALERTS_PAGE,
|
||||
APP_LEAVE_CONFIRM_MODAL,
|
||||
CASES_PAGE,
|
||||
MANAGE_PAGE,
|
||||
OBSERVABILITY_ALERTS_PAGE,
|
||||
} from '../../../screens/kibana_navigation';
|
||||
import { TIMELINE_SAVE_MODAL } from '../../../screens/timeline';
|
||||
import { cleanKibana } from '../../../tasks/common';
|
||||
import {
|
||||
navigateFromKibanaCollapsibleTo,
|
||||
openKibanaNavigation,
|
||||
} from '../../../tasks/kibana_navigation';
|
||||
import { login, visit } from '../../../tasks/login';
|
||||
import { closeTimelineUsingToggle } from '../../../tasks/security_main';
|
||||
import {
|
||||
addNameAndDescriptionToTimeline,
|
||||
createNewTimeline,
|
||||
populateTimeline,
|
||||
waitForTimelineChanges,
|
||||
} from '../../../tasks/timeline';
|
||||
import { HOSTS_URL, MANAGE_URL } from '../../../urls/navigation';
|
||||
|
||||
describe('Save Timeline Prompts', () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
/*
|
||||
* When timeline changes are pending, chrome would popup with
|
||||
* a confirm dialog stating that `you can lose unsaved changed.
|
||||
* Below changes will disable that.
|
||||
*
|
||||
* */
|
||||
cy.window().then((win) => {
|
||||
win.onbeforeunload = null;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visit(HOSTS_URL);
|
||||
createNewTimeline();
|
||||
});
|
||||
|
||||
it('unchanged & unsaved timeline should NOT prompt when user navigates away', () => {
|
||||
openKibanaNavigation();
|
||||
navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE);
|
||||
cy.url().should('not.contain', HOSTS_URL);
|
||||
});
|
||||
|
||||
it('Changed & unsaved timeline should prompt when user navigates away from security solution', () => {
|
||||
populateTimeline();
|
||||
waitForTimelineChanges();
|
||||
closeTimelineUsingToggle();
|
||||
openKibanaNavigation();
|
||||
navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE);
|
||||
cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible');
|
||||
cy.get(MODAL_CONFIRMATION_BTN).click();
|
||||
});
|
||||
|
||||
it('Changed & unsaved timeline should NOT prompt when user navigates away within security solution where timelines are enabled', () => {
|
||||
populateTimeline();
|
||||
|
||||
waitForTimelineChanges();
|
||||
closeTimelineUsingToggle();
|
||||
// navigate to any other page in security solution
|
||||
openKibanaNavigation();
|
||||
cy.get(CASES_PAGE).click();
|
||||
cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist');
|
||||
});
|
||||
|
||||
it('Changed & unsaved timeline should prompt when user navigates away within security solution where timelines are disbaled eg. admin screen', () => {
|
||||
populateTimeline();
|
||||
waitForTimelineChanges();
|
||||
openKibanaNavigation();
|
||||
cy.get(MANAGE_PAGE).click();
|
||||
cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible');
|
||||
cy.get(MODAL_CONFIRMATION_BTN).click();
|
||||
});
|
||||
|
||||
it('Changed & saved timeline should NOT prompt when user navigates away out of security solution', () => {
|
||||
populateTimeline();
|
||||
waitForTimelineChanges();
|
||||
closeTimelineUsingToggle();
|
||||
openKibanaNavigation();
|
||||
navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE);
|
||||
cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible');
|
||||
cy.get(MODAL_CONFIRMATION_CANCEL_BTN).click();
|
||||
addNameAndDescriptionToTimeline(
|
||||
{
|
||||
title: 'Some Timeline',
|
||||
description: 'Some Timeline',
|
||||
} as Timeline,
|
||||
true
|
||||
);
|
||||
openKibanaNavigation();
|
||||
navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE);
|
||||
cy.url().should('not.contain', HOSTS_URL);
|
||||
});
|
||||
|
||||
it('Changed & saved timeline should NOT prompt when user navigates within security solution where timelines are disabled', () => {
|
||||
populateTimeline();
|
||||
waitForTimelineChanges();
|
||||
closeTimelineUsingToggle();
|
||||
openKibanaNavigation();
|
||||
cy.get(MANAGE_PAGE).click();
|
||||
cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible');
|
||||
cy.get(MODAL_CONFIRMATION_CANCEL_BTN).click();
|
||||
addNameAndDescriptionToTimeline(
|
||||
{
|
||||
title: 'Some Timeline',
|
||||
description: 'Some Timeline',
|
||||
} as Timeline,
|
||||
true
|
||||
);
|
||||
openKibanaNavigation();
|
||||
cy.get(MANAGE_PAGE).click();
|
||||
cy.url().should('not.contain', HOSTS_URL);
|
||||
});
|
||||
|
||||
it('When user navigates to the page where timeline is present, Time save modal should not exists.', () => {
|
||||
populateTimeline();
|
||||
waitForTimelineChanges();
|
||||
closeTimelineUsingToggle();
|
||||
openKibanaNavigation();
|
||||
cy.get(MANAGE_PAGE).click();
|
||||
cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible');
|
||||
cy.get(MODAL_CONFIRMATION_BTN).click();
|
||||
|
||||
// Navigate back to HOSTS_URL and ensure that
|
||||
// timeline save modal is NOT present
|
||||
|
||||
openKibanaNavigation();
|
||||
cy.get(ALERTS_PAGE).click();
|
||||
cy.get(TIMELINE_SAVE_MODAL).should('not.exist');
|
||||
});
|
||||
|
||||
it('Changed and unsaved timeline should NOT prompt when user navigates from the page where timeline is disabled', () => {
|
||||
populateTimeline();
|
||||
waitForTimelineChanges();
|
||||
closeTimelineUsingToggle();
|
||||
openKibanaNavigation();
|
||||
cy.get(MANAGE_PAGE).click();
|
||||
cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible');
|
||||
cy.get(MODAL_CONFIRMATION_BTN).click();
|
||||
// now we have come from MANAGE_PAGE where timeline is disabled
|
||||
// to outside app where timeline is not present.
|
||||
// There should be NO confirmation model in that case.
|
||||
openKibanaNavigation();
|
||||
navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE);
|
||||
// should not be manage page i.e. successfull navigation
|
||||
cy.get(TIMELINE_SAVE_MODAL).should('not.exist');
|
||||
cy.url().should('not.contain', MANAGE_URL);
|
||||
});
|
||||
});
|
|
@ -10,17 +10,11 @@
|
|||
"cypress": "../../../node_modules/.bin/cypress",
|
||||
"cypress:burn": "yarn cypress:run:reporter --env burn=2 --concurrency=1 --headed",
|
||||
"cypress:changed-specs-only": "yarn cypress:run:reporter --changed-specs-only --env burn=2",
|
||||
"cypress:open": "TZ=UTC node ./scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config",
|
||||
"cypress:run": "yarn cypress:run:reporter --spec './cypress/e2e/{,!(investigations,explore)/**/}*.cy.ts'; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:cases": "yarn cypress:run:reporter --spec './cypress/e2e/explore/cases/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:reporter": "TZ=UTC node ./scripts/start_cypress_parallel run --browser chrome --config-file ./cypress/cypress_ci.config.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json",
|
||||
"cypress:run:respops": "yarn cypress:run:reporter --spec './cypress/e2e/(detection_alerts|detection_rules|exceptions)/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:dw:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress.config.ts ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/cli_config",
|
||||
"cypress:dw:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:dw:endpoint:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress_endpoint.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/endpoint_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json --concurrency 1; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:dw:endpoint:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress_endpoint.config.ts ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/endpoint_config",
|
||||
"cypress:investigations:run": "yarn cypress:run:reporter --spec './cypress/e2e/investigations/**/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:explore:run": "yarn cypress:run:reporter --spec './cypress/e2e/explore/**/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:reporter": "TZ=UTC node ./scripts/start_cypress_parallel run --ftr-config-file ../../test/defend_workflows_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=../../test/security_solution_cypress/cypress/reporter_config.json",
|
||||
"cypress:dw:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress.config.ts ts --ftr-config-file ../../test/defend_workflows_cypress/cli_config",
|
||||
"cypress:dw:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress.config.ts --ftr-config-file ../../test/defend_workflows_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=../../test/security_solution_cypress/cypress/reporter_config.json; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:dw:endpoint:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress_endpoint.config.ts --ftr-config-file ../../test/defend_workflows_cypress/endpoint_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=../../test/security_solution_cypress/cypress/reporter_config.json --concurrency 1; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:dw:endpoint:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress_endpoint.config.ts ts --ftr-config-file ../../test/defend_workflows_cypress/endpoint_config",
|
||||
"junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-security-solution/cypress/results/mochawesome*.json > ../../../target/kibana-security-solution/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-security-solution/cypress/results/output.json --reportDir ../../../target/kibana-security-solution/cypress/results && yarn junit:transform && mkdir -p ../../../target/junit && cp ../../../target/kibana-security-solution/cypress/results/*.xml ../../../target/junit/",
|
||||
"test:generate": "node scripts/endpoint/resolver_generator",
|
||||
"mappings:generate": "node scripts/mappings/mappings_generator",
|
||||
|
|
|
@ -84,8 +84,10 @@ export const cli = () => {
|
|||
);
|
||||
|
||||
const isOpen = argv._[0] === 'open';
|
||||
const cypressConfigFilePath = require.resolve(`../../${argv.configFile}`) as string;
|
||||
const cypressConfigFile = await import(require.resolve(`../../${argv.configFile}`));
|
||||
const cypressConfigFilePath = require.resolve(
|
||||
`../../${_.isArray(argv.configFile) ? _.last(argv.configFile) : argv.configFile}`
|
||||
) as string;
|
||||
const cypressConfigFile = await import(cypressConfigFilePath);
|
||||
const spec: string | undefined = argv?.spec as string;
|
||||
let files = retrieveIntegrations(spec ? [spec] : cypressConfigFile?.e2e?.specPattern);
|
||||
|
||||
|
@ -192,7 +194,9 @@ export const cli = () => {
|
|||
const config = await readConfigFile(
|
||||
log,
|
||||
EsVersion.getDefault(),
|
||||
_.isArray(argv.ftrConfigFile) ? _.last(argv.ftrConfigFile) : argv.ftrConfigFile,
|
||||
path.resolve(
|
||||
_.isArray(argv.ftrConfigFile) ? _.last(argv.ftrConfigFile) : argv.ftrConfigFile
|
||||
),
|
||||
{
|
||||
servers: {
|
||||
elasticsearch: {
|
||||
|
|
|
@ -10,12 +10,12 @@ import Url from 'url';
|
|||
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
import { encode } from '@kbn/rison';
|
||||
import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '@kbn/security-solution-plugin/common/constants';
|
||||
import {
|
||||
LOADING_INDICATOR,
|
||||
LOADING_INDICATOR_HIDDEN,
|
||||
} from '@kbn/security-solution-plugin/cypress/screens/security_header';
|
||||
import { encode } from '@kbn/rison';
|
||||
import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '@kbn/security-solution-plugin/common/constants';
|
||||
} from '../../../../test/security_solution_cypress/cypress/screens/security_header';
|
||||
import type { ROLES } from './privileges';
|
||||
|
||||
const LOGIN_API_ENDPOINT = '/internal/security/login';
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
"license": "Elastic License 2.0",
|
||||
"scripts": {
|
||||
"cypress": "../../../node_modules/.bin/cypress",
|
||||
"cypress:open": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/threat_intelligence_cypress/cli_config_parallel",
|
||||
"cypress:open": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ../../plugins/threat_intelligence/cypress/cypress.config.ts --ftr-config-file ../../test/threat_intelligence_cypress/cli_config_parallel",
|
||||
"cypress:run": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/**/*.cy.ts'; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:spec": "yarn cypress:run:reporter --browser chrome --spec ${SPEC_LIST:-'./cypress/e2e/**/*.cy.ts'}; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:cases": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/cases/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:reporter": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel run --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/threat_intelligence_cypress/cli_config_parallel --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json",
|
||||
"cypress:run:respops": "yarn cypress:run:reporter --browser chrome --spec ./cypress/e2e/detection_alerts/*.cy.ts,./cypress/e2e/detection_rules/*.cy.ts,./cypress/e2e/exceptions/*.cy.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:cases": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/cases/*.cy.ts' --ftr-config-file ../../test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"cypress:run:reporter": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel run --config-file ../../plugins/threat_intelligence/cypress/cypress.config.ts --ftr-config-file ../../test/threat_intelligence_cypress/cli_config_parallel --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json",
|
||||
"cypress:run:respops": "yarn cypress:run:reporter --browser chrome --spec ./cypress/e2e/detection_alerts/*.cy.ts,./cypress/e2e/detection_rules/*.cy.ts,./cypress/e2e/exceptions/*.cy.ts --ftr-config-file ../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status",
|
||||
"junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-threat-intelligence/cypress/results/mochawesome*.json > ../../../target/kibana-threat-intelligence/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-threat-intelligence/cypress/results/output.json --reportDir ../../../target/kibana-threat-intelligence/cypress/results && mkdir -p ../../../target/junit && cp ../../../target/kibana-threat-intelligence/cypress/results/*.xml ../../../target/junit/"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,21 +38,39 @@ of data for your test, [**Running the tests**](#running-the-tests) to know how t
|
|||
|
||||
Please, before opening a PR with the new test, please make sure that the test fails. If you never see your test fail you don’t know if your test is actually testing the right thing, or testing anything at all.
|
||||
|
||||
Note that we use tags in order to select which tests we want to execute:
|
||||
|
||||
```typescript
|
||||
export const tag = {
|
||||
SERVERLESS: '@serverless',
|
||||
ESS: '@ess',
|
||||
BROKEN_IN_SERVERLESS: '@brokenInServerless',
|
||||
};
|
||||
```
|
||||
|
||||
Please, before opening a PR with the new test, make sure that the test fails. If you never see your test fail you don’t know if your test is actually testing the right thing, or testing anything at all.
|
||||
|
||||
## Running the tests
|
||||
|
||||
### Run them locally
|
||||
Run the tests with the following yarn scripts:
|
||||
When running the tests, FTR is used to spawn both a Kibana instance (http://localhost:5620) and an Elasticsearch instance (http://localhost:9220) with a preloaded minimum set of data (see preceding "Test data" section).
|
||||
|
||||
Run the tests with the following yarn scripts from `x-pack/test/security_solution_cypress`:
|
||||
|
||||
| Script Name | Description |
|
||||
| ----------- | ----------- |
|
||||
| cypress | Runs the default Cypress command |
|
||||
| cypress:open | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a local kibana and ES instance. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. |C
|
||||
| cypress:run | Runs all tests in the `e2e` directory excluding `investigations` and `explore` directories in headless mode |
|
||||
| cypress:run:cases | Runs all tests under `explore/cases` in the `e2e` directory related to the Cases area team in headless mode |
|
||||
| cypress:run:reporter | Runs all tests with the specified configuration in headless mode and produces a report using `cypress-multi-reporters` |
|
||||
| cypress:run:respops | Runs all tests related to the Response Ops area team, specifically tests in `detection_alerts`, `detection_rules`, and `exceptions` directories in headless mode |
|
||||
| cypress:investigations:run | Runs all tests in the `e2e/investigations` directory in headless mode |
|
||||
| cypress:explore:run | Runs all tests in the `e2e/explore` directory in headless mode |
|
||||
| cypress:open:ess | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a local kibana and ES instance. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. |
|
||||
| cypress:open:serverless | Opens the Cypress UI with all tests in the `e2e` directory. This also runs a mocked serverless environment. The kibana instance will reload when you make code changes. This is the recommended way to debug and develop tests. |
|
||||
| cypress:run:ess | Runs all tests tagged as ESS placed in the `e2e` directory excluding `investigations` and `explore` directories in headless mode |
|
||||
| cypress:run:cases:ess | Runs all tests under `explore/cases` in the `e2e` directory related to the Cases area team in headless mode |
|
||||
| cypress:ess | Runs all ESS tests with the specified configuration in headless mode and produces a report using `cypress-multi-reporters` |
|
||||
| cypress:run:respops:ess | Runs all tests related to the Response Ops area team, specifically tests in `detection_alerts`, `detection_rules`, and `exceptions` directories in headless mode |
|
||||
| cypress:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e` directory excluding `investigations` and `explore` directories in headless mode |
|
||||
| cypress:investigations:run:ess | Runs all tests tagged as ESS in the `e2e/investigations` directory in headless mode |
|
||||
| cypress:explore:run:ess | Runs all tests tagged as ESS in the `e2e/explore` directory in headless mode |
|
||||
| cypress:investigations:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/investigations` directory in headless mode |
|
||||
| cypress:explore:run:serverless | Runs all tests tagged as SERVERLESS in the `e2e/explore` directory in headless mode |
|
||||
| junit:merge | Merges individual test reports into a single report and moves the report to the `junit` directory |
|
||||
|
||||
Please note that all the headless mode commands do not open the Cypress UI and are typically used in CI/CD environments. The scripts that open the Cypress UI are useful for development and debugging.
|
||||
|
@ -148,7 +166,7 @@ We use es_archiver to manage the data that our Cypress tests need.
|
|||
|
||||
1. Set up a clean instance of kibana and elasticsearch (if this is not possible, try to clean/minimize the data that you are going to archive).
|
||||
2. With the kibana and elasticsearch instance up and running, create the data that you need for your test.
|
||||
3. When you are sure that you have all the data you need run the following command from: `x-pack/plugins/security_solution`
|
||||
3. When you are sure that you have all the data you need run the following command from: `x-pack/test/security_solution_cypress`
|
||||
|
||||
```sh
|
||||
node ../../../scripts/es_archiver save <nameOfTheFolderWhereDataIsSaved> <indexPatternsToBeSaved> --dir ../../test/security_solution_cypress/es_archives --config ../../../test/functional/config.base.js --es-url http://<elasticsearchUsername>:<elasticsearchPassword>@<elasticsearchHost>:<elasticsearchPort>
|
||||
|
@ -164,7 +182,7 @@ Note that the command will create the folder if it does not exist.
|
|||
|
||||
### Using an archive from within the Cypress tests
|
||||
|
||||
Task [cypress/support/es_archiver.ts](https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/cypress/support/es_archiver.ts) provides helpers such as `esArchiverLoad` and `esArchiverUnload` by means of `es_archiver`'s CLI.
|
||||
Task [cypress/support/es_archiver.ts](https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_cypress/cypress/support/es_archiver.ts) provides helpers such as `esArchiverLoad` and `esArchiverUnload` by means of `es_archiver`'s CLI.
|
||||
|
||||
## Development Best Practices
|
||||
|
|
@ -10,6 +10,10 @@ import { esArchiver } from './support/es_archiver';
|
|||
|
||||
export default defineCypressConfig({
|
||||
defaultCommandTimeout: 60000,
|
||||
env: {
|
||||
grepFilterSpecs: true,
|
||||
grepTags: '@ess',
|
||||
},
|
||||
execTimeout: 60000,
|
||||
pageLoadTimeout: 60000,
|
||||
responseTimeout: 60000,
|
||||
|
@ -25,6 +29,9 @@ export default defineCypressConfig({
|
|||
experimentalMemoryManagement: true,
|
||||
setupNodeEvents(on, config) {
|
||||
esArchiver(on, config);
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require('@cypress/grep/src/plugin')(config);
|
||||
return config;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -11,6 +11,10 @@ import { esArchiver } from './support/es_archiver';
|
|||
// eslint-disable-next-line import/no-default-export
|
||||
export default defineCypressConfig({
|
||||
defaultCommandTimeout: 150000,
|
||||
env: {
|
||||
grepFilterSpecs: true,
|
||||
grepTags: '@ess',
|
||||
},
|
||||
execTimeout: 150000,
|
||||
pageLoadTimeout: 150000,
|
||||
numTestsKeptInMemory: 0,
|
||||
|
@ -29,6 +33,9 @@ export default defineCypressConfig({
|
|||
specPattern: './cypress/e2e/**/*.cy.ts',
|
||||
setupNodeEvents(on, config) {
|
||||
esArchiver(on, config);
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require('@cypress/grep/src/plugin')(config);
|
||||
return config;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { defineCypressConfig } from '@kbn/cypress-config';
|
||||
import { esArchiver } from './support/es_archiver';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default defineCypressConfig({
|
||||
defaultCommandTimeout: 150000,
|
||||
env: {
|
||||
grepFilterSpecs: true,
|
||||
grepTags: '@serverless --@brokenInServerless',
|
||||
},
|
||||
execTimeout: 150000,
|
||||
pageLoadTimeout: 150000,
|
||||
numTestsKeptInMemory: 0,
|
||||
retries: {
|
||||
runMode: 1,
|
||||
},
|
||||
screenshotsFolder: '../../../target/kibana-security-solution/cypress/screenshots',
|
||||
trashAssetsBeforeRuns: false,
|
||||
video: false,
|
||||
videosFolder: '../../../../target/kibana-security-solution/cypress/videos',
|
||||
viewportHeight: 946,
|
||||
viewportWidth: 1680,
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:5601',
|
||||
experimentalMemoryManagement: true,
|
||||
specPattern: './cypress/e2e/**/*.cy.ts',
|
||||
setupNodeEvents(on, config) {
|
||||
esArchiver(on, config);
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require('@cypress/grep/src/plugin')(config);
|
||||
return config;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { defineCypressConfig } from '@kbn/cypress-config';
|
||||
import { esArchiver } from './support/es_archiver';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default defineCypressConfig({
|
||||
defaultCommandTimeout: 60000,
|
||||
execTimeout: 60000,
|
||||
pageLoadTimeout: 60000,
|
||||
responseTimeout: 60000,
|
||||
screenshotsFolder: '../../../target/kibana-security-solution/cypress/screenshots',
|
||||
trashAssetsBeforeRuns: false,
|
||||
video: false,
|
||||
videosFolder: '../../../target/kibana-security-solution/cypress/videos',
|
||||
viewportHeight: 946,
|
||||
viewportWidth: 1680,
|
||||
numTestsKeptInMemory: 10,
|
||||
env: {
|
||||
grepFilterSpecs: true,
|
||||
grepTags: '@serverless --@brokenInServerless',
|
||||
},
|
||||
e2e: {
|
||||
experimentalRunAllSpecs: true,
|
||||
experimentalMemoryManagement: true,
|
||||
setupNodeEvents(on, config) {
|
||||
esArchiver(on, config);
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require('@cypress/grep/src/plugin')(config);
|
||||
return config;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -24,7 +24,7 @@ import type {
|
|||
RuleName,
|
||||
RuleReferenceArray,
|
||||
RuleTagArray,
|
||||
} from '../../common/api/detection_engine';
|
||||
} from '@kbn/security-solution-plugin/common/api/detection_engine';
|
||||
|
||||
interface RuleFields {
|
||||
defaultIndexPatterns: IndexPatternArray;
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { login, visit } from '../../tasks/login';
|
||||
import { openTimelineUsingToggle } from '../../tasks/security_main';
|
||||
import { openTimelineFieldsBrowser, populateTimeline } from '../../tasks/timeline';
|
||||
|
@ -25,7 +27,7 @@ import { GET_TIMELINE_HEADER } from '../../screens/timeline';
|
|||
const alertRunTimeField = 'field.name.alert.page';
|
||||
const timelineRuntimeField = 'field.name.timeline';
|
||||
|
||||
describe('Create DataView runtime field', () => {
|
||||
describe('Create DataView runtime field', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
deleteRuntimeField('security-solution-default', alertRunTimeField);
|
||||
deleteRuntimeField('security-solution-default', timelineRuntimeField);
|
|
@ -5,6 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
DEFAULT_ALERTS_INDEX,
|
||||
DEFAULT_INDEX_PATTERN,
|
||||
} from '@kbn/security-solution-plugin/common/constants';
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { login, loginWithUser, visit, visitWithUser } from '../../tasks/login';
|
||||
|
||||
import { HOSTS_URL, TIMELINES_URL } from '../../urls/navigation';
|
||||
|
@ -30,7 +36,6 @@ import { postDataView } from '../../tasks/common';
|
|||
import { openTimelineUsingToggle } from '../../tasks/security_main';
|
||||
import { createUsersAndRoles, secReadCasesAll, secReadCasesAllUser } from '../../tasks/privileges';
|
||||
import { TOASTER } from '../../screens/configure_cases';
|
||||
import { DEFAULT_ALERTS_INDEX, DEFAULT_INDEX_PATTERN } from '../../../common/constants';
|
||||
import { SOURCERER } from '../../screens/sourcerer';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { getTimeline, getTimelineModifiedSourcerer } from '../../objects/timeline';
|
||||
|
@ -46,7 +51,7 @@ describe('Sourcerer', () => {
|
|||
cy.task('esArchiverResetKibana');
|
||||
dataViews.forEach((dataView: string) => postDataView(dataView));
|
||||
});
|
||||
describe('permissions', () => {
|
||||
describe('permissions', { tags: tag.ESS }, () => {
|
||||
before(() => {
|
||||
createUsersAndRoles(usersToCreate, rolesToCreate);
|
||||
});
|
||||
|
@ -57,7 +62,7 @@ describe('Sourcerer', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Default scope', () => {
|
||||
describe('Default scope', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
login();
|
||||
|
@ -117,20 +122,24 @@ describe('Sourcerer', () => {
|
|||
cy.get(SOURCERER.saveButton).should('be.disabled');
|
||||
});
|
||||
|
||||
it('adds a pattern to the default index and correctly filters out auditbeat-*', () => {
|
||||
openSourcerer();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isNotSourcererSelection('*beat*');
|
||||
addIndexToDefault('*beat*');
|
||||
isHostsStatValue('1');
|
||||
openSourcerer();
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection('*beat*');
|
||||
});
|
||||
it(
|
||||
'adds a pattern to the default index and correctly filters out auditbeat-*',
|
||||
{ tags: tag.BROKEN_IN_SERVERLESS },
|
||||
() => {
|
||||
openSourcerer();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isNotSourcererSelection('*beat*');
|
||||
addIndexToDefault('*beat*');
|
||||
isHostsStatValue('1');
|
||||
openSourcerer();
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection('*beat*');
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Timeline scope', () => {
|
||||
describe('Timeline scope', { tags: tag.BROKEN_IN_SERVERLESS }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
login();
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import {
|
||||
clickAlertTag,
|
||||
|
@ -24,7 +26,7 @@ import {
|
|||
UNSELECTED_ALERT_TAG,
|
||||
} from '../../screens/alerts';
|
||||
|
||||
describe('Alert tagging', () => {
|
||||
describe('Alert tagging', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
cy.task('esArchiverResetKibana');
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { ALERTS_COUNT } from '../../screens/alerts';
|
||||
import {
|
||||
|
@ -24,7 +26,7 @@ import {
|
|||
} from '../../screens/search_bar';
|
||||
import { TOASTER } from '../../screens/alerts_detection_rules';
|
||||
|
||||
describe('Histogram legend hover actions', () => {
|
||||
describe('Histogram legend hover actions', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
const ruleConfigs = getNewRule();
|
||||
|
||||
before(() => {
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL, ALERTS_URL } from '../../urls/navigation';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { PAGE_TITLE } from '../../screens/common/page';
|
||||
|
||||
import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../tasks/login';
|
||||
import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts';
|
||||
|
||||
const loadPageAsPlatformEngineerUser = (url: string) => {
|
||||
login(ROLES.soc_manager);
|
||||
waitForPageWithoutDateRange(url, ROLES.soc_manager);
|
||||
waitForPageTitleToBeShown();
|
||||
};
|
||||
|
||||
const waitForPageTitleToBeShown = () => {
|
||||
cy.get(PAGE_TITLE).should('be.visible');
|
||||
};
|
||||
|
||||
describe(
|
||||
'Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set',
|
||||
{ tags: tag.ESS },
|
||||
() => {
|
||||
const NEED_ADMIN_FOR_UPDATE_CALLOUT = 'need-admin-for-update-rules';
|
||||
|
||||
before(() => {
|
||||
// First, we have to open the app on behalf of a privileged user in order to initialize it.
|
||||
// Otherwise the app will be disabled and show a "welcome"-like page.
|
||||
login();
|
||||
visitWithoutDateRange(ALERTS_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
});
|
||||
|
||||
context(
|
||||
'The users index_mapping_outdated is "true" and their admin callouts should show up',
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
// Index mapping outdated is forced to return true as being outdated so that we get the
|
||||
// need admin callouts being shown.
|
||||
cy.intercept('GET', '/api/detection_engine/index', (req) => {
|
||||
req.reply((res) => {
|
||||
res.send(200, {
|
||||
index_mapping_outdated: true,
|
||||
name: '.alerts-security.alerts-default',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('On Detections home page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(ALERTS_URL);
|
||||
});
|
||||
|
||||
it('We show the need admin primary callout', () => {
|
||||
waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rules Management page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
it('We show 1 primary callout of need admin', () => {
|
||||
waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createRule(getNewRule({ rule_id: 'rule_testing' }));
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
deleteCustomRule();
|
||||
});
|
||||
|
||||
it('We show 1 primary callout', () => {
|
||||
waitForCallOutToBeShown(NEED_ADMIN_FOR_UPDATE_CALLOUT, 'primary');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
context(
|
||||
'The users index_mapping_outdated is "false" and their admin callouts should not show up ',
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
// Index mapping outdated is forced to return true as being outdated so that we get the
|
||||
// need admin callouts being shown.
|
||||
cy.intercept('GET', '/api/detection_engine/index', {
|
||||
index_mapping_outdated: false,
|
||||
name: '.alerts-security.alerts-default',
|
||||
});
|
||||
});
|
||||
context('On Detections home page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(ALERTS_URL);
|
||||
});
|
||||
|
||||
it('We show the need admin primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rules Management page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
it('We show 1 primary callout of need admin', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createRule(getNewRule({ rule_id: 'rule_testing' }));
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
deleteCustomRule();
|
||||
});
|
||||
|
||||
it('We show 1 primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
context(
|
||||
'The users index_mapping_outdated is "null" and their admin callouts should not show up ',
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
// Index mapping outdated is forced to return true as being outdated so that we get the
|
||||
// need admin callouts being shown.
|
||||
cy.intercept('GET', '/api/detection_engine/index', {
|
||||
index_mapping_outdated: null,
|
||||
name: '.alerts-security.alerts-default',
|
||||
});
|
||||
});
|
||||
context('On Detections home page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(ALERTS_URL);
|
||||
});
|
||||
|
||||
it('We show the need admin primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rules Management page', () => {
|
||||
beforeEach(() => {
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
it('We show 1 primary callout of need admin', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createRule(getNewRule({ rule_id: 'rule_testing' }));
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
deleteCustomRule();
|
||||
});
|
||||
|
||||
it('We show 1 primary callout', () => {
|
||||
getCallOut(NEED_ADMIN_FOR_UPDATE_CALLOUT).should('not.exist');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { disableExpandableFlyout } from '../../tasks/api_calls/kibana_advanced_settings';
|
||||
import { getNewThreatIndicatorRule, indicatorRuleMatchingDoc } from '../../objects/rule';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
|
@ -28,7 +30,7 @@ import { openJsonView, openThreatIndicatorDetails } from '../../tasks/alerts_det
|
|||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
|
||||
import { addsFieldsToTimeline } from '../../tasks/rule_details';
|
||||
|
||||
describe('CTI Enrichment', () => {
|
||||
describe('CTI Enrichment', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
cy.task('esArchiverLoad', 'threat_indicator');
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import {
|
||||
HOST_RISK_HEADER_COLIMN,
|
||||
|
@ -30,7 +32,7 @@ import { login, visit } from '../../tasks/login';
|
|||
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
|
||||
describe('Enrichment', () => {
|
||||
describe('Enrichment', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
cy.task('esArchiverLoad', 'risk_users');
|
|
@ -5,7 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ROLES } from '../../../common/test';
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL, ALERTS_URL } from '../../urls/navigation';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { PAGE_TITLE } from '../../screens/common/page';
|
||||
|
@ -36,7 +38,7 @@ const waitForPageTitleToBeShown = () => {
|
|||
cy.get(PAGE_TITLE).should('be.visible');
|
||||
};
|
||||
|
||||
describe('Detections > Callouts', () => {
|
||||
describe('Detections > Callouts', { tags: tag.ESS }, () => {
|
||||
const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges';
|
||||
|
||||
before(() => {
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
|
||||
|
@ -14,7 +16,7 @@ import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timelin
|
|||
import { selectAlertsHistogram } from '../../tasks/alerts';
|
||||
import { createTimeline } from '../../tasks/timelines';
|
||||
|
||||
describe('Ransomware Detection Alerts', () => {
|
||||
describe('Ransomware Detection Alerts', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverLoad', 'ransomware_detection');
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
|
||||
|
@ -14,7 +16,7 @@ import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timelin
|
|||
import { selectAlertsHistogram } from '../../tasks/alerts';
|
||||
import { createTimeline } from '../../tasks/timelines';
|
||||
|
||||
describe('Ransomware Prevention Alerts', () => {
|
||||
describe('Ransomware Prevention Alerts', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverLoad', 'ransomware_prevention');
|
||||
});
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
APP_PATH,
|
||||
RULES_ADD_PATH,
|
||||
RULES_UPDATES,
|
||||
} from '@kbn/security-solution-plugin/common/constants';
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules';
|
||||
import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { resetRulesTableState, deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import { login, waitForPageWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
ADD_ELASTIC_RULES_BTN,
|
||||
getInstallSingleRuleButtonByRuleId,
|
||||
getUpgradeSingleRuleButtonByRuleId,
|
||||
INSTALL_ALL_RULES_BUTTON,
|
||||
RULES_UPDATES_TAB,
|
||||
RULE_CHECKBOX,
|
||||
UPGRADE_ALL_RULES_BUTTON,
|
||||
} from '../../../screens/alerts_detection_rules';
|
||||
|
||||
const RULE_1_ID = 'rule_1';
|
||||
const RULE_2_ID = 'rule_2';
|
||||
const OUTDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 2,
|
||||
});
|
||||
const OUTDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 2,
|
||||
});
|
||||
|
||||
const loadPageAsReadOnlyUser = (url: string) => {
|
||||
login(ROLES.reader);
|
||||
waitForPageWithoutDateRange(url, ROLES.reader);
|
||||
};
|
||||
|
||||
describe(
|
||||
'Detection rules, Prebuilt Rules Installation and Update - Authorization/RBAC',
|
||||
{ tags: tag.ESS },
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
waitForRulesTableToBeLoaded();
|
||||
createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
});
|
||||
|
||||
describe('User with read privileges on Security Solution', () => {
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
beforeEach(() => {
|
||||
// Now login with read-only user in preparation for test
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
|
||||
loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('should not be able to install prebuilt rules', () => {
|
||||
// Check that Add Elastic Rules button is disabled
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.disabled');
|
||||
|
||||
// Navigate to Add Elastic Rules page anyways via URL
|
||||
// and assert that rules cannot be selected and all
|
||||
// installation buttons are disabled
|
||||
cy.visit(`${APP_PATH}${RULES_ADD_PATH}`);
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).should('be.disabled');
|
||||
cy.get(getInstallSingleRuleButtonByRuleId(RULE_1['security-rule'].rule_id)).should(
|
||||
'not.exist'
|
||||
);
|
||||
cy.get(RULE_CHECKBOX).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('User with read privileges on Security Solution', () => {
|
||||
beforeEach(() => {
|
||||
/* Create a second version of the rule, making it available for update */
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
|
||||
installToKibana: false,
|
||||
});
|
||||
// Now login with read-only user in preparation for test
|
||||
loadPageAsReadOnlyUser(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('should not be able to upgrade prebuilt rules', () => {
|
||||
// Check that Rule Update tab is not shown
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
|
||||
// Navigate to Rule Update tab anyways via URL
|
||||
// and assert that rules cannot be selected and all
|
||||
// upgrade buttons are disabled
|
||||
cy.visit(`${APP_PATH}${RULES_UPDATES}`);
|
||||
cy.get(UPGRADE_ALL_RULES_BUTTON).should('be.disabled');
|
||||
cy.get(getUpgradeSingleRuleButtonByRuleId(OUTDATED_RULE_1['security-rule'].rule_id)).should(
|
||||
'not.exist'
|
||||
);
|
||||
cy.get(RULE_CHECKBOX).should('not.exist');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules';
|
||||
import { createAndInstallMockedPrebuiltRules } from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
addElasticRulesButtonClick,
|
||||
assertRuleAvailableForInstallAndInstallOne,
|
||||
assertRuleAvailableForInstallAndInstallSelected,
|
||||
assertRuleAvailableForInstallAndInstallAllInPage,
|
||||
assertRuleAvailableForInstallAndInstallAll,
|
||||
assertRuleUpgradeAvailableAndUpgradeOne,
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected,
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage,
|
||||
assertRuleUpgradeAvailableAndUpgradeAll,
|
||||
ruleUpdatesTabClick,
|
||||
} from '../../../tasks/prebuilt_rules';
|
||||
|
||||
describe(
|
||||
'Detection rules, Prebuilt Rules Installation and Update - Error handling',
|
||||
{ tags: tag.ESS },
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
});
|
||||
|
||||
describe('Installation of prebuilt rules - Should fail gracefully with toast error message when', () => {
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
beforeEach(() => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('installing prebuilt rules one by one', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1], didRequestFail: true });
|
||||
});
|
||||
|
||||
it('installing multiple selected prebuilt rules by selecting them individually', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallSelected({
|
||||
rules: [RULE_1, RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('installing multiple selected prebuilt rules by selecting all in page', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAllInPage({
|
||||
rules: [RULE_1, RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('installing all available rules at once', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAll({
|
||||
rules: [RULE_1, RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update of prebuilt rules - Should fail gracefully with toast error message when', () => {
|
||||
const RULE_1_ID = 'rule_1';
|
||||
const RULE_2_ID = 'rule_2';
|
||||
const OUTDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 2,
|
||||
});
|
||||
const OUTDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 2,
|
||||
});
|
||||
beforeEach(() => {
|
||||
/* Create a new rule and install it */
|
||||
createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
/* Create a second version of the rule, making it available for update */
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
|
||||
installToKibana: false,
|
||||
});
|
||||
waitForRulesTableToBeLoaded();
|
||||
reload();
|
||||
});
|
||||
|
||||
it('upgrading prebuilt rules one by one', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1], didRequestFail: true });
|
||||
});
|
||||
|
||||
it('upgrading multiple selected prebuilt rules by selecting them individually', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected({
|
||||
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('upgrading multiple selected prebuilt rules by selecting all in page', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage({
|
||||
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('upgrading all rules with available upgrades at once', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAll({
|
||||
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
|
||||
didRequestFail: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { BulkInstallPackageInfo } from '@kbn/fleet-plugin/common';
|
||||
import type { Rule } from '@kbn/security-solution-plugin/public/detection_engine/rule_management/logic/types';
|
||||
import { tag } from '../../../tags';
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import {
|
||||
GO_BACK_TO_RULES_TABLE_BUTTON,
|
||||
INSTALL_ALL_RULES_BUTTON,
|
||||
INSTALL_SELECTED_RULES_BUTTON,
|
||||
NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE,
|
||||
NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE,
|
||||
RULES_UPDATES_TAB,
|
||||
RULE_CHECKBOX,
|
||||
SELECT_ALL_RULES_ON_PAGE_CHECKBOX,
|
||||
TOASTER,
|
||||
} from '../../../screens/alerts_detection_rules';
|
||||
import { waitForRulesTableToBeLoaded } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
getRuleAssets,
|
||||
createAndInstallMockedPrebuiltRules,
|
||||
} from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import { resetRulesTableState, deleteAlertsAndRules, reload } from '../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
addElasticRulesButtonClick,
|
||||
assertRuleAvailableForInstallAndInstallOne,
|
||||
assertRuleAvailableForInstallAndInstallSelected,
|
||||
assertRuleAvailableForInstallAndInstallAllInPage,
|
||||
assertRuleAvailableForInstallAndInstallAll,
|
||||
assertRuleUpgradeAvailableAndUpgradeOne,
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected,
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage,
|
||||
assertRuleUpgradeAvailableAndUpgradeAll,
|
||||
ruleUpdatesTabClick,
|
||||
} from '../../../tasks/prebuilt_rules';
|
||||
|
||||
describe(
|
||||
'Detection rules, Prebuilt Rules Installation and Update workflow',
|
||||
{ tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] },
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
});
|
||||
|
||||
describe('Installation of prebuilt rules package via Fleet', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', '/api/fleet/epm/packages/_bulk*').as('installPackageBulk');
|
||||
cy.intercept('POST', '/api/fleet/epm/packages/security_detection_engine/*').as(
|
||||
'installPackage'
|
||||
);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('should install package from Fleet in the background', () => {
|
||||
/* Assert that the package in installed from Fleet */
|
||||
cy.wait('@installPackageBulk', {
|
||||
timeout: 60000,
|
||||
}).then(({ response: bulkResponse }) => {
|
||||
cy.wrap(bulkResponse?.statusCode).should('eql', 200);
|
||||
|
||||
const packages = bulkResponse?.body.items.map(
|
||||
({ name, result }: BulkInstallPackageInfo) => ({
|
||||
name,
|
||||
})
|
||||
);
|
||||
|
||||
const packagesBulkInstalled = packages.map(({ name }: { name: string }) => name);
|
||||
|
||||
// Under normal flow the package is installed via the Fleet bulk install API.
|
||||
// However, for testing purposes the package can be installed via the Fleet individual install API,
|
||||
// so we need to intercept and wait for that request as well.
|
||||
if (!packagesBulkInstalled.includes('security_detection_engine')) {
|
||||
// Should happen only during testing when the `xpack.securitySolution.prebuiltRulesPackageVersion` flag is set
|
||||
cy.wait('@installPackage').then(({ response }) => {
|
||||
cy.wrap(response?.statusCode).should('eql', 200);
|
||||
cy.wrap(response?.body)
|
||||
.should('have.property', 'items')
|
||||
.should('have.length.greaterThan', 0);
|
||||
});
|
||||
} else {
|
||||
// Normal flow, install via the Fleet bulk install API
|
||||
expect(packages.length).to.have.greaterThan(0);
|
||||
// At least one of the packages installed should be the security_detection_engine package
|
||||
expect(packages).to.satisfy((pckgs: BulkInstallPackageInfo[]) =>
|
||||
pckgs.some((pkg) => pkg.name === 'security_detection_engine')
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should install rules from the Fleet package when user clicks on CTA', () => {
|
||||
const getRulesAndAssertNumberInstalled = () => {
|
||||
getRuleAssets().then((response) => {
|
||||
const ruleIds = response.body.hits.hits.map(
|
||||
(hit: { _source: { ['security-rule']: Rule } }) =>
|
||||
hit._source['security-rule'].rule_id
|
||||
);
|
||||
|
||||
const numberOfRulesToInstall = new Set(ruleIds).size;
|
||||
addElasticRulesButtonClick();
|
||||
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).should('be.enabled').click();
|
||||
cy.get(TOASTER)
|
||||
.should('be.visible')
|
||||
.should('have.text', `${numberOfRulesToInstall} rules installed successfully.`);
|
||||
});
|
||||
};
|
||||
/* Retrieve how many rules were installed from the Fleet package */
|
||||
/* See comments in test above for more details */
|
||||
cy.wait('@installPackageBulk', {
|
||||
timeout: 60000,
|
||||
}).then(({ response: bulkResponse }) => {
|
||||
cy.wrap(bulkResponse?.statusCode).should('eql', 200);
|
||||
|
||||
const packagesBulkInstalled = bulkResponse?.body.items.map(
|
||||
({ name }: { name: string }) => name
|
||||
);
|
||||
|
||||
if (!packagesBulkInstalled.includes('security_detection_engine')) {
|
||||
cy.wait('@installPackage').then(() => {
|
||||
getRulesAndAssertNumberInstalled();
|
||||
});
|
||||
} else {
|
||||
getRulesAndAssertNumberInstalled();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Installation of prebuilt rules', () => {
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
beforeEach(() => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1, RULE_2], installToKibana: false });
|
||||
waitForRulesTableToBeLoaded();
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform').as(
|
||||
'installPrebuiltRules'
|
||||
);
|
||||
});
|
||||
|
||||
it('should install prebuilt rules one by one', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallOne({ rules: [RULE_1] });
|
||||
});
|
||||
|
||||
it('should install multiple selected prebuilt rules by selecting them individually', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallSelected({ rules: [RULE_1, RULE_2] });
|
||||
});
|
||||
|
||||
it('should install multiple selected prebuilt rules by selecting all in page', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAllInPage({ rules: [RULE_1, RULE_2] });
|
||||
});
|
||||
|
||||
it('should install all available rules at once', () => {
|
||||
addElasticRulesButtonClick();
|
||||
assertRuleAvailableForInstallAndInstallAll({ rules: [RULE_1, RULE_2] });
|
||||
});
|
||||
|
||||
it('should display an empty screen when all available prebuilt rules have been installed', () => {
|
||||
addElasticRulesButtonClick();
|
||||
cy.get(INSTALL_ALL_RULES_BUTTON).click();
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', `2 rules installed successfully.`);
|
||||
cy.get(RULE_CHECKBOX).should('not.exist');
|
||||
cy.get(NO_RULES_AVAILABLE_FOR_INSTALL_MESSSAGE).should('exist');
|
||||
cy.get(GO_BACK_TO_RULES_TABLE_BUTTON).should('exist');
|
||||
});
|
||||
|
||||
it('should fail gracefully with toast error message when request to install rules fails', () => {
|
||||
/* Stub request to force rules installation to fail */
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/installation/_perform', {
|
||||
statusCode: 500,
|
||||
}).as('installPrebuiltRules');
|
||||
addElasticRulesButtonClick();
|
||||
cy.get(SELECT_ALL_RULES_ON_PAGE_CHECKBOX).click();
|
||||
cy.get(INSTALL_SELECTED_RULES_BUTTON).click();
|
||||
cy.wait('@installPrebuiltRules');
|
||||
cy.get(TOASTER).should('be.visible').should('have.text', 'Rule installation failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Upgrade of prebuilt rules', () => {
|
||||
const RULE_1_ID = 'rule_1';
|
||||
const RULE_2_ID = 'rule_2';
|
||||
const OUTDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 1',
|
||||
rule_id: RULE_1_ID,
|
||||
version: 2,
|
||||
});
|
||||
const OUTDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Outdated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 1,
|
||||
});
|
||||
const UPDATED_RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Updated rule 2',
|
||||
rule_id: RULE_2_ID,
|
||||
version: 2,
|
||||
});
|
||||
beforeEach(() => {
|
||||
cy.intercept('POST', '/internal/detection_engine/prebuilt_rules/upgrade/_perform').as(
|
||||
'updatePrebuiltRules'
|
||||
);
|
||||
/* Create a new rule and install it */
|
||||
createAndInstallMockedPrebuiltRules({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
/* Create a second version of the rule, making it available for update */
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [UPDATED_RULE_1, UPDATED_RULE_2],
|
||||
installToKibana: false,
|
||||
});
|
||||
waitForRulesTableToBeLoaded();
|
||||
reload();
|
||||
});
|
||||
|
||||
it('should upgrade prebuilt rules one by one', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeOne({ rules: [OUTDATED_RULE_1] });
|
||||
});
|
||||
|
||||
it('should upgrade multiple selected prebuilt rules by selecting them individually', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeSelected({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
});
|
||||
|
||||
it('should upgrade multiple selected prebuilt rules by selecting all in page', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAllInPage({
|
||||
rules: [OUTDATED_RULE_1, OUTDATED_RULE_2],
|
||||
});
|
||||
});
|
||||
|
||||
it('should upgrade all rules with available upgrades at once', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
|
||||
it('should display an empty screen when all rules with available updates have been upgraded', () => {
|
||||
ruleUpdatesTabClick();
|
||||
assertRuleUpgradeAvailableAndUpgradeAll({ rules: [OUTDATED_RULE_1, OUTDATED_RULE_2] });
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
cy.get(NO_RULES_AVAILABLE_FOR_UPGRADE_MESSSAGE).should('exist');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import {
|
||||
COLLAPSED_ACTION_BTN,
|
||||
|
@ -49,7 +51,7 @@ const rules = Array.from(Array(5)).map((_, i) => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Prebuilt rules', () => {
|
||||
describe('Prebuilt rules', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { createRuleAssetSavedObject } from '../../../helpers/rules';
|
||||
import { ADD_ELASTIC_RULES_BTN, RULES_UPDATES_TAB } from '../../../screens/alerts_detection_rules';
|
||||
import {
|
||||
deleteFirstRule,
|
||||
waitForRulesTableToBeLoaded,
|
||||
} from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
installAllPrebuiltRulesRequest,
|
||||
createAndInstallMockedPrebuiltRules,
|
||||
} from '../../../tasks/api_calls/prebuilt_rules';
|
||||
import {
|
||||
resetRulesTableState,
|
||||
deleteAlertsAndRules,
|
||||
reload,
|
||||
deletePrebuiltRulesAssets,
|
||||
} from '../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../urls/navigation';
|
||||
|
||||
const RULE_1 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1',
|
||||
rule_id: 'rule_1',
|
||||
});
|
||||
|
||||
describe(
|
||||
'Detection rules, Prebuilt Rules Installation and Update Notifications',
|
||||
{ tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] },
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
/* Make sure persisted rules table state is cleared */
|
||||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
deletePrebuiltRulesAssets();
|
||||
});
|
||||
|
||||
describe('No notifications', () => {
|
||||
it('should NOT display install or update notifications when no prebuilt assets and no rules are installed', () => {
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
// TODO: test plan asserts "should NOT see a CTA to install prebuilt rules"
|
||||
// but current behavior is to always show the CTA, even with no prebuilt rule assets installed
|
||||
// Update that behaviour and then update this test.
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
|
||||
it('should NOT display install or update notifications when latest rules are installed', () => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: true });
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
|
||||
/* Assert that there are no installation or update notifications */
|
||||
/* Add Elastic Rules button should not contain a number badge */
|
||||
/* and Rule Upgrade tab should not be displayed */
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', 'Add Elastic rules');
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Notifications', () => {
|
||||
beforeEach(() => {
|
||||
createAndInstallMockedPrebuiltRules({ rules: [RULE_1], installToKibana: false });
|
||||
});
|
||||
|
||||
describe('Rules installation notification when no rules have been installed', () => {
|
||||
beforeEach(() => {
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules available for installation', () => {
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible');
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`);
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rule installation notification when at least one rule already installed', () => {
|
||||
beforeEach(() => {
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
/* Create new rule assets with a different rule_id as the one that was */
|
||||
/* installed before in order to trigger the installation notification */
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
const RULE_3 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 3',
|
||||
rule_id: 'rule_3',
|
||||
});
|
||||
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [RULE_2, RULE_3],
|
||||
installToKibana: false,
|
||||
});
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules available for installation', () => {
|
||||
const numberOfAvailableRules = 2;
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible');
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should(
|
||||
'have.text',
|
||||
`Add Elastic rules${numberOfAvailableRules}`
|
||||
);
|
||||
cy.get(RULES_UPDATES_TAB).should('not.exist');
|
||||
});
|
||||
|
||||
it('should notify user a rule is again available for installation if it is deleted', () => {
|
||||
/* Install available rules, assert that the notification is gone */
|
||||
/* then delete one rule and assert that the notification is back */
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
reload();
|
||||
deleteFirstRule();
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('be.visible');
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rule update notification', () => {
|
||||
beforeEach(() => {
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
/* Create new rule asset with the same rule_id as the one that was installed */
|
||||
/* but with a higher version, in order to trigger the update notification */
|
||||
const UPDATED_RULE = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1.1 (updated)',
|
||||
rule_id: 'rule_1',
|
||||
version: 2,
|
||||
});
|
||||
createAndInstallMockedPrebuiltRules({ rules: [UPDATED_RULE], installToKibana: false });
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
reload();
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules package available for update', () => {
|
||||
// No rules available for installation
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules`);
|
||||
// But 1 rule available for update
|
||||
cy.get(RULES_UPDATES_TAB).should('be.visible');
|
||||
cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rule installation available and rule update available notifications', () => {
|
||||
beforeEach(() => {
|
||||
installAllPrebuiltRulesRequest().then(() => {
|
||||
/* Create new rule assets with a different rule_id as the one that was */
|
||||
/* installed before in order to trigger the installation notification */
|
||||
const RULE_2 = createRuleAssetSavedObject({
|
||||
name: 'Test rule 2',
|
||||
rule_id: 'rule_2',
|
||||
});
|
||||
/* Create new rule asset with the same rule_id as the one that was installed */
|
||||
/* but with a higher version, in order to trigger the update notification */
|
||||
const UPDATED_RULE = createRuleAssetSavedObject({
|
||||
name: 'Test rule 1.1 (updated)',
|
||||
rule_id: 'rule_1',
|
||||
version: 2,
|
||||
});
|
||||
createAndInstallMockedPrebuiltRules({
|
||||
rules: [RULE_2, UPDATED_RULE],
|
||||
installToKibana: false,
|
||||
});
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify user about prebuilt rules available for installation and for upgrade', () => {
|
||||
// 1 rule available for installation
|
||||
cy.get(ADD_ELASTIC_RULES_BTN).should('have.text', `Add Elastic rules${1}`);
|
||||
// 1 rule available for update
|
||||
cy.get(RULES_UPDATES_TAB).should('be.visible');
|
||||
cy.get(RULES_UPDATES_TAB).should('have.text', `Rule Updates${1}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getIndexConnector } from '../../../objects/connector';
|
||||
import { getSimpleCustomQueryRule } from '../../../objects/rule';
|
||||
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import { deleteIndex, waitForNewDocumentToBeIndexed } from '../../../tasks/api_calls/elasticsearch';
|
||||
import {
|
||||
cleanKibana,
|
||||
deleteAlertsAndRules,
|
||||
deleteConnectors,
|
||||
deleteDataView,
|
||||
} from '../../../tasks/common';
|
||||
import {
|
||||
createAndEnableRule,
|
||||
fillAboutRuleAndContinue,
|
||||
fillDefineCustomRuleAndContinue,
|
||||
fillRuleAction,
|
||||
fillScheduleRuleAndContinue,
|
||||
} from '../../../tasks/create_new_rule';
|
||||
import { login, visit } from '../../../tasks/login';
|
||||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe(
|
||||
'Rule actions during detection rule creation',
|
||||
{ tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] },
|
||||
() => {
|
||||
const indexConnector = getIndexConnector();
|
||||
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
deleteConnectors();
|
||||
deleteIndex(indexConnector.index);
|
||||
deleteDataView(indexConnector.index);
|
||||
});
|
||||
|
||||
const rule = getSimpleCustomQueryRule();
|
||||
const actions = { connectors: [indexConnector] };
|
||||
const index = actions.connectors[0].index;
|
||||
const initialNumberOfDocuments = 0;
|
||||
const expectedJson = JSON.parse(actions.connectors[0].document);
|
||||
|
||||
it('Indexes a new document after the index action is triggered ', function () {
|
||||
visit(RULE_CREATION);
|
||||
fillDefineCustomRuleAndContinue(rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
fillRuleAction(actions);
|
||||
createAndEnableRule();
|
||||
goToRuleDetails();
|
||||
|
||||
/* When the rule is executed, the action is triggered. We wait for the new document to be indexed */
|
||||
waitForNewDocumentToBeIndexed(index, initialNumberOfDocuments);
|
||||
|
||||
/* We assert that the new indexed document is the one set on the index action */
|
||||
cy.request({
|
||||
method: 'GET',
|
||||
url: `${Cypress.env('ELASTICSEARCH_URL')}/${index}/_search`,
|
||||
headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' },
|
||||
}).then((response) => {
|
||||
expect(response.body.hits.hits[0]._source).to.deep.equal(expectedJson);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { ruleFields } from '../../../data/detection_engine';
|
||||
import {
|
||||
getNewRule,
|
||||
|
@ -112,7 +114,7 @@ import { enablesRule, getDetails } from '../../../tasks/rule_details';
|
|||
|
||||
import { RULE_CREATION, DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
||||
|
||||
describe('Custom query rules', () => {
|
||||
describe('Custom query rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules';
|
||||
import { getDataViewRule } from '../../../objects/rule';
|
||||
import { ALERTS_COUNT, ALERT_GRID_CELL } from '../../../screens/alerts';
|
||||
|
@ -67,7 +69,7 @@ import { getDetails } from '../../../tasks/rule_details';
|
|||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe('Custom query rules', () => {
|
||||
describe('Custom query rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
describe('Custom detection rules creation with data views', () => {
|
||||
const rule = getDataViewRule();
|
||||
const expectedUrls = rule.references?.join('');
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getNewRule, getSavedQueryRule } from '../../../objects/rule';
|
||||
|
||||
import {
|
||||
|
@ -45,7 +47,7 @@ const savedQueryName = 'custom saved query';
|
|||
const savedQueryQuery = 'process.name: test';
|
||||
const savedQueryFilterKey = 'testAgent.value';
|
||||
|
||||
describe('Custom saved_query rules', () => {
|
||||
describe('Custom saved_query rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules';
|
||||
import { getEqlRule, getEqlSequenceRule, getIndexPatterns } from '../../../objects/rule';
|
||||
|
||||
|
@ -61,7 +63,7 @@ import { login, visit } from '../../../tasks/login';
|
|||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe('EQL rules', () => {
|
||||
describe('EQL rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
||||
|
@ -150,10 +152,10 @@ describe('EQL rules', () => {
|
|||
|
||||
const rule = getEqlSequenceRule();
|
||||
|
||||
before(() => {
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverLoad', 'auditbeat_big');
|
||||
});
|
||||
after(() => {
|
||||
afterEach(() => {
|
||||
cy.task('esArchiverUnload', 'auditbeat_big');
|
||||
});
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules';
|
||||
import {
|
||||
getIndexPatterns,
|
||||
|
@ -108,7 +110,7 @@ import { DETECTIONS_RULE_MANAGEMENT_URL, RULE_CREATION } from '../../../urls/nav
|
|||
|
||||
const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d/d"';
|
||||
|
||||
describe('indicator match', () => {
|
||||
describe('indicator match', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
describe('Detection rules, Indicator Match', () => {
|
||||
const expectedUrls = getNewThreatIndicatorRule().references?.join('');
|
||||
const expectedFalsePositives = getNewThreatIndicatorRule().false_positives?.join('');
|
|
@ -4,8 +4,8 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isArray } from 'lodash';
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules';
|
||||
import { getMachineLearningRule } from '../../../objects/rule';
|
||||
|
@ -54,7 +54,7 @@ import { login, visitWithoutDateRange } from '../../../tasks/login';
|
|||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe('Detection rules, machine learning', () => {
|
||||
describe('Detection rules, machine learning', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
const expectedUrls = (getMachineLearningRule().references ?? []).join('');
|
||||
const expectedFalsePositives = (getMachineLearningRule().false_positives ?? []).join('');
|
||||
const expectedTags = (getMachineLearningRule().tags ?? []).join('');
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules';
|
||||
import { getIndexPatterns, getNewTermsRule } from '../../../objects/rule';
|
||||
|
||||
|
@ -59,7 +61,7 @@ import { login, visit } from '../../../tasks/login';
|
|||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe('New Terms rules', () => {
|
||||
describe('New Terms rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules';
|
||||
import { getIndexPatterns, getNewOverrideRule, getSeveritiesOverride } from '../../../objects/rule';
|
||||
|
||||
|
@ -61,7 +63,7 @@ import { getDetails } from '../../../tasks/rule_details';
|
|||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe('Detection rules, override', () => {
|
||||
describe('Detection rules, override', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
const rule = getNewOverrideRule();
|
||||
const expectedUrls = rule.references?.join('');
|
||||
const expectedFalsePositives = rule.false_positives?.join('');
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../../helpers/rules';
|
||||
import { getIndexPatterns, getNewThresholdRule } from '../../../objects/rule';
|
||||
|
||||
|
@ -59,7 +61,7 @@ import { login, visitWithoutDateRange } from '../../../tasks/login';
|
|||
|
||||
import { RULE_CREATION } from '../../../urls/navigation';
|
||||
|
||||
describe('Detection rules, threshold', () => {
|
||||
describe('Detection rules, threshold', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
const rule = getNewThresholdRule();
|
||||
const expectedUrls = rule.references?.join('');
|
||||
const expectedFalsePositives = rule.false_positives?.join('');
|
|
@ -5,7 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ROLES } from '../../../../../common/test';
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
import {
|
||||
COLLAPSED_ACTION_BTN,
|
||||
|
@ -26,7 +28,7 @@ import { SECURITY_DETECTIONS_RULES_URL } from '../../../../urls/navigation';
|
|||
|
||||
const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges';
|
||||
|
||||
describe('All rules - read only', () => {
|
||||
describe('All rules - read only', { tags: tag.ESS }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
createRule(getNewRule({ rule_id: '1' }));
|
|
@ -8,11 +8,12 @@
|
|||
import { INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH } from '@kbn/alerting-plugin/common';
|
||||
import type { MaintenanceWindowCreateBody } from '@kbn/alerting-plugin/common';
|
||||
import type { AsApiContract } from '@kbn/alerting-plugin/server/routes/lib';
|
||||
import { tag } from '../../../../tags';
|
||||
import { cleanKibana } from '../../../../tasks/common';
|
||||
import { login, visit } from '../../../../tasks/login';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation';
|
||||
|
||||
describe('Maintenance window callout on Rule Management page', () => {
|
||||
describe('Maintenance window callout on Rule Management page', { tags: [tag.ESS] }, () => {
|
||||
let maintenanceWindowId = '';
|
||||
|
||||
before(() => {
|
||||
|
@ -34,7 +35,7 @@ describe('Maintenance window callout on Rule Management page', () => {
|
|||
cy.request({
|
||||
method: 'POST',
|
||||
url: INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH,
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' },
|
||||
body,
|
||||
}).then((response) => {
|
||||
maintenanceWindowId = response.body.id;
|
||||
|
@ -46,7 +47,7 @@ describe('Maintenance window callout on Rule Management page', () => {
|
|||
cy.request({
|
||||
method: 'DELETE',
|
||||
url: `${INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH}/${maintenanceWindowId}`,
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' },
|
||||
});
|
||||
});
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation';
|
||||
|
||||
import { FIELD } from '../../../../screens/alerts_details';
|
||||
|
@ -52,7 +54,7 @@ Note that the rule we are using for testing purposes has the following character
|
|||
- Integration: unknown
|
||||
*/
|
||||
|
||||
describe('Related integrations', () => {
|
||||
describe('Related integrations', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../../tags';
|
||||
|
||||
import {
|
||||
waitForRulesTableToBeLoaded,
|
||||
goToTheRuleDetailsOf,
|
||||
|
@ -53,7 +55,7 @@ const EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item';
|
|||
|
||||
const NON_EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item with future expiration';
|
||||
|
||||
describe('Detection rules, bulk duplicate', () => {
|
||||
describe('Detection rules, bulk duplicate', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../../tags';
|
||||
|
||||
import {
|
||||
MODAL_CONFIRMATION_BTN,
|
||||
MODAL_CONFIRMATION_BODY,
|
||||
|
@ -121,7 +123,7 @@ const defaultRuleData = {
|
|||
timeline_id: '495ad7a7-316e-4544-8a0f-9c098daee76e',
|
||||
};
|
||||
|
||||
describe('Detection rules, bulk edit', () => {
|
||||
describe('Detection rules, bulk edit', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
import { tag } from '../../../../../tags';
|
||||
|
||||
import {
|
||||
RULES_BULK_EDIT_ACTIONS_INFO,
|
||||
RULES_BULK_EDIT_ACTIONS_WARNING,
|
||||
ADD_RULE_ACTIONS_MENU_ITEM,
|
||||
} from '../../../../../screens/rules_bulk_actions';
|
||||
import { actionFormSelector } from '../../../../../screens/common/rule_actions';
|
||||
|
||||
import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common';
|
||||
import type { RuleActionCustomFrequency } from '../../../../../tasks/common/rule_actions';
|
||||
import {
|
||||
addSlackRuleAction,
|
||||
assertSlackRuleAction,
|
||||
addEmailConnectorAndRuleAction,
|
||||
assertEmailRuleAction,
|
||||
assertSelectedCustomFrequencyOption,
|
||||
assertSelectedPerRuleRunFrequencyOption,
|
||||
assertSelectedSummaryOfAlertsOption,
|
||||
pickCustomFrequencyOption,
|
||||
pickPerRuleRunFrequencyOption,
|
||||
pickSummaryOfAlertsOption,
|
||||
} from '../../../../../tasks/common/rule_actions';
|
||||
import {
|
||||
waitForRulesTableToBeLoaded,
|
||||
selectNumberOfRules,
|
||||
goToEditRuleActionsSettingsOf,
|
||||
} from '../../../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
waitForBulkEditActionToFinish,
|
||||
submitBulkEditForm,
|
||||
checkOverwriteRuleActionsCheckbox,
|
||||
openBulkEditRuleActionsForm,
|
||||
openBulkActionsMenu,
|
||||
} from '../../../../../tasks/rules_bulk_actions';
|
||||
import { login, visitWithoutDateRange } from '../../../../../tasks/login';
|
||||
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation';
|
||||
|
||||
import { createRule } from '../../../../../tasks/api_calls/rules';
|
||||
import { createSlackConnector } from '../../../../../tasks/api_calls/connectors';
|
||||
|
||||
import {
|
||||
getEqlRule,
|
||||
getNewThreatIndicatorRule,
|
||||
getNewRule,
|
||||
getNewThresholdRule,
|
||||
getMachineLearningRule,
|
||||
getNewTermsRule,
|
||||
} from '../../../../../objects/rule';
|
||||
import { excessivelyInstallAllPrebuiltRules } from '../../../../../tasks/api_calls/prebuilt_rules';
|
||||
|
||||
const ruleNameToAssert = 'Custom rule name with actions';
|
||||
const expectedNumberOfCustomRulesToBeEdited = 7;
|
||||
// 7 custom rules of different types + 3 prebuilt.
|
||||
// number of selected rules doesn't matter, we only want to make sure they will be edited an no modal window displayed as for other actions
|
||||
const expectedNumberOfRulesToBeEdited = expectedNumberOfCustomRulesToBeEdited + 3;
|
||||
|
||||
const expectedExistingSlackMessage = 'Existing slack action';
|
||||
const expectedSlackMessage = 'Slack action test message';
|
||||
|
||||
// TODO: Fix flakiness and unskip https://github.com/elastic/kibana/issues/154721
|
||||
describe.skip(
|
||||
'Detection rules, bulk edit of rule actions',
|
||||
{ tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] },
|
||||
() => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
deleteConnectors();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
createSlackConnector().then(({ body }) => {
|
||||
const actions: RuleActionArray = [
|
||||
{
|
||||
id: body.id,
|
||||
action_type_id: '.slack',
|
||||
group: 'default',
|
||||
params: {
|
||||
message: expectedExistingSlackMessage,
|
||||
},
|
||||
frequency: {
|
||||
summary: true,
|
||||
throttle: null,
|
||||
notifyWhen: 'onActiveAlert',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
createRule(getNewRule({ name: ruleNameToAssert, rule_id: '1', max_signals: 500, actions }));
|
||||
});
|
||||
|
||||
createRule(getEqlRule({ rule_id: '2' }));
|
||||
createRule(getMachineLearningRule({ rule_id: '3' }));
|
||||
createRule(getNewThreatIndicatorRule({ rule_id: '4' }));
|
||||
createRule(getNewThresholdRule({ rule_id: '5' }));
|
||||
createRule(getNewTermsRule({ rule_id: '6' }));
|
||||
createRule(getNewRule({ saved_id: 'mocked', rule_id: '7' }));
|
||||
|
||||
createSlackConnector();
|
||||
});
|
||||
|
||||
context('Restricted action privileges', () => {
|
||||
it("User with no privileges can't add rule actions", () => {
|
||||
login(ROLES.hunter_no_actions);
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL, ROLES.hunter_no_actions);
|
||||
waitForRulesTableToBeLoaded();
|
||||
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkActionsMenu();
|
||||
|
||||
cy.get(ADD_RULE_ACTIONS_MENU_ITEM).should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
context('All actions privileges', () => {
|
||||
beforeEach(() => {
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('Add a rule action to rules (existing connector)', () => {
|
||||
const expectedActionFrequency: RuleActionCustomFrequency = {
|
||||
throttle: 1,
|
||||
throttleUnit: 'd',
|
||||
};
|
||||
|
||||
excessivelyInstallAllPrebuiltRules();
|
||||
|
||||
// select both custom and prebuilt rules
|
||||
selectNumberOfRules(expectedNumberOfRulesToBeEdited);
|
||||
openBulkEditRuleActionsForm();
|
||||
|
||||
// ensure rule actions info callout displayed on the form
|
||||
cy.get(RULES_BULK_EDIT_ACTIONS_INFO).should('be.visible');
|
||||
|
||||
addSlackRuleAction(expectedSlackMessage);
|
||||
pickSummaryOfAlertsOption();
|
||||
pickCustomFrequencyOption(expectedActionFrequency);
|
||||
|
||||
submitBulkEditForm();
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated
|
||||
goToEditRuleActionsSettingsOf(ruleNameToAssert);
|
||||
|
||||
assertSelectedSummaryOfAlertsOption();
|
||||
assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
|
||||
assertSlackRuleAction(expectedExistingSlackMessage, 0);
|
||||
assertSlackRuleAction(expectedSlackMessage, 1);
|
||||
// ensure there is no third action
|
||||
cy.get(actionFormSelector(2)).should('not.exist');
|
||||
});
|
||||
|
||||
it('Overwrite rule actions in rules', () => {
|
||||
excessivelyInstallAllPrebuiltRules();
|
||||
|
||||
// select both custom and prebuilt rules
|
||||
selectNumberOfRules(expectedNumberOfRulesToBeEdited);
|
||||
openBulkEditRuleActionsForm();
|
||||
|
||||
addSlackRuleAction(expectedSlackMessage);
|
||||
pickSummaryOfAlertsOption();
|
||||
pickPerRuleRunFrequencyOption();
|
||||
|
||||
// check overwrite box, ensure warning is displayed
|
||||
checkOverwriteRuleActionsCheckbox();
|
||||
cy.get(RULES_BULK_EDIT_ACTIONS_WARNING).contains(
|
||||
`You're about to overwrite rule actions for ${expectedNumberOfRulesToBeEdited} selected rules`
|
||||
);
|
||||
|
||||
submitBulkEditForm();
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated
|
||||
goToEditRuleActionsSettingsOf(ruleNameToAssert);
|
||||
|
||||
assertSelectedSummaryOfAlertsOption();
|
||||
assertSelectedPerRuleRunFrequencyOption();
|
||||
assertSlackRuleAction(expectedSlackMessage);
|
||||
// ensure existing action was overwritten
|
||||
cy.get(actionFormSelector(1)).should('not.exist');
|
||||
});
|
||||
|
||||
it('Add a rule action to rules (new connector)', () => {
|
||||
const expectedActionFrequency: RuleActionCustomFrequency = {
|
||||
throttle: 2,
|
||||
throttleUnit: 'h',
|
||||
};
|
||||
const expectedEmail = 'test@example.com';
|
||||
const expectedSubject = 'Subject';
|
||||
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
openBulkEditRuleActionsForm();
|
||||
|
||||
addEmailConnectorAndRuleAction(expectedEmail, expectedSubject);
|
||||
pickSummaryOfAlertsOption();
|
||||
pickCustomFrequencyOption(expectedActionFrequency);
|
||||
|
||||
submitBulkEditForm();
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated
|
||||
goToEditRuleActionsSettingsOf(ruleNameToAssert);
|
||||
|
||||
assertSelectedSummaryOfAlertsOption();
|
||||
assertSelectedCustomFrequencyOption(expectedActionFrequency, 1);
|
||||
assertEmailRuleAction(expectedEmail, expectedSubject);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../../tags';
|
||||
|
||||
import {
|
||||
RULES_BULK_EDIT_DATA_VIEWS_WARNING,
|
||||
RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX,
|
||||
} from '../../../../../screens/rules_bulk_actions';
|
||||
|
||||
import { DATA_VIEW_DETAILS, INDEX_PATTERNS_DETAILS } from '../../../../../screens/rule_details';
|
||||
|
||||
import {
|
||||
waitForRulesTableToBeLoaded,
|
||||
goToRuleDetails,
|
||||
selectNumberOfRules,
|
||||
goToTheRuleDetailsOf,
|
||||
} from '../../../../../tasks/alerts_detection_rules';
|
||||
|
||||
import {
|
||||
typeIndexPatterns,
|
||||
waitForBulkEditActionToFinish,
|
||||
submitBulkEditForm,
|
||||
checkOverwriteDataViewCheckbox,
|
||||
checkOverwriteIndexPatternsCheckbox,
|
||||
openBulkEditAddIndexPatternsForm,
|
||||
openBulkEditDeleteIndexPatternsForm,
|
||||
} from '../../../../../tasks/rules_bulk_actions';
|
||||
|
||||
import {
|
||||
hasIndexPatterns,
|
||||
getDetails,
|
||||
assertDetailsNotExist,
|
||||
} from '../../../../../tasks/rule_details';
|
||||
import { login, visitWithoutDateRange } from '../../../../../tasks/login';
|
||||
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../../../../urls/navigation';
|
||||
import { createRule } from '../../../../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules, postDataView } from '../../../../../tasks/common';
|
||||
|
||||
import {
|
||||
getEqlRule,
|
||||
getNewThreatIndicatorRule,
|
||||
getNewRule,
|
||||
getNewThresholdRule,
|
||||
getNewTermsRule,
|
||||
} from '../../../../../objects/rule';
|
||||
|
||||
const DATA_VIEW_ID = 'auditbeat';
|
||||
|
||||
const expectedIndexPatterns = ['index-1-*', 'index-2-*'];
|
||||
|
||||
const expectedNumberOfCustomRulesToBeEdited = 6;
|
||||
|
||||
describe(
|
||||
'Bulk editing index patterns of rules with a data view only',
|
||||
{ tags: [tag.ESS, tag.SERVERLESS] },
|
||||
() => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
login();
|
||||
|
||||
postDataView(DATA_VIEW_ID);
|
||||
|
||||
createRule(getNewRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '1' }));
|
||||
createRule(getEqlRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '2' }));
|
||||
createRule(
|
||||
getNewThreatIndicatorRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '3' })
|
||||
);
|
||||
createRule(
|
||||
getNewThresholdRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '4' })
|
||||
);
|
||||
createRule(getNewTermsRule({ index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '5' }));
|
||||
createRule(
|
||||
getNewRule({
|
||||
index: undefined,
|
||||
data_view_id: DATA_VIEW_ID,
|
||||
saved_id: 'mocked',
|
||||
rule_id: '6',
|
||||
})
|
||||
);
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules with configured data view: all rules are skipped', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
skippedCount: expectedNumberOfCustomRulesToBeEdited,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules with configured data view when data view checkbox is checked: rules are updated', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
|
||||
// click on data view overwrite checkbox, ensure warning is displayed
|
||||
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('not.exist');
|
||||
checkOverwriteDataViewCheckbox();
|
||||
cy.get(RULES_BULK_EDIT_DATA_VIEWS_WARNING).should('be.visible');
|
||||
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
|
||||
|
||||
// check if rule has been updated with index patterns and data view does not exist
|
||||
goToRuleDetails();
|
||||
hasIndexPatterns(expectedIndexPatterns.join(''));
|
||||
assertDetailsNotExist(DATA_VIEW_DETAILS);
|
||||
});
|
||||
|
||||
it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is NOT checked:: rules are skipped', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
checkOverwriteIndexPatternsCheckbox();
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
skippedCount: expectedNumberOfCustomRulesToBeEdited,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
|
||||
});
|
||||
|
||||
it('Overwrite index patterns in custom rules with configured data view when overwrite data view checkbox is checked: rules are updated', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
checkOverwriteIndexPatternsCheckbox();
|
||||
checkOverwriteDataViewCheckbox();
|
||||
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({ updatedCount: expectedNumberOfCustomRulesToBeEdited });
|
||||
|
||||
// check if rule has been overwritten with index patterns and data view does not exist
|
||||
goToRuleDetails();
|
||||
hasIndexPatterns(expectedIndexPatterns.join(''));
|
||||
assertDetailsNotExist(DATA_VIEW_DETAILS);
|
||||
});
|
||||
|
||||
it('Delete index patterns in custom rules with configured data view: rules are skipped', () => {
|
||||
selectNumberOfRules(expectedNumberOfCustomRulesToBeEdited);
|
||||
|
||||
openBulkEditDeleteIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
|
||||
// in delete form data view checkbox is absent
|
||||
cy.get(RULES_BULK_EDIT_OVERWRITE_DATA_VIEW_CHECKBOX).should('not.exist');
|
||||
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
skippedCount: expectedNumberOfCustomRulesToBeEdited,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
describe('Bulk editing index patterns of rules with index patterns and rules with a data view', () => {
|
||||
const customRulesNumber = 2;
|
||||
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverResetKibana');
|
||||
|
||||
postDataView(DATA_VIEW_ID);
|
||||
|
||||
createRule(
|
||||
getNewRule({ name: 'with dataview', index: [], data_view_id: DATA_VIEW_ID, rule_id: '1' })
|
||||
);
|
||||
createRule(getNewRule({ name: 'no data view', index: ['test-index-1-*'], rule_id: '2' }));
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
waitForRulesTableToBeLoaded();
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules: one rule is updated, one rule is skipped', () => {
|
||||
selectNumberOfRules(customRulesNumber);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
updatedCount: 1,
|
||||
skippedCount: 1,
|
||||
showDataViewsWarning: true,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToTheRuleDetailsOf('with dataview');
|
||||
getDetails(DATA_VIEW_DETAILS).contains(DATA_VIEW_ID);
|
||||
assertDetailsNotExist(INDEX_PATTERNS_DETAILS);
|
||||
});
|
||||
|
||||
it('Add index patterns to custom rules when overwrite data view checkbox is checked: all rules are updated', () => {
|
||||
selectNumberOfRules(customRulesNumber);
|
||||
|
||||
openBulkEditAddIndexPatternsForm();
|
||||
typeIndexPatterns(expectedIndexPatterns);
|
||||
checkOverwriteDataViewCheckbox();
|
||||
submitBulkEditForm();
|
||||
|
||||
waitForBulkEditActionToFinish({
|
||||
updatedCount: 2,
|
||||
});
|
||||
|
||||
// check if rule still has data view and index patterns field does not exist
|
||||
goToRuleDetails();
|
||||
assertDetailsNotExist(DATA_VIEW_DETAILS);
|
||||
});
|
||||
});
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { tag } from '../../../../../tags';
|
||||
|
||||
import { expectedExportedRule, getNewRule } from '../../../../../objects/rule';
|
||||
import {
|
||||
|
@ -56,7 +57,7 @@ const prebuiltRules = Array.from(Array(7)).map((_, i) => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Export rules', () => {
|
||||
describe('Export rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
const downloadsFolder = Cypress.config('downloadsFolder');
|
||||
|
||||
before(() => {
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../../tags';
|
||||
|
||||
import { TOASTER } from '../../../../../screens/alerts_detection_rules';
|
||||
import {
|
||||
expectManagementTableRules,
|
||||
|
@ -17,7 +19,7 @@ import { login, visitWithoutDateRange } from '../../../../../tasks/login';
|
|||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../../urls/navigation';
|
||||
const RULES_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_rules.ndjson';
|
||||
|
||||
describe('Import rules', () => {
|
||||
describe('Import rules', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -6,7 +6,9 @@
|
|||
*/
|
||||
|
||||
import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/common';
|
||||
import type { RuleResponse } from '../../../../../../common/api/detection_engine';
|
||||
import type { RuleResponse } from '@kbn/security-solution-plugin/common/api/detection_engine';
|
||||
import { tag } from '../../../../../tags';
|
||||
|
||||
import { createRule, snoozeRule as snoozeRuleViaAPI } from '../../../../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../../../tasks/login';
|
||||
|
@ -42,7 +44,7 @@ import { TOOLTIP } from '../../../../../screens/common';
|
|||
|
||||
const RULES_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_rules.ndjson';
|
||||
|
||||
describe('rule snoozing', () => {
|
||||
describe('rule snoozing', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import {
|
||||
RULE_CHECKBOX,
|
||||
REFRESH_RULES_STATUS,
|
||||
|
@ -32,7 +34,7 @@ import { getNewRule } from '../../../../objects/rule';
|
|||
const DEFAULT_RULE_REFRESH_INTERVAL_VALUE = 60000;
|
||||
const NUM_OF_TEST_RULES = 6;
|
||||
|
||||
describe('Rules table: auto-refresh', () => {
|
||||
describe('Rules table: auto-refresh', { tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../../../tasks/login';
|
||||
import {
|
||||
|
@ -26,7 +28,7 @@ import {
|
|||
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
|
||||
describe('Rules table: filtering', () => {
|
||||
describe('Rules table: filtering', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
import { RULES_MONITORING_TAB, RULE_NAME } from '../../../../screens/alerts_detection_rules';
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
|
@ -12,7 +14,7 @@ import { cleanKibana, deleteAlertsAndRules } from '../../../../tasks/common';
|
|||
import { login, visitWithoutDateRange } from '../../../../tasks/login';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation';
|
||||
|
||||
describe('Rules table: links', () => {
|
||||
describe('Rules table: links', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
|
||||
import { encode } from '@kbn/rison';
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { cleanKibana, resetRulesTableState } from '../../../../tasks/common';
|
||||
import { login, visit } from '../../../../tasks/login';
|
||||
import {
|
||||
|
@ -98,7 +100,7 @@ function expectDefaultRulesTableState(): void {
|
|||
expectTablePage(1);
|
||||
}
|
||||
|
||||
describe('Rules table: persistent state', () => {
|
||||
describe('Rules table: persistent state', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
createTestRules();
|
|
@ -4,6 +4,9 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { createRuleAssetSavedObject } from '../../../../helpers/rules';
|
||||
import {
|
||||
SELECTED_RULES_NUMBER_LABEL,
|
||||
|
@ -32,7 +35,7 @@ const RULE_2 = createRuleAssetSavedObject({
|
|||
rule_id: 'rule_2',
|
||||
});
|
||||
|
||||
describe('Rules table: selection', () => {
|
||||
describe('Rules table: selection', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import {
|
||||
FIRST_RULE,
|
||||
RULE_NAME,
|
||||
|
@ -37,7 +39,7 @@ import {
|
|||
} from '../../../../tasks/table_pagination';
|
||||
import { TABLE_FIRST_PAGE, TABLE_SECOND_PAGE } from '../../../../screens/table_pagination';
|
||||
|
||||
describe('Rules table: sorting', () => {
|
||||
describe('Rules table: sorting', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
|
@ -5,8 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ROLES } from '../../../../common/test';
|
||||
import { deleteRoleAndUser, login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
createListsIndex,
|
||||
|
@ -29,7 +31,7 @@ import {
|
|||
} from '../../../screens/lists';
|
||||
|
||||
describe('value lists', () => {
|
||||
describe('management modal', () => {
|
||||
describe('management modal', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
createListsIndex();
|
||||
|
@ -221,17 +223,10 @@ describe('value lists', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('user with restricted access role', () => {
|
||||
before(() => {
|
||||
describe('user with restricted access role', { tags: tag.ESS }, () => {
|
||||
it('Does not allow a t1 analyst user to upload a value list', () => {
|
||||
login(ROLES.t1_analyst);
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL, ROLES.t1_analyst);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
deleteRoleAndUser(ROLES.t1_analyst);
|
||||
});
|
||||
|
||||
it('Does not allow a t1 analyst user to upload a value list', () => {
|
||||
cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled');
|
||||
});
|
||||
});
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../tags';
|
||||
|
||||
import {
|
||||
PAGE_TITLE,
|
||||
HOST_RISK_PREVIEW_TABLE,
|
||||
|
@ -41,7 +43,10 @@ import {
|
|||
|
||||
describe(
|
||||
'Entity analytics management page',
|
||||
{ env: { ftrConfig: { enableExperimental: ['riskScoringRoutesEnabled'] } } },
|
||||
{
|
||||
env: { ftrConfig: { enableExperimental: ['riskScoringRoutesEnabled'] } },
|
||||
tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS],
|
||||
},
|
||||
() => {
|
||||
before(() => {
|
||||
cleanKibana();
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import {
|
||||
expandFirstAlert,
|
||||
goToClosedAlertsOnRuleDetailsPage,
|
||||
openAddEndpointExceptionFromAlertActionButton,
|
||||
openAddEndpointExceptionFromFirstAlert,
|
||||
waitForAlerts,
|
||||
} from '../../../tasks/alerts';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { getEndpointRule } from '../../../objects/rule';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import {
|
||||
waitForAlertsToPopulate,
|
||||
waitForTheRuleToBeExecuted,
|
||||
} from '../../../tasks/create_new_rule';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
addExceptionEntryFieldValueAndSelectSuggestion,
|
||||
addExceptionEntryFieldValueValue,
|
||||
addExceptionFlyoutItemName,
|
||||
editExceptionFlyoutItemName,
|
||||
selectCloseSingleAlerts,
|
||||
submitNewExceptionItem,
|
||||
validateExceptionConditionField,
|
||||
} from '../../../tasks/exceptions';
|
||||
import { ALERTS_COUNT } from '../../../screens/alerts';
|
||||
import {
|
||||
ADD_AND_BTN,
|
||||
EXCEPTION_CARD_ITEM_CONDITIONS,
|
||||
EXCEPTION_CARD_ITEM_NAME,
|
||||
EXCEPTION_ITEM_VIEWER_CONTAINER,
|
||||
} from '../../../screens/exceptions';
|
||||
import { goToEndpointExceptionsTab } from '../../../tasks/rule_details';
|
||||
|
||||
describe(
|
||||
'Endpoint Exceptions workflows from Alert',
|
||||
{ tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] },
|
||||
() => {
|
||||
const ITEM_NAME = 'Sample Exception List Item';
|
||||
const ITEM_NAME_EDIT = 'Sample Exception List Item';
|
||||
const ADDITIONAL_ENTRY = 'host.hostname';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
cy.task('esArchiverResetKibana');
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
cy.task('esArchiverLoad', 'endpoint');
|
||||
createRule(getEndpointRule());
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForTheRuleToBeExecuted();
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
});
|
||||
|
||||
it('Should be able to create and close single Endpoint exception from overflow menu', () => {
|
||||
// The Endpoint will populated with predefined fields
|
||||
openAddEndpointExceptionFromFirstAlert();
|
||||
|
||||
// As the endpoint.alerts-* is used to trigger the alert the
|
||||
// file.Ext.code_signature will be auto-populated
|
||||
validateExceptionConditionField('file.Ext.code_signature');
|
||||
|
||||
selectCloseSingleAlerts();
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
submitNewExceptionItem();
|
||||
|
||||
// Instead of immediately checking if the Opened Alert has moved to the closed tab,
|
||||
// use the waitForAlerts method to create a buffer, allowing the alerts some time to
|
||||
// be moved to the Closed Alert tab.
|
||||
waitForAlerts();
|
||||
|
||||
// Closed alert should appear in table
|
||||
goToClosedAlertsOnRuleDetailsPage();
|
||||
cy.get(ALERTS_COUNT).should('exist');
|
||||
});
|
||||
|
||||
it('Should be able to create Endpoint exception from Alerts take action button, and change multiple exception items without resetting to initial auto-prefilled entries', () => {
|
||||
// Open first Alert Summary
|
||||
expandFirstAlert();
|
||||
|
||||
// The Endpoint should populated with predefined fields
|
||||
openAddEndpointExceptionFromAlertActionButton();
|
||||
|
||||
// As the endpoint.alerts-* is used to trigger the alert the
|
||||
// file.Ext.code_signature will be auto-populated
|
||||
validateExceptionConditionField('file.Ext.code_signature');
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
|
||||
cy.get(ADD_AND_BTN).click();
|
||||
// edit conditions
|
||||
addExceptionEntryFieldValueAndSelectSuggestion(ADDITIONAL_ENTRY, 6);
|
||||
addExceptionEntryFieldValueValue('foo', 4);
|
||||
|
||||
// Change the name again
|
||||
editExceptionFlyoutItemName(ITEM_NAME_EDIT);
|
||||
|
||||
// validate the condition is still "agent.name" or got rest after the name is changed
|
||||
validateExceptionConditionField(ADDITIONAL_ENTRY);
|
||||
|
||||
selectCloseSingleAlerts();
|
||||
submitNewExceptionItem();
|
||||
|
||||
// Endpoint Exception will move to Endpoint List under Exception tab of rule
|
||||
goToEndpointExceptionsTab();
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', ADDITIONAL_ENTRY);
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../../tags';
|
||||
import { LOADING_INDICATOR } from '../../../../screens/security_header';
|
||||
import { getEndpointRule } from '../../../../objects/rule';
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
addExceptionFromFirstAlert,
|
||||
expandFirstAlert,
|
||||
openAddRuleExceptionFromAlertActionButton,
|
||||
} from '../../../../tasks/alerts';
|
||||
import {
|
||||
addExceptionEntryFieldValue,
|
||||
addExceptionEntryFieldValueValue,
|
||||
addExceptionFlyoutItemName,
|
||||
submitNewExceptionItem,
|
||||
validateExceptionConditionField,
|
||||
validateExceptionCommentCountAndText,
|
||||
editExceptionFlyoutItemName,
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions,
|
||||
validateEmptyExceptionConditionField,
|
||||
} from '../../../../tasks/exceptions';
|
||||
import { login, visitWithoutDateRange } from '../../../../tasks/login';
|
||||
import { goToExceptionsTab } from '../../../../tasks/rule_details';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation';
|
||||
import { deleteAlertsAndRules } from '../../../../tasks/common';
|
||||
import {
|
||||
ADD_AND_BTN,
|
||||
ENTRY_DELETE_BTN,
|
||||
EXCEPTION_CARD_ITEM_CONDITIONS,
|
||||
EXCEPTION_CARD_ITEM_NAME,
|
||||
EXCEPTION_ITEM_VIEWER_CONTAINER,
|
||||
} from '../../../../screens/exceptions';
|
||||
import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule';
|
||||
|
||||
describe(
|
||||
'Auto populate exception with Alert data',
|
||||
{ tags: [tag.ESS, tag.BROKEN_IN_SERVERLESS] },
|
||||
() => {
|
||||
const ITEM_NAME = 'Sample Exception Item';
|
||||
const ITEM_NAME_EDIT = 'Sample Exception Item Edit';
|
||||
const ADDITIONAL_ENTRY = 'host.hostname';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
cy.task('esArchiverResetKibana');
|
||||
cy.task('esArchiverLoad', 'endpoint');
|
||||
login();
|
||||
createRule(getEndpointRule());
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
deleteAlertsAndRules();
|
||||
});
|
||||
afterEach(() => {
|
||||
cy.task('esArchiverUnload', 'endpoint');
|
||||
});
|
||||
|
||||
it('Should create a Rule exception item from alert actions overflow menu and auto populate the conditions using alert Highlighted fields', () => {
|
||||
cy.get(LOADING_INDICATOR).should('not.exist');
|
||||
addExceptionFromFirstAlert();
|
||||
|
||||
const highlightedFieldsBasedOnAlertDoc = [
|
||||
'host.name',
|
||||
'agent.id',
|
||||
'user.name',
|
||||
'process.executable',
|
||||
'file.path',
|
||||
];
|
||||
|
||||
/**
|
||||
* Validate the highlighted fields are auto populated, these
|
||||
* fields are based on the alert document that should be generated
|
||||
* when the endpoint rule runs
|
||||
*/
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc);
|
||||
|
||||
/**
|
||||
* Validate that the comments are opened by default with one comment added
|
||||
* showing a text contains information about the pre-filled conditions
|
||||
*/
|
||||
validateExceptionCommentCountAndText(
|
||||
1,
|
||||
'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):'
|
||||
);
|
||||
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
submitNewExceptionItem();
|
||||
});
|
||||
it('Should create a Rule exception from Alerts take action button and change multiple exception items without resetting to initial auto-prefilled entries', () => {
|
||||
cy.get(LOADING_INDICATOR).should('not.exist');
|
||||
|
||||
// Open first Alert Summary
|
||||
expandFirstAlert();
|
||||
|
||||
// The Rule exception should populated with highlighted fields
|
||||
openAddRuleExceptionFromAlertActionButton();
|
||||
|
||||
const highlightedFieldsBasedOnAlertDoc = [
|
||||
'host.name',
|
||||
'agent.id',
|
||||
'user.name',
|
||||
'process.executable',
|
||||
'file.path',
|
||||
];
|
||||
|
||||
/**
|
||||
* Validate the highlighted fields are auto populated, these
|
||||
* fields are based on the alert document that should be generated
|
||||
* when the endpoint rule runs
|
||||
*/
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc);
|
||||
|
||||
/**
|
||||
* Validate that the comments are opened by default with one comment added
|
||||
* showing a text contains information about the pre-filled conditions
|
||||
*/
|
||||
validateExceptionCommentCountAndText(
|
||||
1,
|
||||
'Exception conditions are pre-filled with relevant data from an alert with the alert id (_id):'
|
||||
);
|
||||
|
||||
addExceptionFlyoutItemName(ITEM_NAME);
|
||||
|
||||
cy.get(ADD_AND_BTN).click();
|
||||
|
||||
// edit conditions
|
||||
addExceptionEntryFieldValue(ADDITIONAL_ENTRY, 5);
|
||||
addExceptionEntryFieldValueValue('foo', 5);
|
||||
|
||||
// Change the name again
|
||||
editExceptionFlyoutItemName(ITEM_NAME_EDIT);
|
||||
|
||||
// validate the condition is still 'host.hostname' or got rest after the name is changed
|
||||
validateExceptionConditionField(ADDITIONAL_ENTRY);
|
||||
|
||||
submitNewExceptionItem();
|
||||
|
||||
goToExceptionsTab();
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME_EDIT);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).contains('span', 'host.hostname');
|
||||
});
|
||||
it('Should delete all prefilled exception entries when creating a Rule exception from Alerts take action button without resetting to initial auto-prefilled entries', () => {
|
||||
cy.get(LOADING_INDICATOR).should('not.exist');
|
||||
|
||||
// Open first Alert Summary
|
||||
expandFirstAlert();
|
||||
|
||||
// The Rule exception should populated with highlighted fields
|
||||
openAddRuleExceptionFromAlertActionButton();
|
||||
|
||||
const highlightedFieldsBasedOnAlertDoc = [
|
||||
'host.name',
|
||||
'agent.id',
|
||||
'user.name',
|
||||
'process.executable',
|
||||
'file.path',
|
||||
];
|
||||
|
||||
/**
|
||||
* Validate the highlighted fields are auto populated, these
|
||||
* fields are based on the alert document that should be generated
|
||||
* when the endpoint rule runs
|
||||
*/
|
||||
validateHighlightedFieldsPopulatedAsExceptionConditions(highlightedFieldsBasedOnAlertDoc);
|
||||
|
||||
/**
|
||||
* Delete all the highlighted fields to see if any condition
|
||||
* will prefuilled again.
|
||||
*/
|
||||
const highlightedFieldsCount = highlightedFieldsBasedOnAlertDoc.length - 1;
|
||||
highlightedFieldsBasedOnAlertDoc.forEach((_, index) =>
|
||||
cy
|
||||
.get(ENTRY_DELETE_BTN)
|
||||
.eq(highlightedFieldsCount - index)
|
||||
.click()
|
||||
);
|
||||
|
||||
/**
|
||||
* Validate that there are no highlighted fields are auto populated
|
||||
* after the deletion
|
||||
*/
|
||||
validateEmptyExceptionConditionField();
|
||||
});
|
||||
}
|
||||
);
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
|
||||
|
@ -65,7 +66,7 @@ import { getExceptionList } from '../../../objects/exception';
|
|||
// to test in enzyme and very small changes can inadvertently add
|
||||
// bugs. As the complexity within the builder grows, these should
|
||||
// ensure the most basic logic holds.
|
||||
describe.skip('Exceptions flyout', { testIsolation: false }, () => {
|
||||
describe.skip('Exceptions flyout', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
// this is a made-up index that has just the necessary
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
|
||||
|
@ -30,7 +31,7 @@ import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
|||
|
||||
describe(
|
||||
'Add multiple conditions and validate the generated exceptions',
|
||||
{ testIsolation: false },
|
||||
{ tags: [tag.ESS, tag.SERVERLESS] },
|
||||
() => {
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverResetKibana');
|
|
@ -4,6 +4,8 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import {
|
||||
addExceptionEntryFieldMatchIncludedValue,
|
||||
addExceptionEntryFieldValue,
|
||||
|
@ -49,7 +51,7 @@ const goToRulesAndOpenValueListModal = () => {
|
|||
openValueListsModal();
|
||||
};
|
||||
|
||||
describe('Use Value list in exception entry', () => {
|
||||
describe('Use Value list in exception entry', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
|
||||
|
@ -44,7 +45,7 @@ import {
|
|||
} from '../../../screens/exceptions';
|
||||
import { createEndpointExceptionList } from '../../../tasks/api_calls/exceptions';
|
||||
|
||||
describe('Add endpoint exception from rule details', () => {
|
||||
describe('Add endpoint exception from rule details', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
const ITEM_NAME = 'Sample Exception List Item';
|
||||
|
||||
before(() => {
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getException, getExceptionList } from '../../../objects/exception';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
|
@ -59,7 +60,7 @@ import {
|
|||
} from '../../../tasks/api_calls/exceptions';
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
|
||||
describe('Add/edit exception from rule details', () => {
|
||||
describe('Add/edit exception from rule details', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert';
|
||||
const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name';
|
||||
const ITEM_FIELD = 'unique_value.test';
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { ALERTS_COUNT, EMPTY_ALERT_TABLE } from '../../../screens/alerts';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
goToClosedAlertsOnRuleDetailsPage,
|
||||
goToOpenedAlertsOnRuleDetailsPage,
|
||||
} from '../../../tasks/alerts';
|
||||
import {
|
||||
editException,
|
||||
editExceptionFlyoutItemName,
|
||||
submitEditedExceptionItem,
|
||||
} from '../../../tasks/exceptions';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import {
|
||||
addFirstExceptionFromRuleDetails,
|
||||
goToAlertsTab,
|
||||
goToExceptionsTab,
|
||||
openEditException,
|
||||
removeException,
|
||||
waitForTheRuleToBeExecuted,
|
||||
} from '../../../tasks/rule_details';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../urls/navigation';
|
||||
import { postDataView, deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import {
|
||||
NO_EXCEPTIONS_EXIST_PROMPT,
|
||||
EXCEPTION_ITEM_VIEWER_CONTAINER,
|
||||
EXCEPTION_CARD_ITEM_NAME,
|
||||
EXCEPTION_CARD_ITEM_CONDITIONS,
|
||||
EXCEPTION_ITEM_CONTAINER,
|
||||
VALUES_INPUT,
|
||||
FIELD_INPUT_PARENT,
|
||||
} from '../../../screens/exceptions';
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
|
||||
describe(
|
||||
'Add exception using data views from rule details',
|
||||
{ tags: [tag.ESS, tag.SERVERLESS] },
|
||||
() => {
|
||||
const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1 alert';
|
||||
const ITEM_NAME = 'Sample Exception List Item';
|
||||
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
cy.task('esArchiverLoad', 'exceptions');
|
||||
login();
|
||||
postDataView('exceptions-*');
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'exceptions');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createRule(
|
||||
getNewRule({
|
||||
query: 'agent.name:*',
|
||||
data_view_id: 'exceptions-*',
|
||||
interval: '10s',
|
||||
rule_id: 'rule_testing',
|
||||
})
|
||||
);
|
||||
login();
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.task('esArchiverUnload', 'exceptions_2');
|
||||
});
|
||||
|
||||
it('Creates an exception item and close all matching alerts', () => {
|
||||
goToExceptionsTab();
|
||||
// when no exceptions exist, empty component shows with action to add exception
|
||||
cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist');
|
||||
|
||||
// clicks prompt button to add first exception that will also select to close
|
||||
// all matching alerts
|
||||
addFirstExceptionFromRuleDetails(
|
||||
{
|
||||
field: 'agent.name',
|
||||
operator: 'is',
|
||||
values: ['foo'],
|
||||
},
|
||||
ITEM_NAME
|
||||
);
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
|
||||
// Alerts table should now be empty from having added exception and closed
|
||||
// matching alert
|
||||
goToAlertsTab();
|
||||
cy.get(EMPTY_ALERT_TABLE).should('exist');
|
||||
|
||||
// Closed alert should appear in table
|
||||
goToClosedAlertsOnRuleDetailsPage();
|
||||
cy.get(ALERTS_COUNT).should('exist');
|
||||
cy.get(ALERTS_COUNT).should('have.text', `${NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS}`);
|
||||
|
||||
// Remove the exception and load an event that would have matched that exception
|
||||
// to show that said exception now starts to show up again
|
||||
goToExceptionsTab();
|
||||
|
||||
// when removing exception and again, no more exist, empty screen shows again
|
||||
removeException();
|
||||
cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist');
|
||||
|
||||
// load more docs
|
||||
cy.task('esArchiverLoad', 'exceptions_2');
|
||||
|
||||
// now that there are no more exceptions, the docs should match and populate alerts
|
||||
goToAlertsTab();
|
||||
goToOpenedAlertsOnRuleDetailsPage();
|
||||
waitForTheRuleToBeExecuted();
|
||||
waitForAlertsToPopulate();
|
||||
|
||||
cy.get(ALERTS_COUNT).should('exist');
|
||||
cy.get(ALERTS_COUNT).should('have.text', '2 alerts');
|
||||
});
|
||||
|
||||
it('Edits an exception item', () => {
|
||||
const NEW_ITEM_NAME = 'Exception item-EDITED';
|
||||
const ITEM_FIELD = 'unique_value.test';
|
||||
const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.name';
|
||||
|
||||
goToExceptionsTab();
|
||||
// add item to edit
|
||||
addFirstExceptionFromRuleDetails(
|
||||
{
|
||||
field: ITEM_FIELD,
|
||||
operator: 'is',
|
||||
values: ['foo'],
|
||||
},
|
||||
ITEM_NAME
|
||||
);
|
||||
|
||||
// displays existing exception items
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist');
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' unique_value.testIS foo');
|
||||
|
||||
// open edit exception modal
|
||||
openEditException();
|
||||
|
||||
// edit exception item name
|
||||
editExceptionFlyoutItemName(NEW_ITEM_NAME);
|
||||
|
||||
// check that the existing item's field is being populated
|
||||
cy.get(EXCEPTION_ITEM_CONTAINER)
|
||||
.eq(0)
|
||||
.find(FIELD_INPUT_PARENT)
|
||||
.eq(0)
|
||||
.should('have.text', ITEM_FIELD);
|
||||
cy.get(VALUES_INPUT).should('have.text', 'foo');
|
||||
|
||||
// edit conditions
|
||||
editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0);
|
||||
|
||||
// submit
|
||||
submitEditedExceptionItem();
|
||||
|
||||
// new exception item displays
|
||||
cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
|
||||
|
||||
// check that updates stuck
|
||||
cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME);
|
||||
cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.nameIS foo');
|
||||
});
|
||||
}
|
||||
);
|
|
@ -4,10 +4,11 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getExceptionList } from '../../../objects/exception';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { ROLES } from '../../../../common/test';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { goToExceptionsTab, goToAlertsTab } from '../../../tasks/rule_details';
|
||||
|
@ -27,7 +28,7 @@ import {
|
|||
deleteExceptionList,
|
||||
} from '../../../tasks/api_calls/exceptions';
|
||||
|
||||
describe('Exceptions viewer read only', () => {
|
||||
describe('Exceptions viewer read only', { tags: tag.ESS }, () => {
|
||||
const exceptionList = getExceptionList();
|
||||
|
||||
before(() => {
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { getExceptionList } from '../../../../objects/exception';
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
|
@ -40,7 +41,7 @@ const getExceptionList1 = () => ({
|
|||
|
||||
const EXCEPTION_LIST_NAME = 'Newly created list';
|
||||
|
||||
describe('Exception list detail page', () => {
|
||||
describe('Exception list detail page', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
login();
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../tags';
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
|
@ -38,7 +39,7 @@ import {
|
|||
waitForExceptionsTableToBeLoaded,
|
||||
} from '../../../tasks/exceptions_table';
|
||||
|
||||
describe('Add, edit and delete exception', () => {
|
||||
describe('Add, edit and delete exception', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
cy.task('esArchiverLoad', 'exceptions');
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { createRule } from '../../../../tasks/api_calls/rules';
|
||||
import { getExceptionList } from '../../../../objects/exception';
|
||||
|
@ -40,7 +41,7 @@ const getExceptionList2 = () => ({
|
|||
list_id: 'exception_list_2',
|
||||
});
|
||||
|
||||
describe('Duplicate List', () => {
|
||||
describe('Duplicate List', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
login();
|
|
@ -4,6 +4,8 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { tag } from '../../../../tags';
|
||||
|
||||
import { getExceptionList } from '../../../../objects/exception';
|
||||
import { getNewRule } from '../../../../objects/rule';
|
||||
import {
|
||||
|
@ -34,7 +36,7 @@ const getExceptionList2 = () => ({
|
|||
name: EXCEPTION_LIST_NAME_TWO,
|
||||
list_id: 'exception_list_2',
|
||||
});
|
||||
describe('Filter Lists', () => {
|
||||
describe('Filter Lists', { tags: [tag.ESS, tag.SERVERLESS] }, () => {
|
||||
beforeEach(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
login();
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue