Skip to content

Commit

Permalink
[SIEM] Adds threshold rule creation Cypress test (#74065) (#74127)
Browse files Browse the repository at this point in the history
* adds threshold rule creation cypress test

* fixes type chek error

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
MadameSheema and elasticmachine authored Aug 4, 2020
1 parent 6687bda commit 046a9bc
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* 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 { newThresholdRule } from '../objects/rule';

import {
CUSTOM_RULES_BTN,
RISK_SCORE,
RULE_NAME,
RULES_ROW,
RULES_TABLE,
SEVERITY,
} from '../screens/alerts_detection_rules';
import {
ABOUT_FALSE_POSITIVES,
ABOUT_INVESTIGATION_NOTES,
ABOUT_MITRE,
ABOUT_RISK,
ABOUT_RULE_DESCRIPTION,
ABOUT_SEVERITY,
ABOUT_STEP,
ABOUT_TAGS,
ABOUT_URLS,
DEFINITION_CUSTOM_QUERY,
DEFINITION_INDEX_PATTERNS,
DEFINITION_THRESHOLD,
DEFINITION_TIMELINE,
DEFINITION_STEP,
INVESTIGATION_NOTES_MARKDOWN,
INVESTIGATION_NOTES_TOGGLE,
RULE_ABOUT_DETAILS_HEADER_TOGGLE,
RULE_NAME_HEADER,
SCHEDULE_LOOPBACK,
SCHEDULE_RUNS,
SCHEDULE_STEP,
} from '../screens/rule_details';

import {
goToManageAlertsDetectionRules,
waitForAlertsIndexToBeCreated,
waitForAlertsPanelToBeLoaded,
} from '../tasks/alerts';
import {
changeToThreeHundredRowsPerPage,
filterByCustomRules,
goToCreateNewRule,
goToRuleDetails,
waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded,
waitForRulesToBeLoaded,
} from '../tasks/alerts_detection_rules';
import {
createAndActivateRule,
fillAboutRuleAndContinue,
fillDefineThresholdRuleAndContinue,
selectThresholdRuleType,
} from '../tasks/create_new_rule';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';

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

describe('Detection rules, threshold', () => {
before(() => {
esArchiverLoad('timeline');
});

after(() => {
esArchiverUnload('timeline');
});

it('Creates and activates a new threshold rule', () => {
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL);
waitForAlertsPanelToBeLoaded();
waitForAlertsIndexToBeCreated();
goToManageAlertsDetectionRules();
waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded();
goToCreateNewRule();
selectThresholdRuleType();
fillDefineThresholdRuleAndContinue(newThresholdRule);
fillAboutRuleAndContinue(newThresholdRule);
createAndActivateRule();

cy.get(CUSTOM_RULES_BTN).invoke('text').should('eql', 'Custom rules (1)');

changeToThreeHundredRowsPerPage();
waitForRulesToBeLoaded();

const expectedNumberOfRules = 1;
cy.get(RULES_TABLE).then(($table) => {
cy.wrap($table.find(RULES_ROW).length).should('eql', expectedNumberOfRules);
});

filterByCustomRules();

cy.get(RULES_TABLE).then(($table) => {
cy.wrap($table.find(RULES_ROW).length).should('eql', 1);
});
cy.get(RULE_NAME).invoke('text').should('eql', newThresholdRule.name);
cy.get(RISK_SCORE).invoke('text').should('eql', newThresholdRule.riskScore);
cy.get(SEVERITY).invoke('text').should('eql', newThresholdRule.severity);
cy.get('[data-test-subj="rule-switch"]').should('have.attr', 'aria-checked', 'true');

goToRuleDetails();

let expectedUrls = '';
newThresholdRule.referenceUrls.forEach((url) => {
expectedUrls = expectedUrls + url;
});
let expectedFalsePositives = '';
newThresholdRule.falsePositivesExamples.forEach((falsePositive) => {
expectedFalsePositives = expectedFalsePositives + falsePositive;
});
let expectedTags = '';
newThresholdRule.tags.forEach((tag) => {
expectedTags = expectedTags + tag;
});
let expectedMitre = '';
newThresholdRule.mitre.forEach((mitre) => {
expectedMitre = expectedMitre + mitre.tactic;
mitre.techniques.forEach((technique) => {
expectedMitre = expectedMitre + technique;
});
});
const expectedIndexPatterns = [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
];

cy.get(RULE_NAME_HEADER).invoke('text').should('eql', `${newThresholdRule.name} Beta`);

cy.get(ABOUT_RULE_DESCRIPTION).invoke('text').should('eql', newThresholdRule.description);
cy.get(ABOUT_STEP).eq(ABOUT_SEVERITY).invoke('text').should('eql', newThresholdRule.severity);
cy.get(ABOUT_STEP).eq(ABOUT_RISK).invoke('text').should('eql', newThresholdRule.riskScore);
cy.get(ABOUT_STEP).eq(ABOUT_URLS).invoke('text').should('eql', expectedUrls);
cy.get(ABOUT_STEP)
.eq(ABOUT_FALSE_POSITIVES)
.invoke('text')
.should('eql', expectedFalsePositives);
cy.get(ABOUT_STEP).eq(ABOUT_MITRE).invoke('text').should('eql', expectedMitre);
cy.get(ABOUT_STEP).eq(ABOUT_TAGS).invoke('text').should('eql', expectedTags);

cy.get(RULE_ABOUT_DETAILS_HEADER_TOGGLE).eq(INVESTIGATION_NOTES_TOGGLE).click({ force: true });
cy.get(ABOUT_INVESTIGATION_NOTES).invoke('text').should('eql', INVESTIGATION_NOTES_MARKDOWN);

cy.get(DEFINITION_INDEX_PATTERNS).then((patterns) => {
cy.wrap(patterns).each((pattern, index) => {
cy.wrap(pattern).invoke('text').should('eql', expectedIndexPatterns[index]);
});
});
cy.get(DEFINITION_STEP)
.eq(DEFINITION_CUSTOM_QUERY)
.invoke('text')
.should('eql', `${newThresholdRule.customQuery} `);
cy.get(DEFINITION_STEP).eq(DEFINITION_TIMELINE).invoke('text').should('eql', 'None');
cy.get(DEFINITION_STEP)
.eq(DEFINITION_THRESHOLD)
.invoke('text')
.should(
'eql',
`Results aggregated by ${newThresholdRule.thresholdField} >= ${newThresholdRule.threshold}`
);

cy.get(SCHEDULE_STEP).eq(SCHEDULE_RUNS).invoke('text').should('eql', '5m');
cy.get(SCHEDULE_STEP).eq(SCHEDULE_LOOPBACK).invoke('text').should('eql', '1m');
});
});
21 changes: 21 additions & 0 deletions x-pack/plugins/security_solution/cypress/objects/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ export interface CustomRule {
timelineId: string;
}

