Skip to content

Commit

Permalink
[Security Solution] POC reusing types and avoiding data-driven (elast…
Browse files Browse the repository at this point in the history
…ic#143383)

Co-authored-by: Kibana Machine <[email protected]>
(cherry picked from commit 3d7f1fb)
  • Loading branch information
MadameSheema committed Nov 17, 2022
1 parent 095f596 commit dc350d4
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 58 deletions.
88 changes: 88 additions & 0 deletions x-pack/plugins/security_solution/cypress/data/detection_engine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* 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 {
RiskScore,
RuleInterval,
RuleIntervalFrom,
Severity,
Threat,
ThreatSubtechnique,
ThreatTechnique,
} from '@kbn/securitysolution-io-ts-alerting-types';

import type {
IndexPatternArray,
InvestigationGuide,
RuleDescription,
RuleFalsePositiveArray,
RuleQuery,
RuleName,
RuleReferenceArray,
RuleTagArray,
} from '../../common/detection_engine/rule_schema';

interface RuleFields {
defaultIndexPatterns: IndexPatternArray;
falsePositives: RuleFalsePositiveArray;
investigationGuide: InvestigationGuide;
referenceUrls: RuleReferenceArray;
riskScore: RiskScore;
ruleDescription: RuleDescription;
ruleInterval: RuleInterval;
ruleIntervalFrom: RuleIntervalFrom;
ruleQuery: RuleQuery;
ruleName: RuleName;
ruleTags: RuleTagArray;
ruleSeverity: Severity;
threat: Threat;
threatSubtechnique: ThreatSubtechnique;
threatTechnique: ThreatTechnique;
}

export const ruleFields: RuleFields = {
defaultIndexPatterns: [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'logs-*',
'packetbeat-*',
'traces-apm*',
'winlogbeat-*',
'-*elastic-cloud-logs-*',
],
falsePositives: ['False1', 'False2'],
investigationGuide: '# test markdown',
referenceUrls: ['http://example.com/', 'https://example.com/'],
riskScore: 17,
ruleDescription: 'The rule description',
ruleInterval: '5m',
ruleIntervalFrom: '50000h',
ruleQuery: 'host.name: *',
ruleName: 'Test Rule',
ruleTags: ['test', 'newRule'],
ruleSeverity: 'high',
threat: {
framework: 'MITRE ATT&CK',
tactic: {
name: 'Credential Access',
id: 'TA0006',
reference: 'https://attack.mitre.org/tactics/TA0006',
},
},
threatSubtechnique: {
name: '/etc/passwd and /etc/shadow',
id: 'T1003.008',
reference: 'https://attack.mitre.org/techniques/T1003/008',
},
threatTechnique: {
id: 'T1003',
name: 'OS Credential Dumping',
reference: 'https://attack.mitre.org/techniques/T1003',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
* 2.0.
*/

import { formatMitreAttackDescription } from '../../helpers/rules';
import type { Mitre } from '../../objects/rule';
import { ruleFields } from '../../data/detection_engine';
import {
getNewRule,
getExistingRule,
getIndexPatterns,
getEditedRule,
getNewOverrideRule,
} from '../../objects/rule';
import type { CompleteTimeline } from '../../objects/timeline';
import { getTimeline } from '../../objects/timeline';
import { ALERT_GRID_CELL, NUMBER_OF_ALERTS } from '../../screens/alerts';

import {
Expand Down Expand Up @@ -56,7 +55,6 @@ import {
INDEX_PATTERNS_DETAILS,
INVESTIGATION_NOTES_MARKDOWN,
INVESTIGATION_NOTES_TOGGLE,
MITRE_ATTACK_DETAILS,
REFERENCE_URLS_DETAILS,
RISK_SCORE_DETAILS,
RULE_NAME_HEADER,
Expand All @@ -66,6 +64,9 @@ import {
SEVERITY_DETAILS,
TAGS_DETAILS,
TIMELINE_TEMPLATE_DETAILS,
THREAT_TACTIC,
THREAT_TECHNIQUE,
THREAT_SUBTECHNIQUE,
} from '../../screens/rule_details';

import {
Expand All @@ -82,14 +83,26 @@ import { createTimeline } from '../../tasks/api_calls/timelines';
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
import { addEmailConnectorAndRuleAction } from '../../tasks/common/rule_actions';
import {
continueWithNextSection,
createAndEnableRule,
expandAdvancedSettings,
fillAboutRule,
fillAboutRuleAndContinue,
fillDefineCustomRuleAndContinue,
fillScheduleRuleAndContinue,
fillDescription,
fillFalsePositiveExamples,
fillFrom,
fillNote,
fillReferenceUrls,
fillRiskScore,
fillRuleName,
fillRuleTags,
fillSeverity,
fillThreat,
fillThreatSubtechnique,
fillThreatTechnique,
goToAboutStepTab,
goToActionsStepTab,
goToScheduleStepTab,
importSavedQuery,
waitForAlertsToPopulate,
waitForTheRuleToBeExecuted,
} from '../../tasks/create_new_rule';
Expand All @@ -105,98 +118,125 @@ describe('Custom query rules', () => {
login();
});
describe('Custom detection rules creation', () => {
const expectedUrls = getNewRule().referenceUrls?.join('');
const expectedFalsePositives = getNewRule().falsePositivesExamples?.join('');
const expectedTags = getNewRule().tags?.join('');
const mitreAttack = getNewRule().mitre as Mitre[];
const expectedMitre = formatMitreAttackDescription(mitreAttack);
const expectedNumberOfRules = 1;

beforeEach(() => {
const timeline = getNewRule().timeline as CompleteTimeline;
deleteAlertsAndRules();
createTimeline(timeline).then((response) => {
cy.wrap({
...getNewRule(),
timeline: {
...timeline,
id: response.body.data.persistTimeline.timeline.savedObjectId,
},
}).as('rule');
});
createTimeline(getTimeline())
.then((response) => {
return response.body.data.persistTimeline.timeline.savedObjectId;
})
.as('timelineId');
});

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

cy.log('Filling define section');
importSavedQuery(this.timelineId);
continueWithNextSection();

cy.log('Filling about section');
fillRuleName();
fillDescription();
fillSeverity();
fillRiskScore();
fillRuleTags();
expandAdvancedSettings();
fillReferenceUrls();
fillFalsePositiveExamples();
fillThreat();
fillThreatTechnique();
fillThreatSubtechnique();
fillNote();
continueWithNextSection();

cy.log('Filling schedule section');
fillFrom();

// expect define step to repopulate
cy.get(DEFINE_EDIT_BUTTON).click();
cy.get(CUSTOM_QUERY_INPUT).should('have.value', this.rule.customQuery);
cy.get(CUSTOM_QUERY_INPUT).should('have.value', ruleFields.ruleQuery);
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });
cy.get(DEFINE_CONTINUE_BUTTON).should('not.exist');

// expect about step to populate
cy.get(ABOUT_EDIT_BUTTON).click();
cy.get(RULE_NAME_INPUT).invoke('val').should('eql', this.rule.name);
cy.get(RULE_NAME_INPUT).invoke('val').should('eql', ruleFields.ruleName);
cy.get(ABOUT_CONTINUE_BTN).should('exist').click({ force: true });
cy.get(ABOUT_CONTINUE_BTN).should('not.exist');
cy.get(SCHEDULE_CONTINUE_BUTTON).click({ force: true });

createAndEnableRule();

cy.log('Asserting we have a new rule created');
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');

cy.log('Asserting rule view in rules list');
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_NAME).should('have.text', ruleFields.ruleName);
cy.get(RISK_SCORE).should('have.text', ruleFields.riskScore);
cy.get(SEVERITY)
.invoke('text')
.then((text) => {
cy.wrap(text.toLowerCase()).should('equal', ruleFields.ruleSeverity);
});
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.log('Asserting rule details');
cy.get(RULE_NAME_HEADER).should('contain', ruleFields.ruleName);
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', ruleFields.ruleDescription);
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(SEVERITY_DETAILS)
.invoke('text')
.then((text) => {
cy.wrap(text.toLowerCase()).should('equal', ruleFields.ruleSeverity);
});
getDetails(RISK_SCORE_DETAILS).should('have.text', ruleFields.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);
expect(removeExternalLinkText(details.text())).equal(ruleFields.referenceUrls.join(''));
});
getDetails(TAGS_DETAILS).should('have.text', expectedTags);
getDetails(FALSE_POSITIVES_DETAILS).should('have.text', ruleFields.falsePositives.join(''));
getDetails(TAGS_DETAILS).should('have.text', ruleFields.ruleTags.join(''));
});
cy.get(THREAT_TACTIC).should(
'contain',
`${ruleFields.threat.tactic.name} (${ruleFields.threat.tactic.id})`
);
cy.get(THREAT_TECHNIQUE).should(
'contain',
`${ruleFields.threatTechnique.name} (${ruleFields.threatTechnique.id})`
);
cy.get(THREAT_SUBTECHNIQUE).should(
'contain',
`${ruleFields.threatSubtechnique.name} (${ruleFields.threatSubtechnique.id})`
);
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', getIndexPatterns().join(''));
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery);
getDetails(INDEX_PATTERNS_DETAILS).should(
'have.text',
ruleFields.defaultIndexPatterns.join('')
);
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', ruleFields.ruleQuery);
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query');
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
});
cy.get(SCHEDULE_DETAILS).within(() => {
getDetails(RUNS_EVERY_DETAILS).should(
'have.text',
`${getNewRule().runsEvery?.interval}${getNewRule().runsEvery?.type}`
);
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
'have.text',
`${getNewRule().lookBack?.interval}${getNewRule().lookBack?.type}`
);
getDetails(RUNS_EVERY_DETAILS).should('have.text', ruleFields.ruleInterval);
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', ruleFields.ruleIntervalFrom);
});

