Skip to content

Commit

Permalink
[Security Solution] Adds basic test for rule data view (#136822)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
MadameSheema and kibanamachine authored Jul 25, 2022
1 parent 711d337 commit 691e21e
Show file tree
Hide file tree
Showing 13 changed files with 386 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,6 @@ const DEFAULT_INDEX_PATTERNS = ['index-1-*', 'index-2-*'];
const TAGS = ['cypress-tag-1', 'cypress-tag-2'];
const OVERWRITE_INDEX_PATTERNS = ['overwrite-index-1-*', 'overwrite-index-2-*'];

const customRule = {
...getNewRule(),
index: DEFAULT_INDEX_PATTERNS,
name: RULE_NAME,
};

const expectedNumberOfCustomRulesToBeEdited = 6;
const expectedNumberOfMachineLearningRulesToBeEdited = 1;
const numberOfRulesPerPage = 5;
Expand All @@ -92,7 +86,14 @@ describe('Detection rules, bulk edit', () => {
beforeEach(() => {
deleteAlertsAndRules();
esArchiverResetKibana();
createCustomRule(customRule, '1');
createCustomRule(
{
...getNewRule(),
name: RULE_NAME,
dataSource: { index: DEFAULT_INDEX_PATTERNS, type: 'indexPatterns' },
},
'1'
);
createCustomRule(getExistingRule(), '2');
createCustomRule(getNewOverrideRule(), '3');
createCustomRule(getNewThresholdRule(), '4');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,13 @@ describe('Custom query rules', () => {
});

context('Edition', () => {
const expectedEditedtags = getEditedRule().tags.join('');
const rule = getEditedRule();
const expectedEditedtags = rule.tags.join('');
const expectedEditedIndexPatterns =
getEditedRule().index && getEditedRule().index.length
? getEditedRule().index
rule.dataSource.type === 'indexPatterns' &&
rule.dataSource.index &&
rule.dataSource.index.length
? rule.dataSource.index
: getIndexPatterns();

before(() => {
Expand All @@ -325,27 +328,32 @@ describe('Custom query rules', () => {
});

it('Allows a rule to be edited', () => {
const existingRule = getExistingRule();

editFirstRule();

// expect define step to populate
cy.get(CUSTOM_QUERY_INPUT).should('have.value', getExistingRule().customQuery);
if (getExistingRule().index && getExistingRule().index.length > 0) {
cy.get(DEFINE_INDEX_INPUT).should('have.text', getExistingRule().index.join(''));
cy.get(CUSTOM_QUERY_INPUT).should('have.value', existingRule.customQuery);
if (
existingRule.dataSource.type === 'indexPatterns' &&
existingRule.dataSource.index.length > 0
) {
cy.get(DEFINE_INDEX_INPUT).should('have.text', existingRule.dataSource.index.join(''));
}

goToAboutStepTab();

// expect about step to populate
cy.get(RULE_NAME_INPUT).invoke('val').should('eql', getExistingRule().name);
cy.get(RULE_DESCRIPTION_INPUT).should('have.text', getExistingRule().description);
cy.get(TAGS_FIELD).should('have.text', getExistingRule().tags.join(''));
cy.get(SEVERITY_DROPDOWN).should('have.text', getExistingRule().severity);
cy.get(DEFAULT_RISK_SCORE_INPUT).invoke('val').should('eql', getExistingRule().riskScore);
cy.get(RULE_NAME_INPUT).invoke('val').should('eql', existingRule.name);
cy.get(RULE_DESCRIPTION_INPUT).should('have.text', existingRule.description);
cy.get(TAGS_FIELD).should('have.text', existingRule.tags.join(''));
cy.get(SEVERITY_DROPDOWN).should('have.text', existingRule.severity);
cy.get(DEFAULT_RISK_SCORE_INPUT).invoke('val').should('eql', existingRule.riskScore);

goToScheduleStepTab();

// expect schedule step to populate
const interval = getExistingRule().interval;
const interval = existingRule.interval;
const intervalParts = interval != null && interval.match(/[0-9]+|[a-zA-Z]+/g);
if (intervalParts) {
const [amount, unit] = intervalParts;
Expand Down Expand Up @@ -381,7 +389,7 @@ describe('Custom query rules', () => {
cy.wait('@getRule').then(({ response }) => {
cy.wrap(response?.statusCode).should('eql', 200);
// ensure that editing rule does not modify max_signals
cy.wrap(response?.body.max_signals).should('eql', getExistingRule().maxSignals);
cy.wrap(response?.body.max_signals).should('eql', existingRule.maxSignals);
});

cy.get(RULE_NAME_HEADER).should('contain', `${getEditedRule().name}`);
Expand All @@ -396,7 +404,7 @@ describe('Custom query rules', () => {
cy.get(DEFINITION_DETAILS).within(() => {
getDetails(INDEX_PATTERNS_DETAILS).should(
'have.text',
expectedEditedIndexPatterns.join('')
expectedEditedIndexPatterns?.join('')
);
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', getEditedRule().customQuery);
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* 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 { formatMitreAttackDescription } from '../../helpers/rules';
import { getDataViewRule } from '../../objects/rule';
import { ALERT_GRID_CELL, 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 {
ADDITIONAL_LOOK_BACK_DETAILS,
ABOUT_DETAILS,
ABOUT_INVESTIGATION_NOTES,
ABOUT_RULE_DESCRIPTION,
CUSTOM_QUERY_DETAILS,
DEFINITION_DETAILS,
FALSE_POSITIVES_DETAILS,
removeExternalLinkText,
INDEX_PATTERNS_DETAILS,
INVESTIGATION_NOTES_MARKDOWN,
INVESTIGATION_NOTES_TOGGLE,
MITRE_ATTACK_DETAILS,
REFERENCE_URLS_DETAILS,
RISK_SCORE_DETAILS,
RULE_NAME_HEADER,
RULE_TYPE_DETAILS,
RUNS_EVERY_DETAILS,
SCHEDULE_DETAILS,
SEVERITY_DETAILS,
TAGS_DETAILS,
TIMELINE_TEMPLATE_DETAILS,
DATA_VIEW_DETAILS,
} from '../../screens/rule_details';

import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
import { createTimeline } from '../../tasks/api_calls/timelines';
import { postDataView } from '../../tasks/common';
import {
createAndEnableRule,
fillAboutRuleAndContinue,
fillDefineCustomRuleWithImportedQueryAndContinue,
fillScheduleRuleAndContinue,
waitForAlertsToPopulate,
waitForTheRuleToBeExecuted,
} from '../../tasks/create_new_rule';

import { esArchiverResetKibana } from '../../tasks/es_archiver';
import { login, visit } from '../../tasks/login';
import { getDetails } from '../../tasks/rule_details';

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

describe('Custom query rules', () => {
before(() => {
login();
});

describe('Custom detection rules creation with data views', () => {
const rule = getDataViewRule();
const expectedUrls = rule.referenceUrls.join('');
const expectedFalsePositives = rule.falsePositivesExamples.join('');
const expectedTags = rule.tags.join('');
const expectedMitre = formatMitreAttackDescription(rule.mitre);
const expectedNumberOfRules = 1;

beforeEach(() => {
/* We don't call cleanKibana method on the before hook, instead we call esArchiverReseKibana on the before each. This is because we
are creating a data view we'll use after and cleanKibana does not delete all the data views created, esArchiverReseKibana does.
We don't use esArchiverReseKibana in all the tests because is a time-consuming method and we don't need to perform an exhaustive
cleaning in all the other tests. */
esArchiverResetKibana();
createTimeline(rule.timeline).then((response) => {
cy.wrap({
...rule,
timeline: {
...rule.timeline,
id: response.body.data.persistTimeline.timeline.savedObjectId,
},
}).as('rule');
});
if (rule.dataSource.type === 'dataView') {
postDataView(rule.dataSource.dataView);
}
});

it('Creates and enables a new rule', function () {
visit(RULE_CREATION);
fillDefineCustomRuleWithImportedQueryAndContinue(this.rule);
fillAboutRuleAndContinue(this.rule);
fillScheduleRuleAndContinue(this.rule);
createAndEnableRule();

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

cy.get(RULES_TABLE).find(RULES_ROW).should('have.length', expectedNumberOfRules);
cy.get(RULE_NAME).should('have.text', this.rule.name);
cy.get(RISK_SCORE).should('have.text', this.rule.riskScore);
cy.get(SEVERITY).should('have.text', this.rule.severity);
cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');

goToRuleDetails();

cy.get(RULE_NAME_HEADER).should('contain', `${this.rule.name}`);
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', this.rule.description);
cy.get(ABOUT_DETAILS).within(() => {
getDetails(SEVERITY_DETAILS).should('have.text', this.rule.severity);
getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.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(DATA_VIEW_DETAILS).should('have.text', this.rule.dataSource.dataView);
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery);
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query');
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
});
cy.get(DEFINITION_DETAILS).should('not.contain', INDEX_PATTERNS_DETAILS);
cy.get(SCHEDULE_DETAILS).within(() => {
getDetails(RUNS_EVERY_DETAILS).should(
'have.text',
`${getDataViewRule().runsEvery.interval}${getDataViewRule().runsEvery.type}`
);
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
'have.text',
`${getDataViewRule().lookBack.interval}${getDataViewRule().lookBack.type}`
);
});

waitForTheRuleToBeExecuted();
waitForAlertsToPopulate();

cy.get(NUMBER_OF_ALERTS)
.invoke('text')
.should('match', /^[1-9].+$/);
cy.get(ALERT_GRID_CELL).contains(this.rule.name);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,12 @@ describe('indicator match', () => {

describe('Indicator mapping', () => {
beforeEach(() => {
const rule = getNewThreatIndicatorRule();
visitWithoutDateRange(RULE_CREATION);
selectIndicatorMatchType();
fillIndexAndIndicatorIndexPattern(
getNewThreatIndicatorRule().index,
getNewThreatIndicatorRule().indicatorIndexPattern
);
if (rule.dataSource.type === 'indexPatterns') {
fillIndexAndIndicatorIndexPattern(rule.dataSource.index, rule.indicatorIndexPattern);
}
});

it('Does NOT show invalidation text on initial page load', () => {
Expand Down Expand Up @@ -419,11 +419,12 @@ describe('indicator match', () => {
});

it('Creates and enables a new Indicator Match rule', () => {
const rule = getNewThreatIndicatorRule();
visitWithoutDateRange(RULE_CREATION);
selectIndicatorMatchType();
fillDefineIndicatorMatchRuleAndContinue(getNewThreatIndicatorRule());
fillAboutRuleAndContinue(getNewThreatIndicatorRule());
fillScheduleRuleAndContinue(getNewThreatIndicatorRule());
fillDefineIndicatorMatchRuleAndContinue(rule);
fillAboutRuleAndContinue(rule);
fillScheduleRuleAndContinue(rule);
createAndEnableRule();

cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
Expand All @@ -432,22 +433,19 @@ describe('indicator match', () => {
cy.wrap($table.find(RULES_ROW).length).should('eql', expectedNumberOfRules);
});

cy.get(RULE_NAME).should('have.text', getNewThreatIndicatorRule().name);
cy.get(RISK_SCORE).should('have.text', getNewThreatIndicatorRule().riskScore);
cy.get(SEVERITY).should('have.text', getNewThreatIndicatorRule().severity);
cy.get(RULE_NAME).should('have.text', rule.name);
cy.get(RISK_SCORE).should('have.text', rule.riskScore);
cy.get(SEVERITY).should('have.text', rule.severity);
cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');

goToRuleDetails();

cy.get(RULE_NAME_HEADER).should('contain', `${getNewThreatIndicatorRule().name}`);
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', getNewThreatIndicatorRule().description);
cy.get(RULE_NAME_HEADER).should('contain', `${rule.name}`);
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', rule.description);
cy.get(ABOUT_DETAILS).within(() => {
getDetails(SEVERITY_DETAILS).should('have.text', getNewThreatIndicatorRule().severity);
getDetails(RISK_SCORE_DETAILS).should('have.text', getNewThreatIndicatorRule().riskScore);
getDetails(INDICATOR_PREFIX_OVERRIDE).should(
'have.text',
getNewThreatIndicatorRule().threatIndicatorPath
);
getDetails(SEVERITY_DETAILS).should('have.text', rule.severity);
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.riskScore);
getDetails(INDICATOR_PREFIX_OVERRIDE).should('have.text', rule.threatIndicatorPath);
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
});
Expand All @@ -461,50 +459,41 @@ describe('indicator match', () => {
cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN);

cy.get(DEFINITION_DETAILS).within(() => {
getDetails(INDEX_PATTERNS_DETAILS).should(
'have.text',
getNewThreatIndicatorRule().index.join('')
);
if (rule.dataSource.type === 'indexPatterns') {
getDetails(INDEX_PATTERNS_DETAILS).should('have.text', rule.dataSource.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',
getNewThreatIndicatorRule().indicatorIndexPattern.join('')
rule.indicatorIndexPattern.join('')
);
getDetails(INDICATOR_MAPPING).should(
'have.text',
`${getNewThreatIndicatorRule().indicatorMappingField} MATCHES ${
getNewThreatIndicatorRule().indicatorIndexField
}`
`${rule.indicatorMappingField} MATCHES ${rule.indicatorIndexField}`
);
getDetails(INDICATOR_INDEX_QUERY).should('have.text', '*:*');
});

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

waitForTheRuleToBeExecuted();
waitForAlertsToPopulate();

cy.get(NUMBER_OF_ALERTS).should('have.text', expectedNumberOfAlerts);
cy.get(ALERT_RULE_NAME).first().should('have.text', getNewThreatIndicatorRule().name);
cy.get(ALERT_SEVERITY)
.first()
.should('have.text', getNewThreatIndicatorRule().severity.toLowerCase());
cy.get(ALERT_RISK_SCORE).first().should('have.text', getNewThreatIndicatorRule().riskScore);
cy.get(ALERT_RULE_NAME).first().should('have.text', rule.name);
cy.get(ALERT_SEVERITY).first().should('have.text', rule.severity.toLowerCase());
cy.get(ALERT_RISK_SCORE).first().should('have.text', rule.riskScore);
});

it('Investigate alert in timeline', () => {
Expand Down
Loading

0 comments on commit 691e21e

Please sign in to comment.