export interface ThresholdRule extends CustomRule {
thresholdField: string;
threshold: string;
}

export interface MachineLearningRule {
machineLearningJob: string;
anomalyScoreThreshold: string;
Expand Down Expand Up @@ -72,6 +77,22 @@ export const newRule: CustomRule = {
timelineId: '0162c130-78be-11ea-9718-118a926974a4',
};

export const newThresholdRule: ThresholdRule = {
customQuery: 'host.name:*',
name: 'New Rule Test',
description: 'The new rule description.',
severity: 'High',
riskScore: '17',
tags: ['test', 'newRule'],
referenceUrls: ['https://www.google.com/', 'https://elastic.co/'],
falsePositivesExamples: ['False1', 'False2'],
mitre: [mitre1, mitre2],
note: '# test markdown',
timelineId: '0162c130-78be-11ea-9718-118a926974a4',
thresholdField: 'host.name',
threshold: '10',
};

export const machineLearningRule: MachineLearningRule = {
machineLearningJob: 'linux_anomalous_network_service',
anomalyScoreThreshold: '20',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export const DEFINE_CONTINUE_BUTTON = '[data-test-subj="define-continue"]';
export const IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK =
'[data-test-subj="importQueryFromSavedTimeline"]';

export const INPUT = '[data-test-subj="input"]';

export const INVESTIGATION_NOTES_TEXTAREA =
'[data-test-subj="detectionEngineStepAboutRuleNote"] textarea';

Expand Down Expand Up @@ -64,3 +66,9 @@ export const SEVERITY_DROPDOWN =

export const TAGS_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleTags"] [data-test-subj="comboBoxSearchInput"]';

export const THRESHOLD_FIELD_SELECTION = '.euiFilterSelectItem';

export const THRESHOLD_INPUT_AREA = '[data-test-subj="thresholdInput"]';

export const THRESHOLD_TYPE = '[data-test-subj="thresholdRuleType"]';
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export const ANOMALY_SCORE = 1;

export const DEFINITION_CUSTOM_QUERY = 1;

export const DEFINITION_THRESHOLD = 4;

export const DEFINITION_TIMELINE = 3;

export const DEFINITION_INDEX_PATTERNS =
Expand Down
40 changes: 33 additions & 7 deletions x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
* 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, MachineLearningRule, machineLearningRule } from '../objects/rule';

import {
CustomRule,
MachineLearningRule,
machineLearningRule,
ThresholdRule,
} from '../objects/rule';
import {
ABOUT_CONTINUE_BTN,
ANOMALY_THRESHOLD_INPUT,
Expand All @@ -15,6 +21,7 @@ import {
DEFINE_CONTINUE_BUTTON,
FALSE_POSITIVES_INPUT,
IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK,
INPUT,
INVESTIGATION_NOTES_TEXTAREA,
MACHINE_LEARNING_DROPDOWN,
MACHINE_LEARNING_LIST,
Expand All @@ -30,6 +37,9 @@ import {
SCHEDULE_CONTINUE_BUTTON,
SEVERITY_DROPDOWN,
TAGS_INPUT,
THRESHOLD_FIELD_SELECTION,
THRESHOLD_INPUT_AREA,
THRESHOLD_TYPE,
} from '../screens/create_new_rule';
import { TIMELINE } from '../screens/timeline';

Expand All @@ -39,7 +49,9 @@ export const createAndActivateRule = () => {
cy.get(CREATE_AND_ACTIVATE_BTN).should('not.exist');
};

export const fillAboutRuleAndContinue = (rule: CustomRule | MachineLearningRule) => {
export const fillAboutRuleAndContinue = (
rule: CustomRule | MachineLearningRule | ThresholdRule
) => {
cy.get(RULE_NAME_INPUT).type(rule.name, { force: true });
cy.get(RULE_DESCRIPTION_INPUT).type(rule.description, { force: true });

Expand Down Expand Up @@ -80,18 +92,28 @@ export const fillAboutRuleAndContinue = (rule: CustomRule | MachineLearningRule)
cy.get(ABOUT_CONTINUE_BTN).should('exist').click({ force: true });
};

export const fillDefineCustomRuleAndContinue = (rule: CustomRule) => {
cy.get(CUSTOM_QUERY_INPUT).type(rule.customQuery);
export const fillDefineCustomRuleWithImportedQueryAndContinue = (rule: CustomRule) => {
cy.get(IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK).click();
cy.get(TIMELINE(rule.timelineId)).click();
cy.get(CUSTOM_QUERY_INPUT).invoke('text').should('eq', rule.customQuery);
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });

cy.get(CUSTOM_QUERY_INPUT).should('not.exist');
};

export const fillDefineCustomRuleWithImportedQueryAndContinue = (rule: CustomRule) => {
cy.get(IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK).click();
cy.get(TIMELINE(rule.timelineId)).click();
export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRule) => {
const thresholdField = 0;
const threshold = 1;

cy.get(CUSTOM_QUERY_INPUT).type(rule.customQuery);
cy.get(CUSTOM_QUERY_INPUT).invoke('text').should('eq', rule.customQuery);
cy.get(THRESHOLD_INPUT_AREA)
.find(INPUT)
.then((inputs) => {
cy.wrap(inputs[thresholdField]).type(rule.thresholdField);
cy.get(THRESHOLD_FIELD_SELECTION).click({ force: true });
cy.wrap(inputs[threshold]).clear().type(rule.threshold);
});
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });

cy.get(CUSTOM_QUERY_INPUT).should('not.exist');
Expand All @@ -111,3 +133,7 @@ export const fillDefineMachineLearningRuleAndContinue = (rule: MachineLearningRu
export const selectMachineLearningRuleType = () => {
cy.get(MACHINE_LEARNING_TYPE).click({ force: true });
};

export const selectThresholdRuleType = () => {
cy.get(THRESHOLD_TYPE).click({ force: true });
};

0 comments on commit 046a9bc

Please sign in to comment.