Skip to content

Commit

Permalink
[Security Solution] Exceptions Cypress tests (#81759) (#84469)
Browse files Browse the repository at this point in the history
* improves 'Creates and activates a new custom rule' test

* fixes constant problem

* improves 'Creates and activates a new custom rule with override option' test

* improves 'Creates and activates a new threshold rule' test

* refactor

* fixes type check issue

* improves assertions

* removes unused code

* changes variables for constants

* improves 'waitForTheRuleToBeExecuted' test

* improves readability

* fixes jenkins error

* refactor

* blah

* more things

* finishes 'Creates an exception from rule details and deletes the excpetion' implementation

* implements 'Creates an exception from an alert and deletes the exception'

* updates VALUES_INPUT locator

* updates archiver

* refactor

* improves the code

* fixes CI error

* renames exceptions archive

* refactor

* fixes merge issue

* fixes CI issue

* debug

* refactor

* improves test data

* removes signals index after the execution

* removes unused line

* removes unused variable

* refactors 'numberOfauditbeatExceptionsAlerts' constant to camel case

* simplifies the archive

* waits for the rule to be executed after navigating to opened alerts tab

* cleaning data

* fixes tests flakiness

* cleans test data

* refactors code

* removes unsused archives

* cleans data

* simplifies data

* fixes CI issue

Co-authored-by: Elastic Machine <[email protected]>
Co-authored-by: Kibana Machine <[email protected]>

Co-authored-by: Elastic Machine <[email protected]>
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
3 people authored Nov 30, 2020
1 parent dec83f2 commit ffe6614
Show file tree
Hide file tree
Showing 16 changed files with 7,572 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { exception } from '../objects/exception';
import { newRule } from '../objects/rule';

import { RULE_STATUS } from '../screens/create_new_rule';
import { SERVER_SIDE_EVENT_COUNT } from '../screens/timeline';

import {
addExceptionFromFirstAlert,
goToClosedAlerts,
goToManageAlertsDetectionRules,
goToOpenedAlerts,
waitForAlertsIndexToBeCreated,
} from '../tasks/alerts';
import { createCustomRule, deleteCustomRule, removeSignalsIndex } from '../tasks/api_calls';
import { goToRuleDetails } from '../tasks/alerts_detection_rules';
import { waitForAlertsToPopulate } from '../tasks/create_new_rule';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';
import {
activatesRule,
addsException,
addsExceptionFromRuleSettings,
goToAlertsTab,
goToExceptionsTab,
removeException,
waitForTheRuleToBeExecuted,
} from '../tasks/rule_details';
import { refreshPage } from '../tasks/security_header';

import { DETECTIONS_URL } from '../urls/navigation';

const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = 1;

describe('Exceptions', () => {
beforeEach(() => {
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL);
waitForAlertsIndexToBeCreated();
createCustomRule(newRule);
goToManageAlertsDetectionRules();
goToRuleDetails();

cy.get(RULE_STATUS).should('have.text', '—');

esArchiverLoad('auditbeat_for_exceptions');
activatesRule();
waitForTheRuleToBeExecuted();
waitForAlertsToPopulate();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfInitialAlertsText) => {
cy.wrap(parseInt(numberOfInitialAlertsText, 10)).should(
'eql',
NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS
);
});
});

afterEach(() => {
esArchiverUnload('auditbeat_for_exceptions');
esArchiverUnload('auditbeat_for_exceptions2');
removeSignalsIndex();
deleteCustomRule();
});
context('From rule', () => {
it('Creates an exception and deletes it', () => {
goToExceptionsTab();
addsExceptionFromRuleSettings(exception);
esArchiverLoad('auditbeat_for_exceptions2');
waitForTheRuleToBeExecuted();
goToAlertsTab();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfAlertsAfterCreatingExceptionText) => {
cy.wrap(parseInt(numberOfAlertsAfterCreatingExceptionText, 10)).should('eql', 0);
});

goToClosedAlerts();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfClosedAlertsAfterCreatingExceptionText) => {
cy.wrap(parseInt(numberOfClosedAlertsAfterCreatingExceptionText, 10)).should(
'eql',
NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS
);
});

goToOpenedAlerts();
waitForTheRuleToBeExecuted();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfOpenedAlertsAfterCreatingExceptionText) => {
cy.wrap(parseInt(numberOfOpenedAlertsAfterCreatingExceptionText, 10)).should('eql', 0);
});

goToExceptionsTab();
removeException();
refreshPage();
goToAlertsTab();
waitForTheRuleToBeExecuted();
waitForAlertsToPopulate();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfAlertsAfterRemovingExceptionsText) => {
cy.wrap(parseInt(numberOfAlertsAfterRemovingExceptionsText, 10)).should(
'eql',
NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS
);
});
});
});

