Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution][Detections] Implements indicator match rule cypress test #84323

Merged
merged 11 commits into from
Dec 3, 2020
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/*
* 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 { newThreatIndicatorRule } from '../objects/rule';

import {
ALERT_RULE_METHOD,
ALERT_RULE_NAME,
ALERT_RULE_RISK_SCORE,
ALERT_RULE_SEVERITY,
ALERT_RULE_VERSION,
NUMBER_OF_ALERTS,
} from '../screens/alerts';
import {
CUSTOM_RULES_BTN,
RISK_SCORE,
RULE_NAME,
RULES_ROW,
RULES_TABLE,
RULE_SWITCH,
SEVERITY,
} from '../screens/alerts_detection_rules';
import {
ABOUT_DETAILS,
ABOUT_INVESTIGATION_NOTES,
ABOUT_RULE_DESCRIPTION,
ADDITIONAL_LOOK_BACK_DETAILS,
CUSTOM_QUERY_DETAILS,
DEFINITION_DETAILS,
FALSE_POSITIVES_DETAILS,
getDetails,
INDEX_PATTERNS_DETAILS,
INDICATOR_INDEX_PATTERNS,
INDICATOR_INDEX_QUERY,
INDICATOR_MAPPING,
INVESTIGATION_NOTES_MARKDOWN,
INVESTIGATION_NOTES_TOGGLE,
MITRE_ATTACK_DETAILS,
REFERENCE_URLS_DETAILS,
removeExternalLinkText,
RISK_SCORE_DETAILS,
RULE_NAME_HEADER,
RULE_TYPE_DETAILS,
RUNS_EVERY_DETAILS,
SCHEDULE_DETAILS,
SEVERITY_DETAILS,
TAGS_DETAILS,
TIMELINE_TEMPLATE_DETAILS,
} from '../screens/rule_details';

import {
goToManageAlertsDetectionRules,
waitForAlertsIndexToBeCreated,
waitForAlertsPanelToBeLoaded,
} from '../tasks/alerts';
import {
changeToThreeHundredRowsPerPage,
deleteRule,
filterByCustomRules,
goToCreateNewRule,
goToRuleDetails,
waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded,
waitForRulesToBeLoaded,
} from '../tasks/alerts_detection_rules';
import {
createAndActivateRule,
fillAboutRuleAndContinue,
fillDefineIndicatorMatchRuleAndContinue,
fillScheduleRuleAndContinue,
selectIndicatorMatchType,
waitForAlertsToPopulate,
waitForTheRuleToBeExecuted,
} from '../tasks/create_new_rule';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';

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

const expectedUrls = newThreatIndicatorRule.referenceUrls.join('');
const expectedFalsePositives = newThreatIndicatorRule.falsePositivesExamples.join('');
const expectedTags = newThreatIndicatorRule.tags.join('');
const expectedMitre = newThreatIndicatorRule.mitre
.map(function (mitre) {
return mitre.tactic + mitre.techniques.join('');
})
.join('');
const expectedNumberOfRules = 1;
const expectedNumberOfAlerts = 1;

describe('Detection rules, Indicator Match', () => {
beforeEach(() => {
esArchiverLoad('threat_indicator');
esArchiverLoad('threat_data');
});

afterEach(() => {
esArchiverUnload('threat_indicator');
esArchiverUnload('threat_data');
deleteRule();
});

it('Creates and activates a new Indicator Match rule', () => {
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL);
waitForAlertsPanelToBeLoaded();
waitForAlertsIndexToBeCreated();
goToManageAlertsDetectionRules();
waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded();
goToCreateNewRule();
selectIndicatorMatchType();
fillDefineIndicatorMatchRuleAndContinue(newThreatIndicatorRule);
fillAboutRuleAndContinue(newThreatIndicatorRule);
fillScheduleRuleAndContinue(newThreatIndicatorRule);
createAndActivateRule();

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

changeToThreeHundredRowsPerPage();
waitForRulesToBeLoaded();

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).should('have.text', newThreatIndicatorRule.name);
cy.get(RISK_SCORE).should('have.text', newThreatIndicatorRule.riskScore);
cy.get(SEVERITY).should('have.text', newThreatIndicatorRule.severity);
cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');

goToRuleDetails();

cy.get(RULE_NAME_HEADER).should('have.text', `${newThreatIndicatorRule.name}`);
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', newThreatIndicatorRule.description);
cy.get(ABOUT_DETAILS).within(() => {
getDetails(SEVERITY_DETAILS).should('have.text', newThreatIndicatorRule.severity);
getDetails(RISK_SCORE_DETAILS).should('have.text', newThreatIndicatorRule.riskScore);
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
});
getDetails(FALSE_POSITIVES_DETAILS).should('have.text', expectedFalsePositives);
getDetails(MITRE_ATTACK_DETAILS).should((mitre) => {
expect(removeExternalLinkText(mitre.text())).equal(expectedMitre);
});
getDetails(TAGS_DETAILS).should('have.text', expectedTags);
});
cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true });
cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN);

cy.get(DEFINITION_DETAILS).within(() => {
getDetails(INDEX_PATTERNS_DETAILS).should('have.text', newThreatIndicatorRule.index.join(''));
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', '*:*');
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Indicator Match');
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
getDetails(INDICATOR_INDEX_PATTERNS).should(
'have.text',
newThreatIndicatorRule.indicatorIndexPattern.join('')
);
getDetails(INDICATOR_MAPPING).should(
'have.text',
`${newThreatIndicatorRule.indicatorMapping} MATCHES ${newThreatIndicatorRule.indicatorIndexField}`
);
getDetails(INDICATOR_INDEX_QUERY).should('have.text', '*:*');
});

cy.get(SCHEDULE_DETAILS).within(() => {
getDetails(RUNS_EVERY_DETAILS).should(
'have.text',
`${newThreatIndicatorRule.runsEvery.interval}${newThreatIndicatorRule.runsEvery.type}`
);
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
'have.text',
`${newThreatIndicatorRule.lookBack.interval}${newThreatIndicatorRule.lookBack.type}`
);
});

waitForTheRuleToBeExecuted();
waitForAlertsToPopulate();

cy.get(NUMBER_OF_ALERTS).should('have.text', expectedNumberOfAlerts);
cy.get(ALERT_RULE_NAME).first().should('have.text', newThreatIndicatorRule.name);
cy.get(ALERT_RULE_VERSION).first().should('have.text', '1');
cy.get(ALERT_RULE_METHOD).first().should('have.text', 'threat_match');
cy.get(ALERT_RULE_SEVERITY)
.first()
.should('have.text', newThreatIndicatorRule.severity.toLowerCase());
cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', newThreatIndicatorRule.riskScore);
});
});
53 changes: 41 additions & 12 deletions x-pack/plugins/security_solution/cypress/objects/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ interface Interval {
}

export interface CustomRule {
customQuery: string;
customQuery?: string;
name: string;
description: string;
index?: string[];
index: string[];
interval?: string;
severity: string;
riskScore: string;
Expand All @@ -43,7 +43,7 @@ export interface CustomRule {
falsePositivesExamples: string[];
mitre: Mitre[];
note: string;
timelineId: string;
timelineId?: string;
runsEvery: Interval;
lookBack: Interval;
}
Expand All @@ -60,6 +60,12 @@ export interface OverrideRule extends CustomRule {
timestampOverride: string;
}

export interface ThreatIndicatorRule extends CustomRule {
indicatorIndexPattern: string[];
indicatorMapping: string;
indicatorIndexField: string;
}

export interface MachineLearningRule {
machineLearningJob: string;
anomalyScoreThreshold: string;
Expand All @@ -77,6 +83,16 @@ export interface MachineLearningRule {
lookBack: Interval;
}

export const indexPatterns = [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
];

const mitre1: Mitre = {
tactic: 'Discovery (TA0007)',
techniques: ['Cloud Service Discovery (T1526)', 'File and Directory Discovery (T1083)'],
Expand Down Expand Up @@ -121,6 +137,7 @@ const lookBack: Interval = {

export const newRule: CustomRule = {
customQuery: 'host.name:*',
index: indexPatterns,
name: 'New Rule Test',
description: 'The new rule description.',
severity: 'High',
Expand Down Expand Up @@ -162,6 +179,7 @@ export const existingRule: CustomRule = {

export const newOverrideRule: OverrideRule = {
customQuery: 'host.name:*',
index: indexPatterns,
name: 'New Rule Test',
description: 'The new rule description.',
severity: 'High',
Expand All @@ -182,6 +200,7 @@ export const newOverrideRule: OverrideRule = {

export const newThresholdRule: ThresholdRule = {
customQuery: 'host.name:*',
index: indexPatterns,
name: 'New Rule Test',
description: 'The new rule description.',
severity: 'High',
Expand Down Expand Up @@ -217,6 +236,7 @@ export const machineLearningRule: MachineLearningRule = {
export const eqlRule: CustomRule = {
customQuery: 'any where process.name == "which"',
name: 'New EQL Rule',
index: indexPatterns,
description: 'New EQL rule description.',
severity: 'High',
riskScore: '17',
Expand All @@ -236,6 +256,7 @@ export const eqlSequenceRule: CustomRule = {
[any where process.name == "which"]\
[any where process.name == "xargs"]',
name: 'New EQL Sequence Rule',
index: indexPatterns,
description: 'New EQL rule description.',
severity: 'High',
riskScore: '17',
Expand All @@ -249,15 +270,23 @@ export const eqlSequenceRule: CustomRule = {
lookBack,
};

export const indexPatterns = [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'winlogbeat-*',
];
export const newThreatIndicatorRule: ThreatIndicatorRule = {
name: 'Threat Indicator Rule Test',
description: 'The threat indicator rule description.',
index: ['threat-data-*'],
severity: 'Critical',
riskScore: '20',
tags: ['test', 'threat'],
referenceUrls: ['https://www.google.com/', 'https://elastic.co/'],
falsePositivesExamples: ['False1', 'False2'],
mitre: [mitre1, mitre2],
note: '# test markdown',
runsEvery,
lookBack,
indicatorIndexPattern: ['threat-indicator-*'],
indicatorMapping: 'agent.id',
indicatorIndexField: 'agent.id',
};

export const severitiesOverride = ['Low', 'Medium', 'High', 'Critical'];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ export const MITRE_BTN = '[data-test-subj="addMitre"]';

export const ADVANCED_SETTINGS_BTN = '[data-test-subj="advancedSettings"] .euiAccordion__button';

export const COMBO_BOX_CLEAR_BTN = '[data-test-subj="comboBoxClearButton"]';

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

export const COMBO_BOX_RESULT = '.euiFilterSelectItem';

export const CREATE_AND_ACTIVATE_BTN = '[data-test-subj="create-activate"]';

export const CUSTOM_QUERY_INPUT =
Expand Down Expand Up @@ -57,6 +61,8 @@ export const EQL_QUERY_VALIDATION_SPINNER = '[data-test-subj="eql-validation-loa
export const IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK =
'[data-test-subj="importQueryFromSavedTimeline"]';

export const INDICATOR_MATCH_TYPE = '[data-test-subj="threatMatchRuleType"]';

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

export const INVESTIGATION_NOTES_TEXTAREA =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export const FALSE_POSITIVES_DETAILS = 'False positive examples';

export const INDEX_PATTERNS_DETAILS = 'Index patterns';

export const INDICATOR_INDEX_PATTERNS = 'Indicator index patterns';

export const INDICATOR_INDEX_QUERY = 'Indicator index query';

export const INDICATOR_MAPPING = 'Indicator mapping';

export const INVESTIGATION_NOTES_MARKDOWN = 'test markdown';

export const INVESTIGATION_NOTES_TOGGLE = '[data-test-subj="stepAboutDetailsToggle-notes"]';
Expand Down