waitForTheRuleToBeExecuted();
waitForAlertsToPopulate();

cy.log('Asserting that alerts have been generated after the creation');
cy.get(NUMBER_OF_ALERTS)
.invoke('text')
.should('match', /^[1-9].+$/); // Any number of alerts
cy.get(ALERT_GRID_CELL).contains(this.rule.name);
cy.get(ALERT_GRID_CELL).contains(ruleFields.ruleName);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export const DATA_VIEW_COMBO_BOX =

export const DATA_VIEW_OPTION = '[data-test-subj="rule-index-toggle-dataView"]';

export const CONTINUE_BUTTON = '[data-test-subj$=-continue]';

export const DEFINE_CONTINUE_BUTTON = '[data-test-subj="define-continue"]';

export const DEFINE_EDIT_BUTTON = '[data-test-subj="edit-define-rule"]';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,9 @@ export const DEFINE_RULE_PANEL_PROGRESS =
'[data-test-subj="defineRule"] [data-test-subj="stepPanelProgress"]';

export const EDIT_RULE_SETTINGS_LINK = '[data-test-subj="editRuleSettingsLink"]';

export const THREAT_TACTIC = '[data-test-subj="threatTacticLink"]';

export const THREAT_TECHNIQUE = '[data-test-subj="threatTechniqueLink"]';

export const THREAT_SUBTECHNIQUE = '[data-test-subj="threatSubtechniqueLink"]';
Loading

0 comments on commit dc350d4

Please sign in to comment.