context('From alert', () => {
it('Creates an exception and deletes it', () => {
addExceptionFromFirstAlert();
addsException(exception);
esArchiverLoad('auditbeat_for_exceptions2');

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfAlertsAfterCreatingExceptionText) => {
cy.wrap(parseInt(numberOfAlertsAfterCreatingExceptionText, 10)).should('eql', 0);
});

goToClosedAlerts();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfClosedAlertsAfterCreatingExceptionText) => {
cy.wrap(parseInt(numberOfClosedAlertsAfterCreatingExceptionText, 10)).should(
'eql',
NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS
);
});

goToOpenedAlerts();
waitForTheRuleToBeExecuted();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfOpenedAlertsAfterCreatingExceptionText) => {
cy.wrap(parseInt(numberOfOpenedAlertsAfterCreatingExceptionText, 10)).should('eql', 0);
});

goToExceptionsTab();
removeException();
goToAlertsTab();
waitForTheRuleToBeExecuted();
waitForAlertsToPopulate();
refreshPage();

cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((numberOfAlertsAfterRemovingExceptionsText) => {
cy.wrap(parseInt(numberOfAlertsAfterRemovingExceptionsText, 10)).should(
'eql',
NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS
);
});
});
});
});
17 changes: 17 additions & 0 deletions x-pack/plugins/security_solution/cypress/objects/exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export interface Exception {
field: string;
operator: string;
values: string[];
}

export const exception: Exception = {
field: 'host.name',
operator: 'is',
values: ['suricata-iowa'],
};
2 changes: 2 additions & 0 deletions x-pack/plugins/security_solution/cypress/screens/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

export const ADD_EXCEPTION_BTN = '[data-test-subj="addExceptionButton"]';

export const ALERTS = '[data-test-subj="event"]';

export const ALERT_CHECKBOX = '[data-test-subj="select-event-container"] .euiCheckbox__input';
Expand Down
24 changes: 24 additions & 0 deletions x-pack/plugins/security_solution/cypress/screens/exceptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export const ADD_EXCEPTIONS_BTN = '[data-test-subj="exceptionsHeaderAddExceptionBtn"]';

export const CLOSE_ALERTS_CHECKBOX =
'[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]';

export const CONFIRM_BTN = '[data-test-subj="add-exception-confirm-button"]';

export const FIELD_INPUT =
'[data-test-subj="fieldAutocompleteComboBox"] [data-test-subj="comboBoxInput"]';

export const FIELD_INPUT_RESULT = '.euiFilterSelectItem';

export const LOADING_SPINNER = '[data-test-subj="loading-spinner"]';

export const OPERATOR_INPUT = '[data-test-subj="operatorAutocompleteComboBox"]';

export const VALUES_INPUT =
'[data-test-subj="valuesAutocompleteMatch"] [data-test-subj="comboBoxInput"]';
14 changes: 13 additions & 1 deletion x-pack/plugins/security_solution/cypress/screens/rule_details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,22 @@ export const ABOUT_DETAILS =

export const ADDITIONAL_LOOK_BACK_DETAILS = 'Additional look-back time';

export const ALERTS_TAB = '[data-test-subj="alertsTab"]';

export const ANOMALY_SCORE_DETAILS = 'Anomaly score';

export const CUSTOM_QUERY_DETAILS = 'Custom query';

export const DEFINITION_DETAILS =
'[data-test-subj=definitionRule] [data-test-subj="listItemColumnStepRuleDescription"]';

export const DELETE_RULE = '[data-test-subj=rules-details-delete-rule]';

export const DETAILS_DESCRIPTION = '.euiDescriptionList__description';

export const DETAILS_TITLE = '.euiDescriptionList__title';

export const DELETE_RULE = '[data-test-subj=rules-details-delete-rule]';
export const EXCEPTIONS_TAB = '[data-test-subj="exceptionsTab"]';

export const FALSE_POSITIVES_DETAILS = 'False positive examples';

Expand All @@ -42,6 +46,8 @@ export const MACHINE_LEARNING_JOB_STATUS = '[data-test-subj="machineLearningJobS

export const MITRE_ATTACK_DETAILS = 'MITRE ATT&CK';

export const REFRESH_BUTTON = '[data-test-subj="refreshButton"]';

export const RULE_ABOUT_DETAILS_HEADER_TOGGLE = '[data-test-subj="stepAboutDetailsToggle"]';

export const RULE_NAME_HEADER = '[data-test-subj="header-page-title"]';
Expand All @@ -54,6 +60,12 @@ export const RISK_SCORE_OVERRIDE_DETAILS = 'Risk score override';

export const REFERENCE_URLS_DETAILS = 'Reference URLs';

export const REMOVE_EXCEPTION_BTN = '[data-test-subj="exceptionsViewerDeleteBtn"]';

export const RULE_SWITCH = '[data-test-subj="ruleSwitch"]';

export const RULE_SWITCH_LOADER = '[data-test-subj="rule-switch-loader"]';

export const RULE_TYPE_DETAILS = 'Rule type';

export const RUNS_EVERY_DETAILS = 'Runs every';
Expand Down
34 changes: 23 additions & 11 deletions x-pack/plugins/security_solution/cypress/tasks/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,34 @@
*/

import {
CLOSED_ALERTS_FILTER_BTN,
EXPAND_ALERT_BTN,
LOADING_ALERTS_PANEL,
MANAGE_ALERT_DETECTION_RULES_BTN,
OPENED_ALERTS_FILTER_BTN,
SEND_ALERT_TO_TIMELINE_BTN,
ADD_EXCEPTION_BTN,
ALERT_RISK_SCORE_HEADER,
ALERTS,
ALERT_CHECKBOX,
TIMELINE_CONTEXT_MENU_BTN,
CLOSE_ALERT_BTN,
TAKE_ACTION_POPOVER_BTN,
CLOSE_SELECTED_ALERTS_BTN,
CLOSED_ALERTS_FILTER_BTN,
EXPAND_ALERT_BTN,
IN_PROGRESS_ALERTS_FILTER_BTN,
OPEN_ALERT_BTN,
OPEN_SELECTED_ALERTS_BTN,
LOADING_ALERTS_PANEL,
MANAGE_ALERT_DETECTION_RULES_BTN,
MARK_ALERT_IN_PROGRESS_BTN,
MARK_SELECTED_ALERTS_IN_PROGRESS_BTN,
ALERT_RISK_SCORE_HEADER,
OPEN_ALERT_BTN,
OPEN_SELECTED_ALERTS_BTN,
OPENED_ALERTS_FILTER_BTN,
SEND_ALERT_TO_TIMELINE_BTN,
TAKE_ACTION_POPOVER_BTN,
TIMELINE_CONTEXT_MENU_BTN,
} from '../screens/alerts';
import { REFRESH_BUTTON } from '../screens/security_header';
import { TIMELINE_COLUMN_SPINNER } from '../screens/timeline';

export const addExceptionFromFirstAlert = () => {
cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click();
cy.get(ADD_EXCEPTION_BTN).click();
};

export const closeFirstAlert = () => {
cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click({ force: true });
cy.get(CLOSE_ALERT_BTN).click();
Expand All @@ -43,6 +49,9 @@ export const expandFirstAlert = () => {

export const goToClosedAlerts = () => {
cy.get(CLOSED_ALERTS_FILTER_BTN).click();
cy.get(REFRESH_BUTTON).should('not.have.text', 'Updating');
cy.get(REFRESH_BUTTON).should('have.text', 'Refresh');
cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist');
};

export const goToManageAlertsDetectionRules = () => {
Expand All @@ -51,6 +60,9 @@ export const goToManageAlertsDetectionRules = () => {

export const goToOpenedAlerts = () => {
cy.get(OPENED_ALERTS_FILTER_BTN).click({ force: true });
cy.get(REFRESH_BUTTON).should('not.have.text', 'Updating');
cy.get(REFRESH_BUTTON).should('have.text', 'Refresh');
cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist');
};

export const openFirstAlert = () => {
Expand Down
45 changes: 45 additions & 0 deletions x-pack/plugins/security_solution/cypress/tasks/api_calls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { CustomRule } from '../objects/rule';

export const createCustomRule = (rule: CustomRule) => {
cy.request({
method: 'POST',
url: 'api/detection_engine/rules',
body: {
rule_id: 'rule_testing',
risk_score: parseInt(rule.riskScore, 10),
description: rule.description,
interval: '10s',
name: rule.name,
severity: rule.severity.toLocaleLowerCase(),
type: 'query',
from: 'now-17520h',
index: ['exceptions-*'],
query: rule.customQuery,
language: 'kuery',
enabled: false,
},
headers: { 'kbn-xsrf': 'cypress-creds' },
});
};

export const deleteCustomRule = () => {
cy.request({
method: 'DELETE',
url: 'api/detection_engine/rules?rule_id=rule_testing',
headers: { 'kbn-xsrf': 'cypress-creds' },
});
};

export const removeSignalsIndex = () => {
cy.request({
method: 'DELETE',
url: `api/detection_engine/index`,
headers: { 'kbn-xsrf': 'delete-signals' },
});
};
Loading

0 comments on commit ffe6614

Please sign in to comment.