mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.7] [Security Solution][Alerts] Removes custom cypress schemas in favor of io-ts schemas (#151520) (#152878)
# Backport This will backport the following commits from `main` to `8.7`: - [[Security Solution][Alerts] Removes custom cypress schemas in favor of io-ts schemas (#151520)](https://github.com/elastic/kibana/pull/151520) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Marshall Main","email":"55718608+marshallmain@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-03-08T06:36:20Z","message":"[Security Solution][Alerts] Removes custom cypress schemas in favor of io-ts schemas (#151520)\n\n## Summary\r\n\r\nThis PR removes the rule schemas that are specific to Cypress tests, and\r\nreplaces them with the HTTP API schemas from the Detection Engine API.\r\nAs a result, the rule schemas used in Cypress tests will now\r\nautomatically update when we add new fields to rules. In addition, we\r\ncan try to start removing some of mock rule data in Cypress tests and\r\nshare mocks across integration/e2e/unit tests.\r\n\r\nFinally, this PR removes the specific API call functions like\r\n`createCustomRule` and `createCustomRuleEnabled` in favor of a generic\r\n`createRule` function that can create any type of rule, without\r\nrestrictions on which fields can be specified (e.g.\r\n`createMachineLearningRule` hard coded `from: 'now-50000h',` in the\r\nfunction body).\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b20feb24fa264a5bed66ef614936a6abcfbfd5ba","branchLabelMapping":{"^v8.8.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team: SecuritySolution","Team:Detection Alerts","v8.7.0","v8.8.0"],"number":151520,"url":"https://github.com/elastic/kibana/pull/151520","mergeCommit":{"message":"[Security Solution][Alerts] Removes custom cypress schemas in favor of io-ts schemas (#151520)\n\n## Summary\r\n\r\nThis PR removes the rule schemas that are specific to Cypress tests, and\r\nreplaces them with the HTTP API schemas from the Detection Engine API.\r\nAs a result, the rule schemas used in Cypress tests will now\r\nautomatically update when we add new fields to rules. In addition, we\r\ncan try to start removing some of mock rule data in Cypress tests and\r\nshare mocks across integration/e2e/unit tests.\r\n\r\nFinally, this PR removes the specific API call functions like\r\n`createCustomRule` and `createCustomRuleEnabled` in favor of a generic\r\n`createRule` function that can create any type of rule, without\r\nrestrictions on which fields can be specified (e.g.\r\n`createMachineLearningRule` hard coded `from: 'now-50000h',` in the\r\nfunction body).\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b20feb24fa264a5bed66ef614936a6abcfbfd5ba"}},"sourceBranch":"main","suggestedTargetBranches":["8.7"],"targetPullRequestStates":[{"branch":"8.7","label":"v8.7.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.8.0","labelRegex":"^v8.8.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/151520","number":151520,"mergeCommit":{"message":"[Security Solution][Alerts] Removes custom cypress schemas in favor of io-ts schemas (#151520)\n\n## Summary\r\n\r\nThis PR removes the rule schemas that are specific to Cypress tests, and\r\nreplaces them with the HTTP API schemas from the Detection Engine API.\r\nAs a result, the rule schemas used in Cypress tests will now\r\nautomatically update when we add new fields to rules. In addition, we\r\ncan try to start removing some of mock rule data in Cypress tests and\r\nshare mocks across integration/e2e/unit tests.\r\n\r\nFinally, this PR removes the specific API call functions like\r\n`createCustomRule` and `createCustomRuleEnabled` in favor of a generic\r\n`createRule` function that can create any type of rule, without\r\nrestrictions on which fields can be specified (e.g.\r\n`createMachineLearningRule` hard coded `from: 'now-50000h',` in the\r\nfunction body).\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b20feb24fa264a5bed66ef614936a6abcfbfd5ba"}}]}] BACKPORT-->
This commit is contained in:
parent
58099ea904
commit
a472ed48f0
59 changed files with 1074 additions and 1485 deletions
|
@ -9,7 +9,7 @@ import { JSON_TEXT } from '../../screens/alerts_details';
|
|||
|
||||
import { expandFirstAlert, waitForAlertsPanelToBeLoaded } from '../../tasks/alerts';
|
||||
import { openJsonView } from '../../tasks/alerts_details';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { esArchiverCCSLoad } from '../../tasks/es_archiver';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
@ -23,7 +23,7 @@ describe('Alert details with unmapped fields', () => {
|
|||
login();
|
||||
cleanKibana();
|
||||
esArchiverCCSLoad('unmapped_fields');
|
||||
createCustomRuleEnabled(getUnmappedCCSRule());
|
||||
createRule(getUnmappedCCSRule());
|
||||
visitWithoutDateRange(ALERTS_URL);
|
||||
waitForAlertsPanelToBeLoaded();
|
||||
expandFirstAlert();
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
goToRuleDetails,
|
||||
waitForRulesTableToBeLoaded,
|
||||
} from '../../tasks/alerts_detection_rules';
|
||||
import { createEventCorrelationRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate, waitForTheRuleToBeExecuted } from '../../tasks/create_new_rule';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
@ -31,9 +31,9 @@ describe('Detection rules', function () {
|
|||
|
||||
it('EQL rule on remote indices generates alerts', function () {
|
||||
esArchiverCCSLoad('linux_process');
|
||||
this.rule = getCCSEqlRule();
|
||||
const rule = getCCSEqlRule();
|
||||
login();
|
||||
createEventCorrelationRule(this.rule);
|
||||
createRule(rule);
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
filterByCustomRules();
|
||||
|
@ -46,9 +46,9 @@ describe('Detection rules', function () {
|
|||
.invoke('text')
|
||||
.then((text) => {
|
||||
cy.log('ALERT_DATA_GRID', text);
|
||||
expect(text).contains(this.rule.name);
|
||||
expect(text).contains(this.rule.severity.toLowerCase());
|
||||
expect(text).contains(this.rule.riskScore);
|
||||
expect(text).contains(rule.name);
|
||||
expect(text).contains(rule.severity);
|
||||
expect(text).contains(rule.risk_score);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getNewRule } from '../../objects/rule';
|
|||
import { ROLES } from '../../../common/test';
|
||||
|
||||
import { expandFirstAlertActions } from '../../tasks/alerts';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login, visit, waitForPageWithoutDateRange } from '../../tasks/login';
|
||||
|
@ -28,7 +28,7 @@ describe('Alerts timeline', () => {
|
|||
// First we login as a privileged user to create alerts.
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
waitForInstallRiskScoreModule,
|
||||
} from '../../tasks/api_calls/risk_scores';
|
||||
import { findSavedObjects } from '../../tasks/api_calls/risk_scores/saved_objects';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
import { clickEnableRiskScore } from '../../tasks/risk_scores';
|
||||
|
@ -36,7 +36,7 @@ describe('Enable risk scores', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule(), 'rule1');
|
||||
createRule({ ...getNewRule(), rule_id: 'rule1' });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
HOSTS_TABLE_ALERT_CELL,
|
||||
} from '../../screens/entity_analytics';
|
||||
import { openRiskTableFilterAndSelectTheLowOption } from '../../tasks/host_risk';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { QUERY_TAB_BUTTON } from '../../screens/timeline';
|
||||
|
@ -143,7 +143,7 @@ describe('Entity Analytics Dashboard', () => {
|
|||
|
||||
describe('With alerts data', () => {
|
||||
before(() => {
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -203,7 +203,7 @@ describe('Entity Analytics Dashboard', () => {
|
|||
|
||||
describe('With alerts data', () => {
|
||||
before(() => {
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '../../screens/entity_analytics';
|
||||
import { deleteRiskScore, installLegacyRiskScoreModule } from '../../tasks/api_calls/risk_scores';
|
||||
import { findSavedObjects } from '../../tasks/api_calls/risk_scores/saved_objects';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
import {
|
||||
|
@ -39,7 +39,7 @@ describe('Upgrade risk scores', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule(), 'rule1');
|
||||
createRule({ ...getNewRule(), rule_id: 'rule1' });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -88,7 +88,7 @@ versions.forEach((version) =>
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule(), 'rule1');
|
||||
createRule({ ...getNewRule(), rule_id: 'rule1' });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { openTimelineFieldsBrowser, populateTimeline } from '../../tasks/timelin
|
|||
|
||||
import { HOSTS_URL, ALERTS_URL } from '../../urls/navigation';
|
||||
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { refreshPage } from '../../tasks/security_header';
|
||||
|
@ -27,7 +27,7 @@ describe('Create DataView runtime field', () => {
|
|||
it('adds field to alert table', () => {
|
||||
const fieldName = 'field.name.alert.page';
|
||||
visit(ALERTS_URL);
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
refreshPage();
|
||||
waitForAlertsToPopulate();
|
||||
openEventsViewerFieldsBrowser();
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
*/
|
||||
|
||||
import { expandFirstAlert, waitForAlertsPanelToBeLoaded } from '../../tasks/alerts';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import type { CustomRule } from '../../objects/rule';
|
||||
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
import {
|
||||
|
@ -24,12 +23,11 @@ import { OPEN_ALERT_DETAILS_PAGE } from '../../screens/alerts_details';
|
|||
|
||||
describe('Alert Details Page Navigation', () => {
|
||||
describe('navigating to alert details page', () => {
|
||||
let rule: CustomRule;
|
||||
const rule = getNewRule();
|
||||
before(() => {
|
||||
rule = getNewRule();
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(rule, 'rule1');
|
||||
createRule({ ...rule, rule_id: 'rule1' });
|
||||
});
|
||||
|
||||
describe('context menu', () => {
|
||||
|
|
|
@ -20,7 +20,7 @@ import { expandFirstAlert } from '../../tasks/alerts';
|
|||
import { verifyInsightCount } from '../../tasks/alerts_details';
|
||||
import { setStartDate } from '../../tasks/date_picker';
|
||||
import { closeTimeline } from '../../tasks/timeline';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
@ -33,7 +33,7 @@ describe('Alert Flyout', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule(), 'rule1');
|
||||
createRule({ ...getNewRule(), rule_id: 'rule1' });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
|
||||
import { expandFirstAlert } from '../../tasks/alerts';
|
||||
import { openJsonView, openTable } from '../../tasks/alerts_details';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
|
||||
|
@ -31,7 +31,7 @@ describe('Alert details with unmapped fields', () => {
|
|||
cleanKibana();
|
||||
esArchiverLoad('unmapped_fields');
|
||||
login();
|
||||
createCustomRuleEnabled(getUnmappedRule());
|
||||
createRule(getUnmappedRule());
|
||||
visitWithoutDateRange(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
expandFirstAlert();
|
||||
|
@ -65,7 +65,7 @@ describe('Alert details with unmapped fields', () => {
|
|||
};
|
||||
|
||||
openTable();
|
||||
cy.get(ALERT_FLYOUT).find(tablePageSelector(4)).click({ force: true });
|
||||
cy.get(ALERT_FLYOUT).find(tablePageSelector(6)).click({ force: true });
|
||||
cy.get(ALERT_FLYOUT)
|
||||
.find(TABLE_ROWS)
|
||||
.last()
|
||||
|
|
|
@ -12,7 +12,7 @@ import { PAGE_TITLE } from '../../screens/common/page';
|
|||
|
||||
import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../tasks/login';
|
||||
import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts';
|
||||
|
||||
const loadPageAsPlatformEngineerUser = (url: string) => {
|
||||
|
@ -73,7 +73,7 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr
|
|||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createCustomRule(getNewRule());
|
||||
createRule({ ...getNewRule(), rule_id: 'rule_testing' });
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
|
@ -123,7 +123,7 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr
|
|||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createCustomRule(getNewRule());
|
||||
createRule({ ...getNewRule(), rule_id: 'rule_testing' });
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
|
@ -173,7 +173,7 @@ describe('Detections > Need Admin Callouts indicating an admin is needed to migr
|
|||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createCustomRule(getNewRule());
|
||||
createRule({ ...getNewRule(), rule_id: 'rule_testing' });
|
||||
loadPageAsPlatformEngineerUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getBuildingBlockRule } from '../../objects/rule';
|
|||
import { OVERVIEW_ALERTS_HISTOGRAM } from '../../screens/overview';
|
||||
import { OVERVIEW } from '../../screens/security_header';
|
||||
import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate, waitForTheRuleToBeExecuted } from '../../tasks/create_new_rule';
|
||||
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
|
||||
|
@ -26,7 +26,7 @@ describe('Alerts generated by building block rules', () => {
|
|||
login();
|
||||
});
|
||||
beforeEach(() => {
|
||||
createCustomRuleEnabled(getBuildingBlockRule());
|
||||
createRule(getBuildingBlockRule());
|
||||
});
|
||||
after(() => {
|
||||
esArchiverUnload('auditbeat_big');
|
||||
|
|
|
@ -29,7 +29,7 @@ import {
|
|||
openFirstAlert,
|
||||
selectCountTable,
|
||||
} from '../../tasks/alerts';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
|
||||
|
@ -48,7 +48,7 @@ describe('Changing alert status', () => {
|
|||
});
|
||||
context('Opening alerts', () => {
|
||||
beforeEach(() => {
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
selectNumberOfAlerts(3);
|
||||
|
@ -114,13 +114,13 @@ describe('Changing alert status', () => {
|
|||
context('Marking alerts as acknowledged', () => {
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
selectCountTable();
|
||||
clearGroupByTopInput();
|
||||
});
|
||||
it('Mark one alert as acknowledged when more than one open alerts are selected', () => {
|
||||
it.skip('Mark one alert as acknowledged when more than one open alerts are selected', () => {
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
|
@ -154,7 +154,7 @@ describe('Changing alert status', () => {
|
|||
context('Closing alerts', () => {
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(getNewRule(), '1', 100);
|
||||
createRule({ ...getNewRule(), rule_id: '1', max_signals: 100 });
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
selectCountTable();
|
||||
|
@ -223,7 +223,7 @@ describe('Changing alert status', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('Closes one alert when more than one opened alerts are selected', () => {
|
||||
it.skip('Closes one alert when more than one opened alerts are selected', () => {
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
|
@ -306,13 +306,13 @@ describe('Changing alert status', () => {
|
|||
});
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
selectCountTable();
|
||||
clearGroupByTopInput();
|
||||
});
|
||||
it('Mark one alert as acknowledged when more than one open alerts are selected', () => {
|
||||
it.skip('Mark one alert as acknowledged when more than one open alerts are selected', () => {
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getNewThreatIndicatorRule } from '../../objects/rule';
|
||||
import { getNewThreatIndicatorRule, indicatorRuleMatchingDoc } from '../../objects/rule';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
@ -22,7 +22,7 @@ import {
|
|||
import { TIMELINE_FIELD } from '../../screens/rule_details';
|
||||
import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { expandFirstAlert, setEnrichmentDates, viewThreatIntelTab } from '../../tasks/alerts';
|
||||
import { createCustomIndicatorRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { openJsonView, openThreatIndicatorDetails } from '../../tasks/alerts_details';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
|
||||
|
@ -34,7 +34,7 @@ describe('CTI Enrichment', () => {
|
|||
esArchiverLoad('threat_indicator');
|
||||
esArchiverLoad('suspicious_source_event');
|
||||
login();
|
||||
createCustomIndicatorRule(getNewThreatIndicatorRule());
|
||||
createRule({ ...getNewThreatIndicatorRule(), rule_id: 'rule_testing', enabled: true });
|
||||
});
|
||||
|
||||
after(() => {
|
||||
|
@ -49,11 +49,12 @@ describe('CTI Enrichment', () => {
|
|||
|
||||
it('Displays enrichment matched.* fields on the timeline', () => {
|
||||
const expectedFields = {
|
||||
'threat.enrichments.matched.atomic': getNewThreatIndicatorRule().atomic,
|
||||
'threat.enrichments.matched.type': getNewThreatIndicatorRule().matchedType,
|
||||
'threat.enrichments.matched.field': getNewThreatIndicatorRule().indicatorMappingField,
|
||||
'threat.enrichments.matched.id': getNewThreatIndicatorRule().matchedId,
|
||||
'threat.enrichments.matched.index': getNewThreatIndicatorRule().matchedIndex,
|
||||
'threat.enrichments.matched.atomic': indicatorRuleMatchingDoc.atomic,
|
||||
'threat.enrichments.matched.type': indicatorRuleMatchingDoc.matchedType,
|
||||
'threat.enrichments.matched.field':
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
'threat.enrichments.matched.id': indicatorRuleMatchingDoc.matchedId,
|
||||
'threat.enrichments.matched.index': indicatorRuleMatchingDoc.matchedIndex,
|
||||
};
|
||||
const fields = Object.keys(expectedFields) as Array<keyof typeof expectedFields>;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
OPTION_LIST_VALUES,
|
||||
OPTION_SELECTABLE,
|
||||
} from '../../screens/common/filter_group';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
|
@ -60,7 +60,7 @@ describe.skip('Detections : Page Filters', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule(), 'custom_rule_filters');
|
||||
createRule({ ...getNewRule(), rule_id: 'custom_rule_filters' });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import { ENRICHED_DATA_ROW } from '../../screens/alerts_details';
|
||||
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
|
||||
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import {
|
||||
|
@ -45,7 +45,7 @@ describe('Enrichment', () => {
|
|||
beforeEach(() => {
|
||||
esArchiverLoad('risk_hosts');
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(getNewRule(), 'rule1');
|
||||
createRule({ ...getNewRule(), rule_id: 'rule1' });
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
investigateFirstAlertInTimeline,
|
||||
scrollAlertTableColumnIntoView,
|
||||
} from '../../tasks/alerts';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
|
@ -31,7 +31,7 @@ describe('Alerts timeline', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
});
|
||||
beforeEach(() => {
|
||||
visit(ALERTS_URL);
|
||||
|
|
|
@ -12,7 +12,7 @@ import { PAGE_TITLE } from '../../screens/common/page';
|
|||
|
||||
import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../tasks/login';
|
||||
import { goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createCustomRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { getCallOut, waitForCallOutToBeShown, dismissCallOut } from '../../tasks/common/callouts';
|
||||
|
||||
const loadPageAsReadOnlyUser = (url: string) => {
|
||||
|
@ -71,7 +71,7 @@ describe('Detections > Callouts', () => {
|
|||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createCustomRule(getNewRule());
|
||||
createRule(getNewRule());
|
||||
loadPageAsReadOnlyUser(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
|
@ -121,7 +121,7 @@ describe('Detections > Callouts', () => {
|
|||
|
||||
context('On Rule Details page', () => {
|
||||
beforeEach(() => {
|
||||
createCustomRule(getNewRule());
|
||||
createRule(getNewRule());
|
||||
loadPageAsPlatformEngineer(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForPageTitleToBeShown();
|
||||
goToRuleDetails();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { ANALYZER_NODE } from '../../screens/alerts';
|
||||
|
||||
import { openAnalyzerForFirstAlertInTimeline } from '../../tasks/alerts';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { setStartDate } from '../../tasks/date_picker';
|
||||
|
@ -21,7 +21,7 @@ describe('Analyze events view for alerts', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
});
|
||||
beforeEach(() => {
|
||||
visit(ALERTS_URL);
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
USER_TABLE_ROW_TOTAL_ALERTS,
|
||||
} from '../../screens/detection_response';
|
||||
import { QUERY_TAB_BUTTON } from '../../screens/timeline';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
import { closeTimeline } from '../../tasks/timeline';
|
||||
|
@ -25,7 +25,7 @@ describe.skip('Detection response view', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
visit(DETECTIONS_RESPONSE_URL);
|
||||
});
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
} from '../../screens/alerts_detection_rules';
|
||||
import { VALUE_LISTS_MODAL_ACTIVATOR } from '../../screens/lists';
|
||||
import { waitForRulesTableToBeLoaded } from '../../tasks/alerts_detection_rules';
|
||||
import { createCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { dismissCallOut, getCallOut, waitForCallOutToBeShown } from '../../tasks/common/callouts';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
@ -25,7 +25,7 @@ const MISSING_PRIVILEGES_CALLOUT = 'missing-user-privileges';
|
|||
describe('All rules - read only', () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
createCustomRule(getNewRule(), '1');
|
||||
createRule({ ...getNewRule(), rule_id: '1' });
|
||||
login(ROLES.reader);
|
||||
});
|
||||
|
||||
|
|
|
@ -76,14 +76,7 @@ import { hasIndexPatterns, getDetails } from '../../tasks/rule_details';
|
|||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
|
||||
import {
|
||||
createCustomRule,
|
||||
createMachineLearningRule,
|
||||
createCustomIndicatorRule,
|
||||
createEventCorrelationRule,
|
||||
createThresholdRule,
|
||||
createNewTermsRule,
|
||||
} from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { loadPrepackagedTimelineTemplates } from '../../tasks/api_calls/timelines';
|
||||
import { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../tasks/common';
|
||||
|
||||
|
@ -95,7 +88,6 @@ import {
|
|||
getMachineLearningRule,
|
||||
getNewTermsRule,
|
||||
} from '../../objects/rule';
|
||||
import { getIndicatorMatchTimelineTemplate } from '../../objects/timeline';
|
||||
|
||||
import { esArchiverResetKibana } from '../../tasks/es_archiver';
|
||||
import { getAvailablePrebuiltRulesCount } from '../../tasks/api_calls/prebuilt_rules';
|
||||
|
@ -109,7 +101,6 @@ const prePopulatedTags = ['test-default-tag-1', 'test-default-tag-2'];
|
|||
const expectedNumberOfCustomRulesToBeEdited = 6;
|
||||
const expectedNumberOfMachineLearningRulesToBeEdited = 1;
|
||||
|
||||
const timelineTemplate = getIndicatorMatchTimelineTemplate();
|
||||
/**
|
||||
* total number of custom rules that are not Machine learning
|
||||
*/
|
||||
|
@ -117,12 +108,11 @@ const expectedNumberOfNotMLRules =
|
|||
expectedNumberOfCustomRulesToBeEdited - expectedNumberOfMachineLearningRulesToBeEdited;
|
||||
const numberOfRulesPerPage = 5;
|
||||
|
||||
const indexDataSource = { index: prePopulatedIndexPatterns, type: 'indexPatterns' } as const;
|
||||
|
||||
const defaultRuleData = {
|
||||
dataSource: indexDataSource,
|
||||
index: prePopulatedIndexPatterns,
|
||||
tags: prePopulatedTags,
|
||||
timeline: timelineTemplate,
|
||||
timeline_title: 'Generic Threat Match Timeline',
|
||||
timeline_id: '495ad7a7-316e-4544-8a0f-9c098daee76e',
|
||||
};
|
||||
|
||||
describe('Detection rules, bulk edit', () => {
|
||||
|
@ -135,19 +125,17 @@ describe('Detection rules, bulk edit', () => {
|
|||
resetRulesTableState();
|
||||
deleteAlertsAndRules();
|
||||
esArchiverResetKibana();
|
||||
createCustomRule(
|
||||
{
|
||||
...getNewRule(),
|
||||
name: RULE_NAME,
|
||||
...defaultRuleData,
|
||||
},
|
||||
'1'
|
||||
);
|
||||
createEventCorrelationRule({ ...getEqlRule(), ...defaultRuleData }, '2');
|
||||
createMachineLearningRule({ ...getMachineLearningRule(), ...defaultRuleData });
|
||||
createCustomIndicatorRule({ ...getNewThreatIndicatorRule(), ...defaultRuleData }, '4');
|
||||
createThresholdRule({ ...getNewThresholdRule(), ...defaultRuleData }, '5');
|
||||
createNewTermsRule({ ...getNewTermsRule(), ...defaultRuleData }, '6');
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
name: RULE_NAME,
|
||||
...defaultRuleData,
|
||||
rule_id: '1',
|
||||
});
|
||||
createRule({ ...getEqlRule(), ...defaultRuleData, rule_id: '2' });
|
||||
createRule({ ...getMachineLearningRule(), tags: ['test-default-tag-1', 'test-default-tag-2'] });
|
||||
createRule({ ...getNewThreatIndicatorRule(), ...defaultRuleData, rule_id: '4' });
|
||||
createRule({ ...getNewThresholdRule(), ...defaultRuleData, rule_id: '5' });
|
||||
createRule({ ...getNewTermsRule(), ...defaultRuleData, rule_id: '6' });
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
|
|
|
@ -41,15 +41,7 @@ import { esArchiverResetKibana } from '../../tasks/es_archiver';
|
|||
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
|
||||
|
||||
import {
|
||||
createMachineLearningRule,
|
||||
createCustomIndicatorRule,
|
||||
createEventCorrelationRule,
|
||||
createThresholdRule,
|
||||
createNewTermsRule,
|
||||
createSavedQueryRule,
|
||||
createCustomRuleEnabled,
|
||||
} from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { createSlackConnector } from '../../tasks/api_calls/connectors';
|
||||
|
||||
import {
|
||||
|
@ -93,23 +85,21 @@ describe('Detection rules, bulk edit of rule actions', () => {
|
|||
},
|
||||
];
|
||||
|
||||
createCustomRuleEnabled(
|
||||
{
|
||||
...getNewRule(),
|
||||
name: ruleNameToAssert,
|
||||
},
|
||||
'1',
|
||||
500,
|
||||
actions
|
||||
);
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
name: ruleNameToAssert,
|
||||
rule_id: '1',
|
||||
max_signals: 500,
|
||||
actions,
|
||||
});
|
||||
});
|
||||
|
||||
createEventCorrelationRule(getEqlRule(), '2');
|
||||
createMachineLearningRule(getMachineLearningRule(), '3');
|
||||
createCustomIndicatorRule(getNewThreatIndicatorRule(), '4');
|
||||
createThresholdRule(getNewThresholdRule(), '5');
|
||||
createNewTermsRule(getNewTermsRule(), '6');
|
||||
createSavedQueryRule({ ...getNewRule(), savedId: 'mocked' }, '7');
|
||||
createRule({ ...getEqlRule(), rule_id: '2' });
|
||||
createRule({ ...getMachineLearningRule(), rule_id: '3' });
|
||||
createRule({ ...getNewThreatIndicatorRule(), rule_id: '4' });
|
||||
createRule({ ...getNewThresholdRule(), rule_id: '5' });
|
||||
createRule({ ...getNewTermsRule(), rule_id: '6' });
|
||||
createRule({ ...getNewRule(), saved_id: 'mocked', rule_id: '7' });
|
||||
|
||||
createSlackConnector();
|
||||
});
|
||||
|
|
|
@ -32,14 +32,7 @@ import { hasIndexPatterns, getDetails, assertDetailsNotExist } from '../../tasks
|
|||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
||||
import { SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
|
||||
import {
|
||||
createCustomRule,
|
||||
createCustomIndicatorRule,
|
||||
createEventCorrelationRule,
|
||||
createThresholdRule,
|
||||
createNewTermsRule,
|
||||
createSavedQueryRule,
|
||||
} from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules, postDataView } from '../../tasks/common';
|
||||
|
||||
import {
|
||||
|
@ -58,12 +51,6 @@ const expectedIndexPatterns = ['index-1-*', 'index-2-*'];
|
|||
|
||||
const expectedNumberOfCustomRulesToBeEdited = 6;
|
||||
|
||||
const dataViewDataSource = { dataView: DATA_VIEW_ID, type: 'dataView' } as const;
|
||||
|
||||
const dataViewRuleData = {
|
||||
dataSource: dataViewDataSource,
|
||||
};
|
||||
|
||||
describe('Bulk editing index patterns of rules with a data view only', () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
|
@ -75,12 +62,33 @@ describe('Bulk editing index patterns of rules with a data view only', () => {
|
|||
|
||||
postDataView(DATA_VIEW_ID);
|
||||
|
||||
createCustomRule({ ...getNewRule(), ...dataViewRuleData }, '1');
|
||||
createEventCorrelationRule({ ...getEqlRule(), ...dataViewRuleData }, '2');
|
||||
createCustomIndicatorRule({ ...getNewThreatIndicatorRule(), ...dataViewRuleData }, '3');
|
||||
createThresholdRule({ ...getNewThresholdRule(), ...dataViewRuleData }, '4');
|
||||
createNewTermsRule({ ...getNewTermsRule(), ...dataViewRuleData }, '5');
|
||||
createSavedQueryRule({ ...getNewRule(), ...dataViewRuleData, savedId: 'mocked' }, '6');
|
||||
createRule({ ...getNewRule(), index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '1' });
|
||||
createRule({ ...getEqlRule(), index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '2' });
|
||||
createRule({
|
||||
...getNewThreatIndicatorRule(),
|
||||
index: undefined,
|
||||
data_view_id: DATA_VIEW_ID,
|
||||
rule_id: '3',
|
||||
});
|
||||
createRule({
|
||||
...getNewThresholdRule(),
|
||||
index: undefined,
|
||||
data_view_id: DATA_VIEW_ID,
|
||||
rule_id: '4',
|
||||
});
|
||||
createRule({
|
||||
...getNewTermsRule(),
|
||||
index: undefined,
|
||||
data_view_id: DATA_VIEW_ID,
|
||||
rule_id: '5',
|
||||
});
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
index: undefined,
|
||||
data_view_id: DATA_VIEW_ID,
|
||||
saved_id: 'mocked',
|
||||
rule_id: '6',
|
||||
});
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
|
@ -197,17 +205,12 @@ describe('Bulk editing index patterns of rules with index patterns and rules wit
|
|||
|
||||
postDataView(DATA_VIEW_ID);
|
||||
|
||||
createCustomRule({ ...getNewRule(), ...dataViewRuleData }, '1');
|
||||
createCustomRule(
|
||||
{
|
||||
...getNewRule(),
|
||||
dataSource: {
|
||||
type: 'indexPatterns',
|
||||
index: ['test-index-1-*'],
|
||||
},
|
||||
},
|
||||
'2'
|
||||
);
|
||||
createRule({ ...getNewRule(), index: undefined, data_view_id: DATA_VIEW_ID, rule_id: '1' });
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
index: ['test-index-1-*'],
|
||||
rule_id: '2',
|
||||
});
|
||||
|
||||
visitWithoutDateRange(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
|
|
|
@ -6,13 +6,7 @@
|
|||
*/
|
||||
|
||||
import { ruleFields } from '../../data/detection_engine';
|
||||
import {
|
||||
getNewRule,
|
||||
getExistingRule,
|
||||
getIndexPatterns,
|
||||
getEditedRule,
|
||||
getNewOverrideRule,
|
||||
} from '../../objects/rule';
|
||||
import { getNewRule, getExistingRule, getEditedRule, getNewOverrideRule } from '../../objects/rule';
|
||||
import { getTimeline } from '../../objects/timeline';
|
||||
import { ALERT_GRID_CELL, NUMBER_OF_ALERTS } from '../../screens/alerts';
|
||||
|
||||
|
@ -77,7 +71,7 @@ import {
|
|||
goToRuleDetails,
|
||||
selectNumberOfRules,
|
||||
} from '../../tasks/alerts_detection_rules';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { cleanKibana, deleteAlertsAndRules, deleteConnectors } from '../../tasks/common';
|
||||
import { addEmailConnectorAndRuleAction } from '../../tasks/common/rule_actions';
|
||||
|
@ -240,9 +234,9 @@ describe('Custom query rules', () => {
|
|||
context('Deletion', () => {
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(getNewRule(), 'rule1');
|
||||
createCustomRuleEnabled(getNewOverrideRule(), 'rule2');
|
||||
createCustomRuleEnabled(getExistingRule(), 'rule3');
|
||||
createRule({ ...getNewRule(), rule_id: 'rule1', enabled: true, max_signals: 500 });
|
||||
createRule({ ...getNewOverrideRule(), rule_id: 'rule2', enabled: true, max_signals: 500 });
|
||||
createRule({ ...getExistingRule(), rule_id: 'rule3', enabled: true });
|
||||
visit(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
|
@ -347,17 +341,12 @@ describe('Custom query rules', () => {
|
|||
context('Edition', () => {
|
||||
const rule = getEditedRule();
|
||||
const expectedEditedtags = rule.tags?.join('');
|
||||
const expectedEditedIndexPatterns =
|
||||
rule.dataSource.type === 'indexPatterns' &&
|
||||
rule.dataSource.index &&
|
||||
rule.dataSource.index.length
|
||||
? rule.dataSource.index
|
||||
: getIndexPatterns();
|
||||
const expectedEditedIndexPatterns = rule.index;
|
||||
|
||||
before(() => {
|
||||
deleteAlertsAndRules();
|
||||
deleteConnectors();
|
||||
createCustomRuleEnabled(getExistingRule(), 'rule1');
|
||||
createRule({ ...getExistingRule(), rule_id: 'rule1', enabled: true });
|
||||
});
|
||||
beforeEach(() => {
|
||||
visit(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
|
@ -373,7 +362,7 @@ describe('Custom query rules', () => {
|
|||
cy.wait('@fetchRuleDetails').then(({ response }) => {
|
||||
cy.wrap(response?.statusCode).should('eql', 200);
|
||||
|
||||
cy.wrap(response?.body.max_signals).should('eql', getExistingRule().maxSignals);
|
||||
cy.wrap(response?.body.max_signals).should('eql', getExistingRule().max_signals);
|
||||
cy.wrap(response?.body.enabled).should('eql', false);
|
||||
});
|
||||
});
|
||||
|
@ -384,13 +373,9 @@ describe('Custom query rules', () => {
|
|||
editFirstRule();
|
||||
|
||||
// expect define step to populate
|
||||
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(''));
|
||||
}
|
||||
cy.get(CUSTOM_QUERY_INPUT).should('have.value', existingRule.query);
|
||||
|
||||
cy.get(DEFINE_INDEX_INPUT).should('have.text', existingRule.index?.join(''));
|
||||
|
||||
goToAboutStepTab();
|
||||
|
||||
|
@ -398,8 +383,8 @@ describe('Custom query rules', () => {
|
|||
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);
|
||||
cy.get(SEVERITY_DROPDOWN).should('have.text', 'High');
|
||||
cy.get(DEFAULT_RISK_SCORE_INPUT).invoke('val').should('eql', `${existingRule.risk_score}`);
|
||||
|
||||
goToScheduleStepTab();
|
||||
|
||||
|
@ -433,14 +418,14 @@ 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', existingRule.maxSignals);
|
||||
cy.wrap(response?.body.max_signals).should('eql', existingRule.max_signals);
|
||||
});
|
||||
|
||||
cy.get(RULE_NAME_HEADER).should('contain', `${getEditedRule().name}`);
|
||||
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', getEditedRule().description);
|
||||
cy.get(ABOUT_DETAILS).within(() => {
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', getEditedRule().severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', getEditedRule().riskScore);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'Medium');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', `${getEditedRule().risk_score}`);
|
||||
getDetails(TAGS_DETAILS).should('have.text', expectedEditedtags);
|
||||
});
|
||||
cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true });
|
||||
|
@ -450,7 +435,7 @@ describe('Custom query rules', () => {
|
|||
'have.text',
|
||||
expectedEditedIndexPatterns?.join('')
|
||||
);
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', getEditedRule().customQuery);
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', getEditedRule().query);
|
||||
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query');
|
||||
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
|
||||
});
|
||||
|
|
|
@ -5,10 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { formatMitreAttackDescription } from '../../helpers/rules';
|
||||
import type { Mitre } from '../../objects/rule';
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../helpers/rules';
|
||||
import { getDataViewRule } from '../../objects/rule';
|
||||
import type { CompleteTimeline } from '../../objects/timeline';
|
||||
import { ALERT_GRID_CELL, NUMBER_OF_ALERTS } from '../../screens/alerts';
|
||||
|
||||
import {
|
||||
|
@ -53,7 +51,6 @@ import {
|
|||
} 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,
|
||||
|
@ -78,11 +75,11 @@ describe('Custom query rules', () => {
|
|||
|
||||
describe('Custom detection rules creation with data views', () => {
|
||||
const rule = getDataViewRule();
|
||||
const expectedUrls = rule.referenceUrls?.join('');
|
||||
const expectedFalsePositives = rule.falsePositivesExamples?.join('');
|
||||
const expectedUrls = rule.references?.join('');
|
||||
const expectedFalsePositives = rule.false_positives?.join('');
|
||||
const expectedTags = rule.tags?.join('');
|
||||
const mitreAttack = rule.mitre as Mitre[];
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack);
|
||||
const mitreAttack = rule.threat;
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack ?? []);
|
||||
const expectedNumberOfRules = 1;
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -90,44 +87,34 @@ describe('Custom query rules', () => {
|
|||
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. */
|
||||
const timeline = rule.timeline as CompleteTimeline;
|
||||
esArchiverResetKibana();
|
||||
createTimeline(timeline).then((response) => {
|
||||
cy.wrap({
|
||||
...rule,
|
||||
timeline: {
|
||||
...timeline,
|
||||
id: response.body.data.persistTimeline.timeline.savedObjectId,
|
||||
},
|
||||
}).as('rule');
|
||||
});
|
||||
if (rule.dataSource.type === 'dataView') {
|
||||
postDataView(rule.dataSource.dataView);
|
||||
if (rule.data_view_id != null) {
|
||||
postDataView(rule.data_view_id);
|
||||
}
|
||||
});
|
||||
|
||||
it('Creates and enables a new rule', function () {
|
||||
visit(RULE_CREATION);
|
||||
fillDefineCustomRuleAndContinue(this.rule);
|
||||
fillAboutRuleAndContinue(this.rule);
|
||||
fillScheduleRuleAndContinue(this.rule);
|
||||
fillDefineCustomRuleAndContinue(rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
createAndEnableRule();
|
||||
|
||||
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
|
||||
|
||||
cy.get(RULES_MANAGEMENT_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', rule.name);
|
||||
cy.get(RISK_SCORE).should('have.text', rule.risk_score);
|
||||
cy.get(SEVERITY).should('have.text', 'High');
|
||||
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(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', this.rule.severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'High');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.risk_score);
|
||||
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
|
||||
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
|
||||
});
|
||||
|
@ -140,21 +127,19 @@ describe('Custom query rules', () => {
|
|||
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(DATA_VIEW_DETAILS).should('have.text', rule.data_view_id);
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.query);
|
||||
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}`
|
||||
getDetails(RUNS_EVERY_DETAILS).should('have.text', `${rule.interval}`);
|
||||
const humanizedDuration = getHumanizedDuration(
|
||||
rule.from ?? 'now-6m',
|
||||
rule.interval ?? '5m'
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', `${humanizedDuration}`);
|
||||
});
|
||||
|
||||
waitForTheRuleToBeExecuted();
|
||||
|
@ -163,19 +148,17 @@ describe('Custom query rules', () => {
|
|||
cy.get(NUMBER_OF_ALERTS)
|
||||
.invoke('text')
|
||||
.should('match', /^[1-9].+$/);
|
||||
cy.get(ALERT_GRID_CELL).contains(this.rule.name);
|
||||
cy.get(ALERT_GRID_CELL).contains(rule.name);
|
||||
});
|
||||
it('Creates and edits a new rule with a data view', function () {
|
||||
visit(RULE_CREATION);
|
||||
fillDefineCustomRuleAndContinue(this.rule);
|
||||
cy.get(RULE_NAME_INPUT).clear({ force: true }).type(this.rule.name, { force: true });
|
||||
cy.get(RULE_DESCRIPTION_INPUT)
|
||||
.clear({ force: true })
|
||||
.type(this.rule.description, { force: true });
|
||||
fillDefineCustomRuleAndContinue(rule);
|
||||
cy.get(RULE_NAME_INPUT).clear({ force: true }).type(rule.name, { force: true });
|
||||
cy.get(RULE_DESCRIPTION_INPUT).clear({ force: true }).type(rule.description, { force: true });
|
||||
|
||||
cy.get(ABOUT_CONTINUE_BTN).should('exist').click({ force: true });
|
||||
|
||||
fillScheduleRuleAndContinue(this.rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
createRuleWithoutEnabling();
|
||||
|
||||
goToRuleDetails();
|
||||
|
|
|
@ -24,7 +24,6 @@ import {
|
|||
} from '../../screens/rule_details';
|
||||
|
||||
import { goToRuleDetails, editFirstRule } from '../../tasks/alerts_detection_rules';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { createSavedQuery, deleteSavedQueries } from '../../tasks/api_calls/saved_queries';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import {
|
||||
|
@ -39,10 +38,9 @@ import {
|
|||
import { saveEditedRule } from '../../tasks/edit_rule';
|
||||
import { login, visit } from '../../tasks/login';
|
||||
import { getDetails } from '../../tasks/rule_details';
|
||||
import { createSavedQueryRule, createCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
|
||||
import { RULE_CREATION, SECURITY_DETECTIONS_RULES_URL } from '../../urls/navigation';
|
||||
import type { CompleteTimeline } from '../../objects/timeline';
|
||||
|
||||
const savedQueryName = 'custom saved query';
|
||||
const savedQueryQuery = 'process.name: test';
|
||||
|
@ -57,19 +55,10 @@ describe('Custom saved_query rules', () => {
|
|||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
deleteSavedQueries();
|
||||
const timeline = getNewRule().timeline as CompleteTimeline;
|
||||
createTimeline(timeline).then((response) => {
|
||||
cy.wrap({
|
||||
...getNewRule(),
|
||||
timeline: {
|
||||
...timeline,
|
||||
id: response.body.data.persistTimeline.timeline.savedObjectId,
|
||||
},
|
||||
}).as('rule');
|
||||
});
|
||||
});
|
||||
|
||||
it('Creates saved query rule', function () {
|
||||
const rule = getNewRule();
|
||||
createSavedQuery(savedQueryName, savedQueryQuery, savedQueryFilterKey);
|
||||
visit(RULE_CREATION);
|
||||
|
||||
|
@ -88,8 +77,8 @@ describe('Custom saved_query rules', () => {
|
|||
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });
|
||||
cy.get(DEFINE_CONTINUE_BUTTON).should('not.exist');
|
||||
|
||||
fillAboutRuleAndContinue(this.rule);
|
||||
fillScheduleRuleAndContinue(this.rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
cy.intercept('POST', '/api/detection_engine/rules').as('savedQueryRule');
|
||||
createAndEnableRule();
|
||||
|
||||
|
@ -100,7 +89,7 @@ describe('Custom saved_query rules', () => {
|
|||
|
||||
goToRuleDetails();
|
||||
|
||||
cy.get(RULE_NAME_HEADER).should('contain', `${this.rule.name}`);
|
||||
cy.get(RULE_NAME_HEADER).should('contain', `${rule.name}`);
|
||||
|
||||
cy.get(DEFINE_RULE_PANEL_PROGRESS).should('not.exist');
|
||||
|
||||
|
@ -112,7 +101,12 @@ describe('Custom saved_query rules', () => {
|
|||
context('Non existent saved query', () => {
|
||||
const FAILED_TO_LOAD_ERROR = 'Failed to load the saved query';
|
||||
beforeEach(() => {
|
||||
createSavedQueryRule({ ...getNewRule(), savedId: 'non-existent' });
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
type: 'saved_query',
|
||||
saved_id: 'non-existent',
|
||||
query: undefined,
|
||||
});
|
||||
cy.visit(SECURITY_DETECTIONS_RULES_URL);
|
||||
});
|
||||
it('Shows error toast on details page when saved query can not be loaded', function () {
|
||||
|
@ -131,7 +125,7 @@ describe('Custom saved_query rules', () => {
|
|||
context('Editing', () => {
|
||||
it('Allows to update query rule as saved_query rule type', () => {
|
||||
createSavedQuery(savedQueryName, savedQueryQuery);
|
||||
createCustomRule(getNewRule());
|
||||
createRule(getNewRule());
|
||||
|
||||
cy.visit(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
|
@ -158,7 +152,12 @@ describe('Custom saved_query rules', () => {
|
|||
const expectedCustomTestQuery = 'random test query';
|
||||
createSavedQuery(savedQueryName, savedQueryQuery).then((response) => {
|
||||
cy.log(JSON.stringify(response.body, null, 2));
|
||||
createSavedQueryRule({ ...getNewRule(), savedId: response.body.id });
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
type: 'saved_query',
|
||||
saved_id: response.body.id,
|
||||
query: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
cy.visit(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
@ -185,7 +184,12 @@ describe('Custom saved_query rules', () => {
|
|||
|
||||
it('Allows to update saved_query rule with non-existent query by adding custom query', () => {
|
||||
const expectedCustomTestQuery = 'random test query';
|
||||
createSavedQueryRule({ ...getNewRule(), savedId: 'non-existent' });
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
type: 'saved_query',
|
||||
saved_id: 'non-existent',
|
||||
query: undefined,
|
||||
});
|
||||
|
||||
cy.visit(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
|
@ -208,7 +212,12 @@ describe('Custom saved_query rules', () => {
|
|||
|
||||
it('Allows to update saved_query rule with non-existent query by selecting another saved query', () => {
|
||||
createSavedQuery(savedQueryName, savedQueryQuery);
|
||||
createSavedQueryRule({ ...getNewRule(), savedId: 'non-existent' });
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
type: 'saved_query',
|
||||
saved_id: 'non-existent',
|
||||
query: undefined,
|
||||
});
|
||||
|
||||
cy.visit(SECURITY_DETECTIONS_RULES_URL);
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { formatMitreAttackDescription } from '../../helpers/rules';
|
||||
import type { Mitre } from '../../objects/rule';
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../helpers/rules';
|
||||
import { getEqlRule, getEqlSequenceRule, getIndexPatterns } from '../../objects/rule';
|
||||
|
||||
import { ALERT_DATA_GRID, NUMBER_OF_ALERTS } from '../../screens/alerts';
|
||||
|
@ -48,7 +47,6 @@ import {
|
|||
goToRuleDetails,
|
||||
goToTheRuleDetailsOf,
|
||||
} from '../../tasks/alerts_detection_rules';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import {
|
||||
createAndEnableRule,
|
||||
|
@ -63,7 +61,6 @@ import { login, visit } from '../../tasks/login';
|
|||
|
||||
import { RULE_CREATION } from '../../urls/navigation';
|
||||
import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver';
|
||||
import type { CompleteTimeline } from '../../objects/timeline';
|
||||
|
||||
describe('EQL rules', () => {
|
||||
before(() => {
|
||||
|
@ -72,51 +69,39 @@ describe('EQL rules', () => {
|
|||
deleteAlertsAndRules();
|
||||
});
|
||||
describe('Detection rules, EQL', () => {
|
||||
const expectedUrls = getEqlRule().referenceUrls?.join('');
|
||||
const expectedFalsePositives = getEqlRule().falsePositivesExamples?.join('');
|
||||
const expectedTags = getEqlRule().tags?.join('');
|
||||
const mitreAttack = getEqlRule().mitre as Mitre[];
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack);
|
||||
const rule = getEqlRule();
|
||||
const expectedUrls = rule.references?.join('');
|
||||
const expectedFalsePositives = rule.false_positives?.join('');
|
||||
const expectedTags = rule.tags?.join('');
|
||||
const mitreAttack = rule.threat;
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack ?? []);
|
||||
const expectedNumberOfRules = 1;
|
||||
const expectedNumberOfAlerts = '2 alerts';
|
||||
|
||||
beforeEach(() => {
|
||||
const timeline = getEqlRule().timeline as CompleteTimeline;
|
||||
createTimeline(timeline).then((response) => {
|
||||
cy.wrap({
|
||||
...getEqlRule(),
|
||||
timeline: {
|
||||
...timeline,
|
||||
id: response.body.data.persistTimeline.timeline.savedObjectId,
|
||||
},
|
||||
}).as('rule');
|
||||
});
|
||||
});
|
||||
|
||||
it('Creates and enables a new EQL rule', function () {
|
||||
visit(RULE_CREATION);
|
||||
selectEqlRuleType();
|
||||
fillDefineEqlRuleAndContinue(this.rule);
|
||||
fillAboutRuleAndContinue(this.rule);
|
||||
fillScheduleRuleAndContinue(this.rule);
|
||||
fillDefineEqlRuleAndContinue(rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
createAndEnableRule();
|
||||
|
||||
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
|
||||
|
||||
expectNumberOfRules(RULES_MANAGEMENT_TABLE, 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', rule.name);
|
||||
cy.get(RISK_SCORE).should('have.text', rule.risk_score);
|
||||
cy.get(SEVERITY).should('have.text', 'High');
|
||||
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(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', this.rule.severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'High');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.risk_score);
|
||||
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
|
||||
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
|
||||
});
|
||||
|
@ -130,19 +115,17 @@ describe('EQL rules', () => {
|
|||
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(CUSTOM_QUERY_DETAILS).should('have.text', rule.query);
|
||||
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Event Correlation');
|
||||
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
|
||||
});
|
||||
cy.get(SCHEDULE_DETAILS).within(() => {
|
||||
getDetails(RUNS_EVERY_DETAILS).should(
|
||||
'have.text',
|
||||
`${this.rule.runsEvery.interval}${this.rule.runsEvery.type}`
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
|
||||
'have.text',
|
||||
`${this.rule.lookBack.interval}${this.rule.lookBack.type}`
|
||||
getDetails(RUNS_EVERY_DETAILS).should('have.text', `${rule.interval}`);
|
||||
const humanizedDuration = getHumanizedDuration(
|
||||
rule.from ?? 'now-6m',
|
||||
rule.interval ?? '5m'
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', `${humanizedDuration}`);
|
||||
});
|
||||
|
||||
waitForTheRuleToBeExecuted();
|
||||
|
@ -152,9 +135,9 @@ describe('EQL rules', () => {
|
|||
cy.get(ALERT_DATA_GRID)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
expect(text).contains(this.rule.name);
|
||||
expect(text).contains(this.rule.severity.toLowerCase());
|
||||
expect(text).contains(this.rule.riskScore);
|
||||
expect(text).contains(rule.name);
|
||||
expect(text).contains(rule.severity);
|
||||
expect(text).contains(rule.risk_score);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -162,21 +145,11 @@ describe('EQL rules', () => {
|
|||
describe('Detection rules, sequence EQL', () => {
|
||||
const expectedNumberOfSequenceAlerts = '2 alerts';
|
||||
|
||||
const rule = getEqlSequenceRule();
|
||||
|
||||
before(() => {
|
||||
esArchiverLoad('auditbeat_big');
|
||||
});
|
||||
beforeEach(() => {
|
||||
const timeline = getEqlSequenceRule().timeline as CompleteTimeline;
|
||||
createTimeline(timeline).then((response) => {
|
||||
cy.wrap({
|
||||
...getEqlSequenceRule(),
|
||||
timeline: {
|
||||
...timeline,
|
||||
id: response.body.data.persistTimeline.timeline.savedObjectId,
|
||||
},
|
||||
}).as('rule');
|
||||
});
|
||||
});
|
||||
after(() => {
|
||||
esArchiverUnload('auditbeat_big');
|
||||
});
|
||||
|
@ -184,11 +157,11 @@ describe('EQL rules', () => {
|
|||
it('Creates and enables a new EQL rule with a sequence', function () {
|
||||
visit(RULE_CREATION);
|
||||
selectEqlRuleType();
|
||||
fillDefineEqlRuleAndContinue(this.rule);
|
||||
fillAboutRuleAndContinue(this.rule);
|
||||
fillScheduleRuleAndContinue(this.rule);
|
||||
fillDefineEqlRuleAndContinue(rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
createAndEnableRule();
|
||||
goToTheRuleDetailsOf(this.rule.name);
|
||||
goToTheRuleDetailsOf(rule.name);
|
||||
waitForTheRuleToBeExecuted();
|
||||
waitForAlertsToPopulate();
|
||||
|
||||
|
@ -197,8 +170,8 @@ describe('EQL rules', () => {
|
|||
.invoke('text')
|
||||
.then((text) => {
|
||||
cy.log('ALERT_DATA_GRID', text);
|
||||
expect(text).contains(this.rule.name);
|
||||
expect(text).contains(this.rule.severity.toLowerCase());
|
||||
expect(text).contains(rule.name);
|
||||
expect(text).contains(rule.severity);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
} from '../../tasks/alerts_detection_rules';
|
||||
import { createExceptionList, deleteExceptionList } from '../../tasks/api_calls/exceptions';
|
||||
import { getExceptionList } from '../../objects/exception';
|
||||
import { createCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana, resetRulesTableState, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
||||
|
@ -45,7 +45,7 @@ describe('Export rules', () => {
|
|||
// Rules get exported via _bulk_action endpoint
|
||||
cy.intercept('POST', '/api/detection_engine/rules/_bulk_action').as('bulk_action');
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
createCustomRule(getNewRule()).as('ruleResponse');
|
||||
createRule(getNewRule()).as('ruleResponse');
|
||||
});
|
||||
|
||||
it('Exports a custom rule', function () {
|
||||
|
@ -104,21 +104,19 @@ describe('Export rules', () => {
|
|||
deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type);
|
||||
// create rule with exceptions
|
||||
createExceptionList(exceptionList, exceptionList.list_id).then((response) =>
|
||||
createCustomRule(
|
||||
{
|
||||
...getNewRule(),
|
||||
name: 'rule with exceptions',
|
||||
exceptionLists: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: exceptionList.list_id,
|
||||
type: exceptionList.type,
|
||||
namespace_type: exceptionList.namespace_type,
|
||||
},
|
||||
],
|
||||
},
|
||||
'2'
|
||||
)
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
name: 'rule with exceptions',
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: exceptionList.list_id,
|
||||
type: exceptionList.type,
|
||||
namespace_type: exceptionList.namespace_type,
|
||||
},
|
||||
],
|
||||
rule_id: '2',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { formatMitreAttackDescription } from '../../helpers/rules';
|
||||
import type { Mitre } from '../../objects/rule';
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../helpers/rules';
|
||||
import {
|
||||
getIndexPatterns,
|
||||
getNewThreatIndicatorRule,
|
||||
getThreatIndexPatterns,
|
||||
indicatorRuleMatchingDoc,
|
||||
} from '../../objects/rule';
|
||||
|
||||
import {
|
||||
|
@ -65,7 +65,7 @@ import {
|
|||
checkDuplicatedRule,
|
||||
expectNumberOfRules,
|
||||
} from '../../tasks/alerts_detection_rules';
|
||||
import { createCustomIndicatorRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { loadPrepackagedTimelineTemplates } from '../../tasks/api_calls/timelines';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import {
|
||||
|
@ -106,15 +106,16 @@ import { login, visit, visitWithoutDateRange } from '../../tasks/login';
|
|||
import { goBackToRulesTable, getDetails } from '../../tasks/rule_details';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL, RULE_CREATION } from '../../urls/navigation';
|
||||
|
||||
const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d/d"';
|
||||
|
||||
describe('indicator match', () => {
|
||||
describe('Detection rules, Indicator Match', () => {
|
||||
const expectedUrls = getNewThreatIndicatorRule().referenceUrls?.join('');
|
||||
const expectedFalsePositives = getNewThreatIndicatorRule().falsePositivesExamples?.join('');
|
||||
const expectedUrls = getNewThreatIndicatorRule().references?.join('');
|
||||
const expectedFalsePositives = getNewThreatIndicatorRule().false_positives?.join('');
|
||||
const expectedTags = getNewThreatIndicatorRule().tags?.join('');
|
||||
const mitreAttack = getNewThreatIndicatorRule().mitre as Mitre[];
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack);
|
||||
const mitreAttack = getNewThreatIndicatorRule().threat;
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack ?? []);
|
||||
const expectedNumberOfRules = 1;
|
||||
const expectedNumberOfAlerts = '1 alert';
|
||||
|
||||
|
@ -212,8 +213,8 @@ describe('indicator match', () => {
|
|||
const rule = getNewThreatIndicatorRule();
|
||||
visitWithoutDateRange(RULE_CREATION);
|
||||
selectIndicatorMatchType();
|
||||
if (rule.dataSource.type === 'indexPatterns') {
|
||||
fillIndexAndIndicatorIndexPattern(rule.dataSource.index, rule.indicatorIndexPattern);
|
||||
if (rule.index) {
|
||||
fillIndexAndIndicatorIndexPattern(rule.index, rule.threat_index);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -238,8 +239,8 @@ describe('indicator match', () => {
|
|||
|
||||
it('Does NOT show invalidation text when there is a valid "index field" and a valid "indicator index field"', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
});
|
||||
getDefineContinueButton().click();
|
||||
getIndicatorInvalidationText().should('not.exist');
|
||||
|
@ -248,7 +249,7 @@ describe('indicator match', () => {
|
|||
it('Shows invalidation text when there is an invalid "index field" and a valid "indicator index field"', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: 'non-existent-value',
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
validColumns: 'indicatorField',
|
||||
});
|
||||
getDefineContinueButton().click();
|
||||
|
@ -257,7 +258,7 @@ describe('indicator match', () => {
|
|||
|
||||
it('Shows invalidation text when there is a valid "index field" and an invalid "indicator index field"', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: 'non-existent-value',
|
||||
validColumns: 'indexField',
|
||||
});
|
||||
|
@ -267,21 +268,21 @@ describe('indicator match', () => {
|
|||
|
||||
it('Deletes the first row when you have two rows. Both rows valid rows of "index fields" and valid "indicator index fields". The second row should become the first row', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
});
|
||||
getIndicatorAndButton().click();
|
||||
fillIndicatorMatchRow({
|
||||
rowNumber: 2,
|
||||
indexField: 'agent.name',
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
validColumns: 'indicatorField',
|
||||
});
|
||||
getIndicatorDeleteButton().click();
|
||||
getIndicatorIndexComboField().should('have.text', 'agent.name');
|
||||
getIndicatorMappingComboField().should(
|
||||
'have.text',
|
||||
getNewThreatIndicatorRule().indicatorIndexField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].value
|
||||
);
|
||||
getIndicatorIndexComboField(2).should('not.exist');
|
||||
getIndicatorMappingComboField(2).should('not.exist');
|
||||
|
@ -289,14 +290,14 @@ describe('indicator match', () => {
|
|||
|
||||
it('Deletes the first row when you have two rows. Both rows have valid "index fields" and invalid "indicator index fields". The second row should become the first row', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: 'non-existent-value',
|
||||
validColumns: 'indexField',
|
||||
});
|
||||
getIndicatorAndButton().click();
|
||||
fillIndicatorMatchRow({
|
||||
rowNumber: 2,
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: 'second-non-existent-value',
|
||||
validColumns: 'indexField',
|
||||
});
|
||||
|
@ -309,14 +310,14 @@ describe('indicator match', () => {
|
|||
it('Deletes the first row when you have two rows. Both rows have valid "indicator index fields" and invalid "index fields". The second row should become the first row', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: 'non-existent-value',
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
validColumns: 'indicatorField',
|
||||
});
|
||||
getIndicatorAndButton().click();
|
||||
fillIndicatorMatchRow({
|
||||
rowNumber: 2,
|
||||
indexField: 'second-non-existent-value',
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
validColumns: 'indicatorField',
|
||||
});
|
||||
getIndicatorDeleteButton().click();
|
||||
|
@ -327,8 +328,8 @@ describe('indicator match', () => {
|
|||
|
||||
it('Deletes the first row of data but not the UI elements and the text defaults back to the placeholder of Search', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
});
|
||||
getIndicatorDeleteButton().click();
|
||||
getIndicatorIndexComboField().should('text', 'Search');
|
||||
|
@ -339,8 +340,8 @@ describe('indicator match', () => {
|
|||
|
||||
it('Deletes the second row when you have three rows. The first row is valid data, the second row is invalid data, and the third row is valid data. Third row should shift up correctly', () => {
|
||||
fillIndicatorMatchRow({
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
});
|
||||
getIndicatorAndButton().click();
|
||||
fillIndicatorMatchRow({
|
||||
|
@ -352,25 +353,25 @@ describe('indicator match', () => {
|
|||
getIndicatorAndButton().click();
|
||||
fillIndicatorMatchRow({
|
||||
rowNumber: 3,
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
});
|
||||
getIndicatorDeleteButton(2).click();
|
||||
getIndicatorIndexComboField(1).should(
|
||||
'text',
|
||||
getNewThreatIndicatorRule().indicatorMappingField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].field
|
||||
);
|
||||
getIndicatorMappingComboField(1).should(
|
||||
'text',
|
||||
getNewThreatIndicatorRule().indicatorIndexField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].value
|
||||
);
|
||||
getIndicatorIndexComboField(2).should(
|
||||
'text',
|
||||
getNewThreatIndicatorRule().indicatorMappingField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].field
|
||||
);
|
||||
getIndicatorMappingComboField(2).should(
|
||||
'text',
|
||||
getNewThreatIndicatorRule().indicatorIndexField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].value
|
||||
);
|
||||
getIndicatorIndexComboField(3).should('not.exist');
|
||||
getIndicatorMappingComboField(3).should('not.exist');
|
||||
|
@ -385,17 +386,17 @@ describe('indicator match', () => {
|
|||
getIndicatorOrButton().click();
|
||||
fillIndicatorMatchRow({
|
||||
rowNumber: 2,
|
||||
indexField: getNewThreatIndicatorRule().indicatorMappingField,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().indicatorIndexField,
|
||||
indexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value,
|
||||
});
|
||||
getIndicatorDeleteButton().click();
|
||||
getIndicatorIndexComboField().should(
|
||||
'text',
|
||||
getNewThreatIndicatorRule().indicatorMappingField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].field
|
||||
);
|
||||
getIndicatorMappingComboField().should(
|
||||
'text',
|
||||
getNewThreatIndicatorRule().indicatorIndexField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].value
|
||||
);
|
||||
getIndicatorIndexComboField(2).should('not.exist');
|
||||
getIndicatorMappingComboField(2).should('not.exist');
|
||||
|
@ -436,8 +437,8 @@ describe('indicator match', () => {
|
|||
expectNumberOfRules(RULES_MANAGEMENT_TABLE, expectedNumberOfRules);
|
||||
|
||||
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(RISK_SCORE).should('have.text', rule.risk_score);
|
||||
cy.get(SEVERITY).should('have.text', 'Critical');
|
||||
cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');
|
||||
|
||||
goToRuleDetails();
|
||||
|
@ -445,9 +446,9 @@ describe('indicator match', () => {
|
|||
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', rule.severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.riskScore);
|
||||
getDetails(INDICATOR_PREFIX_OVERRIDE).should('have.text', rule.threatIndicatorPath);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'Critical');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.risk_score);
|
||||
getDetails(INDICATOR_PREFIX_OVERRIDE).should('have.text', rule.threat_indicator_path);
|
||||
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
|
||||
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
|
||||
});
|
||||
|
@ -461,32 +462,27 @@ describe('indicator match', () => {
|
|||
cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN);
|
||||
|
||||
cy.get(DEFINITION_DETAILS).within(() => {
|
||||
if (rule.dataSource.type === 'indexPatterns') {
|
||||
getDetails(INDEX_PATTERNS_DETAILS).should('have.text', rule.dataSource.index?.join(''));
|
||||
if (rule.index) {
|
||||
getDetails(INDEX_PATTERNS_DETAILS).should('have.text', rule.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',
|
||||
rule.indicatorIndexPattern.join('')
|
||||
);
|
||||
getDetails(INDICATOR_INDEX_PATTERNS).should('have.text', rule.threat_index.join(''));
|
||||
getDetails(INDICATOR_MAPPING).should(
|
||||
'have.text',
|
||||
`${rule.indicatorMappingField} MATCHES ${rule.indicatorIndexField}`
|
||||
`${rule.threat_mapping[0].entries[0].field} MATCHES ${rule.threat_mapping[0].entries[0].value}`
|
||||
);
|
||||
getDetails(INDICATOR_INDEX_QUERY).should('have.text', '*:*');
|
||||
});
|
||||
|
||||
cy.get(SCHEDULE_DETAILS).within(() => {
|
||||
getDetails(RUNS_EVERY_DETAILS).should(
|
||||
'have.text',
|
||||
`${rule.runsEvery?.interval}${rule.runsEvery?.type}`
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
|
||||
'have.text',
|
||||
`${rule.lookBack?.interval}${rule.lookBack?.type}`
|
||||
getDetails(RUNS_EVERY_DETAILS).should('have.text', `${rule.interval}`);
|
||||
const humanizedDuration = getHumanizedDuration(
|
||||
rule.from ?? 'now-6m',
|
||||
rule.interval ?? '5m'
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', `${humanizedDuration}`);
|
||||
});
|
||||
|
||||
waitForTheRuleToBeExecuted();
|
||||
|
@ -495,14 +491,14 @@ describe('indicator match', () => {
|
|||
cy.get(NUMBER_OF_ALERTS).should('have.text', expectedNumberOfAlerts);
|
||||
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);
|
||||
cy.get(ALERT_RISK_SCORE).first().should('have.text', rule.risk_score);
|
||||
});
|
||||
|
||||
it('Investigate alert in timeline', () => {
|
||||
const accessibilityText = `Press enter for options, or press space to begin dragging.`;
|
||||
|
||||
loadPrepackagedTimelineTemplates();
|
||||
createCustomIndicatorRule(getNewThreatIndicatorRule());
|
||||
createRule({ ...getNewThreatIndicatorRule(), rule_id: 'rule_testing', enabled: true });
|
||||
visit(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForAlertsToPopulate();
|
||||
|
@ -512,18 +508,20 @@ describe('indicator match', () => {
|
|||
cy.get(PROVIDER_BADGE).should(
|
||||
'have.text',
|
||||
`threat.enrichments.matched.atomic: "${
|
||||
getNewThreatIndicatorRule().atomic
|
||||
indicatorRuleMatchingDoc.atomic
|
||||
}"threat.enrichments.matched.type: "indicator_match_rule"threat.enrichments.matched.field: "${
|
||||
getNewThreatIndicatorRule().indicatorMappingField
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].field
|
||||
}"`
|
||||
);
|
||||
|
||||
cy.get(INDICATOR_MATCH_ROW_RENDER).should(
|
||||
'have.text',
|
||||
`threat.enrichments.matched.field${
|
||||
getNewThreatIndicatorRule().indicatorMappingField
|
||||
}${accessibilityText}matched${getNewThreatIndicatorRule().indicatorMappingField}${
|
||||
getNewThreatIndicatorRule().atomic
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].field
|
||||
}${accessibilityText}matched${
|
||||
getNewThreatIndicatorRule().threat_mapping[0].entries[0].field
|
||||
}${
|
||||
indicatorRuleMatchingDoc.atomic
|
||||
}${accessibilityText}threat.enrichments.matched.typeindicator_match_rule${accessibilityText}provided` +
|
||||
` byfeed.nameAbuseCH malware${accessibilityText}`
|
||||
);
|
||||
|
@ -533,7 +531,7 @@ describe('indicator match', () => {
|
|||
describe('Duplicates the indicator rule', () => {
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomIndicatorRule(getNewThreatIndicatorRule());
|
||||
createRule({ ...getNewThreatIndicatorRule(), rule_id: 'rule_testing', enabled: true });
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { RULES_MONITORING_TAB, RULE_NAME } from '../../screens/alerts_detection_rules';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
|
||||
|
@ -19,7 +19,7 @@ describe('Rules talbes links', () => {
|
|||
});
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(getNewRule(), 'rule1');
|
||||
createRule({ ...getNewRule(), rule_id: 'rule1' });
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
});
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { formatMitreAttackDescription } from '../../helpers/rules';
|
||||
import { isArray } from 'lodash';
|
||||
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../helpers/rules';
|
||||
import { getMachineLearningRule } from '../../objects/rule';
|
||||
|
||||
import {
|
||||
|
@ -53,10 +55,10 @@ import { login, visitWithoutDateRange } from '../../tasks/login';
|
|||
import { RULE_CREATION } from '../../urls/navigation';
|
||||
|
||||
describe('Detection rules, machine learning', () => {
|
||||
const expectedUrls = getMachineLearningRule().referenceUrls.join('');
|
||||
const expectedFalsePositives = getMachineLearningRule().falsePositivesExamples.join('');
|
||||
const expectedTags = getMachineLearningRule().tags.join('');
|
||||
const expectedMitre = formatMitreAttackDescription(getMachineLearningRule().mitre);
|
||||
const expectedUrls = (getMachineLearningRule().references ?? []).join('');
|
||||
const expectedFalsePositives = (getMachineLearningRule().false_positives ?? []).join('');
|
||||
const expectedTags = (getMachineLearningRule().tags ?? []).join('');
|
||||
const expectedMitre = formatMitreAttackDescription(getMachineLearningRule().threat ?? []);
|
||||
const expectedNumberOfRules = 1;
|
||||
|
||||
before(() => {
|
||||
|
@ -66,28 +68,29 @@ describe('Detection rules, machine learning', () => {
|
|||
});
|
||||
|
||||
it('Creates and enables a new ml rule', () => {
|
||||
const mlRule = getMachineLearningRule();
|
||||
selectMachineLearningRuleType();
|
||||
fillDefineMachineLearningRuleAndContinue(getMachineLearningRule());
|
||||
fillAboutRuleAndContinue(getMachineLearningRule());
|
||||
fillScheduleRuleAndContinue(getMachineLearningRule());
|
||||
fillDefineMachineLearningRuleAndContinue(mlRule);
|
||||
fillAboutRuleAndContinue(mlRule);
|
||||
fillScheduleRuleAndContinue(mlRule);
|
||||
createAndEnableRule();
|
||||
|
||||
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
|
||||
|
||||
expectNumberOfRules(RULES_MANAGEMENT_TABLE, expectedNumberOfRules);
|
||||
|
||||
cy.get(RULE_NAME).should('have.text', getMachineLearningRule().name);
|
||||
cy.get(RISK_SCORE).should('have.text', getMachineLearningRule().riskScore);
|
||||
cy.get(SEVERITY).should('have.text', getMachineLearningRule().severity);
|
||||
cy.get(RULE_NAME).should('have.text', mlRule.name);
|
||||
cy.get(RISK_SCORE).should('have.text', mlRule.risk_score);
|
||||
cy.get(SEVERITY).should('have.text', 'Critical');
|
||||
cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');
|
||||
|
||||
goToRuleDetails();
|
||||
|
||||
cy.get(RULE_NAME_HEADER).should('contain', `${getMachineLearningRule().name}`);
|
||||
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', getMachineLearningRule().description);
|
||||
cy.get(RULE_NAME_HEADER).should('contain', `${mlRule.name}`);
|
||||
cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', mlRule.description);
|
||||
cy.get(ABOUT_DETAILS).within(() => {
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', getMachineLearningRule().severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', getMachineLearningRule().riskScore);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'Critical');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', mlRule.risk_score);
|
||||
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
|
||||
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
|
||||
});
|
||||
|
@ -98,31 +101,26 @@ describe('Detection rules, machine learning', () => {
|
|||
getDetails(TAGS_DETAILS).should('have.text', expectedTags);
|
||||
});
|
||||
cy.get(DEFINITION_DETAILS).within(() => {
|
||||
getDetails(ANOMALY_SCORE_DETAILS).should(
|
||||
'have.text',
|
||||
getMachineLearningRule().anomalyScoreThreshold
|
||||
);
|
||||
getDetails(ANOMALY_SCORE_DETAILS).should('have.text', mlRule.anomaly_threshold);
|
||||
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Machine Learning');
|
||||
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
|
||||
const machineLearningJobsArray = isArray(mlRule.machine_learning_job_id)
|
||||
? mlRule.machine_learning_job_id
|
||||
: [mlRule.machine_learning_job_id];
|
||||
// With the #1912 ML rule improvement changes we enable jobs on rule creation.
|
||||
// Though, in cypress jobs enabling does not work reliably and job can be started or stopped.
|
||||
// Thus, we disable next check till we fix the issue with enabling jobs in cypress.
|
||||
// Relevant ticket: https://github.com/elastic/security-team/issues/5389
|
||||
// cy.get(MACHINE_LEARNING_JOB_STATUS).should('have.text', 'StoppedStopped');
|
||||
cy.get(MACHINE_LEARNING_JOB_ID).should(
|
||||
'have.text',
|
||||
getMachineLearningRule().machineLearningJobs.join('')
|
||||
);
|
||||
cy.get(MACHINE_LEARNING_JOB_ID).should('have.text', machineLearningJobsArray.join(''));
|
||||
});
|
||||
cy.get(SCHEDULE_DETAILS).within(() => {
|
||||
getDetails(RUNS_EVERY_DETAILS).should(
|
||||
'have.text',
|
||||
`${getMachineLearningRule().runsEvery.interval}${getMachineLearningRule().runsEvery.type}`
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
|
||||
'have.text',
|
||||
`${getMachineLearningRule().lookBack.interval}${getMachineLearningRule().lookBack.type}`
|
||||
getDetails(RUNS_EVERY_DETAILS).should('have.text', `${mlRule.interval}`);
|
||||
const humanizedDuration = getHumanizedDuration(
|
||||
mlRule.from ?? 'now-6m',
|
||||
mlRule.interval ?? '5m'
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', `${humanizedDuration}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { formatMitreAttackDescription } from '../../helpers/rules';
|
||||
import type { Mitre } from '../../objects/rule';
|
||||
import { getNewTermsRule } from '../../objects/rule';
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../helpers/rules';
|
||||
import { getIndexPatterns, getNewTermsRule } from '../../objects/rule';
|
||||
|
||||
import { ALERT_DATA_GRID } from '../../screens/alerts';
|
||||
import {
|
||||
|
@ -46,7 +45,6 @@ import {
|
|||
|
||||
import { getDetails } from '../../tasks/rule_details';
|
||||
import { expectNumberOfRules, goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import {
|
||||
createAndEnableRule,
|
||||
|
@ -60,7 +58,6 @@ import {
|
|||
import { login, visit } from '../../tasks/login';
|
||||
|
||||
import { RULE_CREATION } from '../../urls/navigation';
|
||||
import type { CompleteTimeline } from '../../objects/timeline';
|
||||
|
||||
describe('New Terms rules', () => {
|
||||
before(() => {
|
||||
|
@ -68,51 +65,42 @@ describe('New Terms rules', () => {
|
|||
login();
|
||||
});
|
||||
describe('Detection rules, New Terms', () => {
|
||||
const expectedUrls = getNewTermsRule().referenceUrls?.join('');
|
||||
const expectedFalsePositives = getNewTermsRule().falsePositivesExamples?.join('');
|
||||
const expectedTags = getNewTermsRule().tags?.join('');
|
||||
const mitreAttack = getNewTermsRule().mitre as Mitre[];
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack);
|
||||
const rule = getNewTermsRule();
|
||||
const expectedUrls = rule.references?.join('');
|
||||
const expectedFalsePositives = rule.false_positives?.join('');
|
||||
const expectedTags = rule.tags?.join('');
|
||||
const mitreAttack = rule.threat;
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack ?? []);
|
||||
const expectedNumberOfRules = 1;
|
||||
|
||||
beforeEach(() => {
|
||||
const timeline = getNewTermsRule().timeline as CompleteTimeline;
|
||||
deleteAlertsAndRules();
|
||||
createTimeline(timeline).then((response) => {
|
||||
cy.wrap({
|
||||
...getNewTermsRule(),
|
||||
timeline: {
|
||||
...timeline,
|
||||
id: response.body.data.persistTimeline.timeline.savedObjectId,
|
||||
},
|
||||
}).as('rule');
|
||||
});
|
||||
});
|
||||
|
||||
it('Creates and enables a new terms rule', function () {
|
||||
visit(RULE_CREATION);
|
||||
selectNewTermsRuleType();
|
||||
fillDefineNewTermsRuleAndContinue(this.rule);
|
||||
fillAboutRuleAndContinue(this.rule);
|
||||
fillScheduleRuleAndContinue(this.rule);
|
||||
fillDefineNewTermsRuleAndContinue(rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
createAndEnableRule();
|
||||
|
||||
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
|
||||
|
||||
expectNumberOfRules(RULES_MANAGEMENT_TABLE, 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', rule.name);
|
||||
cy.get(RISK_SCORE).should('have.text', rule.risk_score);
|
||||
cy.get(SEVERITY).should('have.text', 'High');
|
||||
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(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', this.rule.severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'High');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.risk_score);
|
||||
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
|
||||
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
|
||||
});
|
||||
|
@ -125,22 +113,20 @@ describe('New Terms rules', () => {
|
|||
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', 'auditbeat-*');
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery);
|
||||
getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join(''));
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.query);
|
||||
getDetails(RULE_TYPE_DETAILS).should('have.text', 'New Terms');
|
||||
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
|
||||
getDetails(NEW_TERMS_FIELDS_DETAILS).should('have.text', 'host.name');
|
||||
getDetails(NEW_TERMS_HISTORY_WINDOW_DETAILS).should('have.text', '51000h');
|
||||
});
|
||||
cy.get(SCHEDULE_DETAILS).within(() => {
|
||||
getDetails(RUNS_EVERY_DETAILS).should(
|
||||
'have.text',
|
||||
`${this.rule.runsEvery.interval}${this.rule.runsEvery.type}`
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
|
||||
'have.text',
|
||||
`${this.rule.lookBack.interval}${this.rule.lookBack.type}`
|
||||
getDetails(RUNS_EVERY_DETAILS).should('have.text', `${rule.interval}`);
|
||||
const humanizedDuration = getHumanizedDuration(
|
||||
rule.from ?? 'now-6m',
|
||||
rule.interval ?? '5m'
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', `${humanizedDuration}`);
|
||||
});
|
||||
|
||||
waitForTheRuleToBeExecuted();
|
||||
|
@ -149,9 +135,9 @@ describe('New Terms rules', () => {
|
|||
cy.get(ALERT_DATA_GRID)
|
||||
.invoke('text')
|
||||
.then((text) => {
|
||||
expect(text).contains(this.rule.name);
|
||||
expect(text).contains(this.rule.severity.toLowerCase());
|
||||
expect(text).contains(this.rule.riskScore);
|
||||
expect(text).contains(rule.name);
|
||||
expect(text).contains(rule.severity);
|
||||
expect(text).contains(rule.risk_score);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,10 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { formatMitreAttackDescription } from '../../helpers/rules';
|
||||
import type { Mitre, OverrideRule } from '../../objects/rule';
|
||||
import { getNewOverrideRule, getSeveritiesOverride } from '../../objects/rule';
|
||||
import type { CompleteTimeline } from '../../objects/timeline';
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../helpers/rules';
|
||||
import { getIndexPatterns, getNewOverrideRule, getSeveritiesOverride } from '../../objects/rule';
|
||||
|
||||
import { NUMBER_OF_ALERTS, ALERT_GRID_CELL } from '../../screens/alerts';
|
||||
|
||||
|
@ -50,7 +48,6 @@ import {
|
|||
} from '../../screens/rule_details';
|
||||
|
||||
import { expectNumberOfRules, goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import {
|
||||
createAndEnableRule,
|
||||
|
@ -66,57 +63,46 @@ import { getDetails } from '../../tasks/rule_details';
|
|||
import { RULE_CREATION } from '../../urls/navigation';
|
||||
|
||||
describe('Detection rules, override', () => {
|
||||
const expectedUrls = getNewOverrideRule().referenceUrls?.join('');
|
||||
const expectedFalsePositives = getNewOverrideRule().falsePositivesExamples?.join('');
|
||||
const expectedTags = getNewOverrideRule().tags?.join('');
|
||||
const mitreAttack = getNewOverrideRule().mitre as Mitre[];
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack);
|
||||
const rule = getNewOverrideRule();
|
||||
const expectedUrls = rule.references?.join('');
|
||||
const expectedFalsePositives = rule.false_positives?.join('');
|
||||
const expectedTags = rule.tags?.join('');
|
||||
const mitreAttack = rule.threat;
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack ?? []);
|
||||
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
});
|
||||
beforeEach(() => {
|
||||
const timeline = getNewOverrideRule().timeline as CompleteTimeline;
|
||||
createTimeline(timeline).then((response) => {
|
||||
cy.wrap({
|
||||
...getNewOverrideRule(),
|
||||
timeline: {
|
||||
...timeline,
|
||||
id: response.body.data.persistTimeline.timeline.savedObjectId,
|
||||
},
|
||||
}).as('rule');
|
||||
});
|
||||
});
|
||||
|
||||
it('Creates and enables a new custom rule with override option', function () {
|
||||
visitWithoutDateRange(RULE_CREATION);
|
||||
fillDefineCustomRuleAndContinue(this.rule);
|
||||
fillAboutRuleWithOverrideAndContinue(this.rule);
|
||||
fillScheduleRuleAndContinue(this.rule);
|
||||
fillDefineCustomRuleAndContinue(rule);
|
||||
fillAboutRuleWithOverrideAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
createAndEnableRule();
|
||||
|
||||
cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)');
|
||||
|
||||
expectNumberOfRules(RULES_MANAGEMENT_TABLE, 1);
|
||||
|
||||
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', rule.name);
|
||||
cy.get(RISK_SCORE).should('have.text', rule.risk_score);
|
||||
cy.get(SEVERITY).should('have.text', 'High');
|
||||
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(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', this.rule.severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'High');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.risk_score);
|
||||
getDetails(RISK_SCORE_OVERRIDE_DETAILS).should(
|
||||
'have.text',
|
||||
`${this.rule.riskOverride}kibana.alert.risk_score`
|
||||
`${rule.risk_score_mapping?.[0].field}kibana.alert.risk_score`
|
||||
);
|
||||
getDetails(RULE_NAME_OVERRIDE_DETAILS).should('have.text', this.rule.nameOverride);
|
||||
getDetails(RULE_NAME_OVERRIDE_DETAILS).should('have.text', rule.rule_name_override);
|
||||
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
|
||||
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
|
||||
});
|
||||
|
@ -125,16 +111,16 @@ describe('Detection rules, override', () => {
|
|||
expect(removeExternalLinkText(mitre.text())).equal(expectedMitre);
|
||||
});
|
||||
getDetails(TAGS_DETAILS).should('have.text', expectedTags);
|
||||
getDetails(TIMESTAMP_OVERRIDE_DETAILS).should('have.text', this.rule.timestampOverride);
|
||||
getDetails(TIMESTAMP_OVERRIDE_DETAILS).should('have.text', rule.timestamp_override);
|
||||
cy.contains(DETAILS_TITLE, 'Severity override')
|
||||
.invoke('index', DETAILS_TITLE) // get index relative to other titles, not all siblings
|
||||
.then((severityOverrideIndex) => {
|
||||
(this.rule as OverrideRule).severityOverride.forEach((severity, i) => {
|
||||
rule.severity_mapping?.forEach((severity, i) => {
|
||||
cy.get(DETAILS_DESCRIPTION)
|
||||
.eq(severityOverrideIndex + i)
|
||||
.should(
|
||||
'have.text',
|
||||
`${severity.sourceField}:${severity.sourceValue}${getSeveritiesOverride()[i]}`
|
||||
`${severity.field}:${severity.value}${getSeveritiesOverride()[i]}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -142,20 +128,15 @@ describe('Detection rules, override', () => {
|
|||
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', 'auditbeat-*');
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery);
|
||||
getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join(''));
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.query);
|
||||
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',
|
||||
`${this.rule.runsEvery.interval}${this.rule.runsEvery.type}`
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
|
||||
'have.text',
|
||||
`${this.rule.lookBack.interval}${this.rule.lookBack.type}`
|
||||
);
|
||||
getDetails(RUNS_EVERY_DETAILS).should('have.text', `${rule.interval}`);
|
||||
const humanizedDuration = getHumanizedDuration(rule.from ?? 'now-6m', rule.interval ?? '5m');
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', `${humanizedDuration}`);
|
||||
});
|
||||
|
||||
waitForTheRuleToBeExecuted();
|
||||
|
|
|
@ -37,7 +37,7 @@ import {
|
|||
expectFilterByEnabledRules,
|
||||
} from '../../tasks/alerts_detection_rules';
|
||||
import { RULES_MANAGEMENT_TABLE } from '../../screens/alerts_detection_rules';
|
||||
import { createCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import {
|
||||
expectRowsPerPage,
|
||||
expectTablePage,
|
||||
|
@ -47,25 +47,27 @@ import {
|
|||
sortByTableColumn,
|
||||
} from '../../tasks/table_pagination';
|
||||
|
||||
function createRule(id: string, name: string, tags?: string[], enabled = false): void {
|
||||
const rule = getNewRule();
|
||||
|
||||
rule.name = name;
|
||||
rule.tags = tags;
|
||||
rule.enabled = enabled;
|
||||
|
||||
createCustomRule(rule, id);
|
||||
}
|
||||
|
||||
function createTestRules(): void {
|
||||
createRule('1', 'test 1', ['tag-a']);
|
||||
createRule('2', 'rule 1', ['tag-b']);
|
||||
createRule('3', 'rule 2', ['tag-b']);
|
||||
createRule('4', 'rule 3', ['tag-b', 'tag-c']);
|
||||
createRule('5', 'rule 4', ['tag-b']);
|
||||
createRule('6', 'rule 5', ['tag-b', 'tag-c']);
|
||||
createRule('7', 'rule 6', ['tag-b']);
|
||||
createRule('8', 'rule 7', ['tag-b'], true);
|
||||
createRule({ ...getNewRule(), rule_id: '1', name: 'test 1', tags: ['tag-a'], enabled: false });
|
||||
createRule({ ...getNewRule(), rule_id: '2', name: 'rule 1', tags: ['tag-b'], enabled: false });
|
||||
createRule({ ...getNewRule(), rule_id: '3', name: 'rule 2', tags: ['tag-b'], enabled: false });
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
rule_id: '4',
|
||||
name: 'rule 3',
|
||||
tags: ['tag-b', 'tag-c'],
|
||||
enabled: false,
|
||||
});
|
||||
createRule({ ...getNewRule(), rule_id: '5', name: 'rule 4', tags: ['tag-b'], enabled: false });
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
rule_id: '6',
|
||||
name: 'rule 5',
|
||||
tags: ['tag-b', 'tag-c'],
|
||||
enabled: false,
|
||||
});
|
||||
createRule({ ...getNewRule(), rule_id: '7', name: 'rule 6', tags: ['tag-b'], enabled: false });
|
||||
createRule({ ...getNewRule(), rule_id: '8', name: 'rule 7', tags: ['tag-b'], enabled: true });
|
||||
}
|
||||
|
||||
function visitRulesTableWithState(urlTableState: Record<string, unknown>): void {
|
||||
|
|
|
@ -42,20 +42,18 @@ describe('Rule actions during detection rule creation', () => {
|
|||
deleteDataView(indexConnector.index);
|
||||
});
|
||||
|
||||
const rule = {
|
||||
...getSimpleCustomQueryRule(),
|
||||
actions: { throttle: 'rule', connectors: [indexConnector] },
|
||||
};
|
||||
const index = rule.actions.connectors[0].index;
|
||||
const rule = getSimpleCustomQueryRule();
|
||||
const actions = { throttle: 'rule', connectors: [indexConnector] };
|
||||
const index = actions.connectors[0].index;
|
||||
const initialNumberOfDocuments = 0;
|
||||
const expectedJson = JSON.parse(rule.actions.connectors[0].document);
|
||||
const expectedJson = JSON.parse(actions.connectors[0].document);
|
||||
|
||||
it('Indexes a new document after the index action is triggered ', function () {
|
||||
visit(RULE_CREATION);
|
||||
fillDefineCustomRuleAndContinue(rule);
|
||||
fillAboutRuleAndContinue(rule);
|
||||
fillScheduleRuleAndContinue(rule);
|
||||
fillRuleAction(rule);
|
||||
fillRuleAction(actions);
|
||||
createAndEnableRule();
|
||||
goToRuleDetails();
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
import { login, visit, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
|
||||
import { createCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { setRowsPerPageTo } from '../../tasks/table_pagination';
|
||||
|
@ -38,7 +38,7 @@ describe('Alerts detection rules table auto-refresh', () => {
|
|||
cleanKibana();
|
||||
login();
|
||||
for (let i = 1; i < 7; i += 1) {
|
||||
createCustomRule({ ...getNewRule(), name: `Test rule ${i}` }, `${i}`);
|
||||
createRule({ ...getNewRule(), name: `Test rule ${i}`, rule_id: `${i}` });
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
import { login, visit } from '../../tasks/login';
|
||||
|
||||
import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../urls/navigation';
|
||||
import { createCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import {
|
||||
getExistingRule,
|
||||
|
@ -37,10 +37,10 @@ describe('Alerts detection rules', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRule(getNewRule(), '1');
|
||||
createCustomRule(getExistingRule(), '2');
|
||||
createCustomRule(getNewOverrideRule(), '3');
|
||||
createCustomRule(getNewThresholdRule(), '4');
|
||||
createRule({ ...getNewRule(), rule_id: '1' });
|
||||
createRule({ ...getExistingRule(), rule_id: '2' });
|
||||
createRule({ ...getNewOverrideRule(), rule_id: '3' });
|
||||
createRule({ ...getNewThresholdRule(), rule_id: '4' });
|
||||
});
|
||||
|
||||
it('Sorts by enabled rules', () => {
|
||||
|
@ -62,8 +62,8 @@ describe('Alerts detection rules', () => {
|
|||
});
|
||||
|
||||
it('Pagination updates page number and results', () => {
|
||||
createCustomRule({ ...getNewRule(), name: 'Test a rule' }, '5');
|
||||
createCustomRule({ ...getNewRule(), name: 'Not same as first rule' }, '6');
|
||||
createRule({ ...getNewRule(), name: 'Test a rule', rule_id: '5' });
|
||||
createRule({ ...getNewRule(), name: 'Not same as first rule', rule_id: '6' });
|
||||
|
||||
visit(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
waitForRulesTableToBeLoaded();
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { formatMitreAttackDescription } from '../../helpers/rules';
|
||||
import type { Mitre } from '../../objects/rule';
|
||||
import { getNewThresholdRule } from '../../objects/rule';
|
||||
import { formatMitreAttackDescription, getHumanizedDuration } from '../../helpers/rules';
|
||||
import { getIndexPatterns, getNewThresholdRule } from '../../objects/rule';
|
||||
|
||||
import { ALERT_GRID_CELL, NUMBER_OF_ALERTS } from '../../screens/alerts';
|
||||
|
||||
|
@ -46,7 +45,6 @@ import {
|
|||
|
||||
import { getDetails } from '../../tasks/rule_details';
|
||||
import { expectNumberOfRules, goToRuleDetails } from '../../tasks/alerts_detection_rules';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import {
|
||||
createAndEnableRule,
|
||||
|
@ -60,15 +58,14 @@ import {
|
|||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
||||
import { RULE_CREATION } from '../../urls/navigation';
|
||||
import type { CompleteTimeline } from '../../objects/timeline';
|
||||
|
||||
describe('Detection rules, threshold', () => {
|
||||
let rule = getNewThresholdRule();
|
||||
const expectedUrls = getNewThresholdRule().referenceUrls?.join('');
|
||||
const expectedFalsePositives = getNewThresholdRule().falsePositivesExamples?.join('');
|
||||
const expectedTags = getNewThresholdRule().tags?.join('');
|
||||
const mitreAttack = getNewThresholdRule().mitre as Mitre[];
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack);
|
||||
const rule = getNewThresholdRule();
|
||||
const expectedUrls = rule.references?.join('');
|
||||
const expectedFalsePositives = rule.false_positives?.join('');
|
||||
const expectedTags = rule.tags?.join('');
|
||||
const mitreAttack = rule.threat;
|
||||
const expectedMitre = formatMitreAttackDescription(mitreAttack ?? []);
|
||||
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
|
@ -76,12 +73,7 @@ describe('Detection rules, threshold', () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
rule = getNewThresholdRule();
|
||||
const timeline = rule.timeline as CompleteTimeline;
|
||||
deleteAlertsAndRules();
|
||||
createTimeline(timeline).then((response) => {
|
||||
timeline.id = response.body.data.persistTimeline.timeline.savedObjectId;
|
||||
});
|
||||
visitWithoutDateRange(RULE_CREATION);
|
||||
});
|
||||
|
||||
|
@ -97,8 +89,8 @@ describe('Detection rules, threshold', () => {
|
|||
expectNumberOfRules(RULES_MANAGEMENT_TABLE, 1);
|
||||
|
||||
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(RISK_SCORE).should('have.text', rule.risk_score);
|
||||
cy.get(SEVERITY).should('have.text', 'High');
|
||||
cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true');
|
||||
|
||||
goToRuleDetails();
|
||||
|
@ -106,8 +98,8 @@ describe('Detection rules, threshold', () => {
|
|||
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', rule.severity);
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.riskScore);
|
||||
getDetails(SEVERITY_DETAILS).should('have.text', 'High');
|
||||
getDetails(RISK_SCORE_DETAILS).should('have.text', rule.risk_score);
|
||||
getDetails(REFERENCE_URLS_DETAILS).should((details) => {
|
||||
expect(removeExternalLinkText(details.text())).equal(expectedUrls);
|
||||
});
|
||||
|
@ -120,24 +112,19 @@ describe('Detection rules, threshold', () => {
|
|||
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', 'auditbeat-*');
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.customQuery);
|
||||
getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join(''));
|
||||
getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.query);
|
||||
getDetails(RULE_TYPE_DETAILS).should('have.text', 'Threshold');
|
||||
getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None');
|
||||
getDetails(THRESHOLD_DETAILS).should(
|
||||
'have.text',
|
||||
`Results aggregated by ${rule.thresholdField} >= ${rule.threshold}`
|
||||
`Results aggregated by ${rule.threshold.field} >= ${rule.threshold.value}`
|
||||
);
|
||||
});
|
||||
cy.get(SCHEDULE_DETAILS).within(() => {
|
||||
getDetails(RUNS_EVERY_DETAILS).should(
|
||||
'have.text',
|
||||
`${rule.runsEvery?.interval}${rule.runsEvery?.type}`
|
||||
);
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should(
|
||||
'have.text',
|
||||
`${rule.lookBack?.interval}${rule.lookBack?.type}`
|
||||
);
|
||||
getDetails(RUNS_EVERY_DETAILS).should('have.text', `${rule.interval}`);
|
||||
const humanizedDuration = getHumanizedDuration(rule.from ?? 'now-6m', rule.interval ?? '5m');
|
||||
getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should('have.text', `${humanizedDuration}`);
|
||||
});
|
||||
|
||||
waitForTheRuleToBeExecuted();
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getNewRule } from '../../../objects/rule';
|
|||
|
||||
import { RULE_STATUS } from '../../../screens/create_new_rule';
|
||||
|
||||
import { createCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
esArchiverLoad,
|
||||
|
@ -72,10 +72,11 @@ describe('Exceptions flyout', () => {
|
|||
esArchiverLoad('exceptions');
|
||||
login();
|
||||
createExceptionList(getExceptionList(), getExceptionList().list_id).then((response) =>
|
||||
createCustomRule({
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
dataSource: { index: ['auditbeat-*', 'exceptions-*'], type: 'indexPatterns' },
|
||||
exceptionLists: [
|
||||
index: ['auditbeat-*', 'exceptions-*'],
|
||||
enabled: false,
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: getExceptionList().list_id,
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ROLES } from '../../../../common/test';
|
|||
import { getExceptionList, expectedExportedExceptionList } from '../../../objects/exception';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
|
||||
import { createCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../../tasks/login';
|
||||
|
||||
import { EXCEPTIONS_URL } from '../../../urls/navigation';
|
||||
|
@ -48,9 +48,9 @@ describe('Exceptions Table', () => {
|
|||
|
||||
// Create exception list associated with a rule
|
||||
createExceptionList(getExceptionList2(), getExceptionList2().list_id).then((response) =>
|
||||
createCustomRule({
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
exceptionLists: [
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: getExceptionList2().list_id,
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from '../../../tasks/es_archiver';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { createCustomRule, deleteCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import { createRule, deleteCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import { editException, editExceptionFlyoutItemName } from '../../../tasks/exceptions';
|
||||
import { EXCEPTIONS_URL } from '../../../urls/navigation';
|
||||
|
||||
|
@ -28,7 +28,7 @@ describe('Add/edit exception from exception management page', () => {
|
|||
esArchiverLoad('exceptions');
|
||||
login();
|
||||
visitWithoutDateRange(EXCEPTIONS_URL);
|
||||
createCustomRule(getNewRule());
|
||||
createRule(getNewRule());
|
||||
});
|
||||
|
||||
after(() => {
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ROLES } from '../../../../common/test';
|
|||
import { getExceptionList, expectedExportedExceptionList } from '../../../objects/exception';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
|
||||
import { createCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { login, visitWithoutDateRange, waitForPageWithoutDateRange } from '../../../tasks/login';
|
||||
|
||||
import { EXCEPTIONS_URL } from '../../../urls/navigation';
|
||||
|
@ -48,9 +48,9 @@ describe('Exceptions Table', () => {
|
|||
|
||||
// Create exception list associated with a rule
|
||||
createExceptionList(getExceptionList2(), getExceptionList2().list_id).then((response) =>
|
||||
createCustomRule({
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
exceptionLists: [
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: getExceptionList2().list_id,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
|
||||
import { createCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
esArchiverLoad,
|
||||
|
@ -59,22 +59,20 @@ describe('Add endpoint exception from rule details', () => {
|
|||
deleteAlertsAndRules();
|
||||
// create rule with exception
|
||||
createEndpointExceptionList().then((response) => {
|
||||
createCustomRule(
|
||||
{
|
||||
...getNewRule(),
|
||||
customQuery: 'event.code:*',
|
||||
dataSource: { index: ['auditbeat*'], type: 'indexPatterns' },
|
||||
exceptionLists: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: response.body.list_id,
|
||||
type: response.body.type,
|
||||
namespace_type: response.body.namespace_type,
|
||||
},
|
||||
],
|
||||
},
|
||||
'2'
|
||||
);
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
query: 'event.code:*',
|
||||
index: ['auditbeat*'],
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: response.body.list_id,
|
||||
type: response.body.type,
|
||||
namespace_type: response.body.namespace_type,
|
||||
},
|
||||
],
|
||||
rule_id: '2',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getException, getExceptionList } from '../../../objects/exception';
|
|||
import { getNewRule } from '../../../objects/rule';
|
||||
|
||||
import { ALERTS_COUNT, EMPTY_ALERT_TABLE, NUMBER_OF_ALERTS } from '../../../screens/alerts';
|
||||
import { createCustomRule, createCustomRuleEnabled } from '../../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
goToClosedAlertsOnRuleDetailsPage,
|
||||
|
@ -86,22 +86,20 @@ describe('Add/edit exception from rule details', () => {
|
|||
deleteExceptionList(exceptionList.list_id, exceptionList.namespace_type);
|
||||
// create rule with exceptions
|
||||
createExceptionList(exceptionList, exceptionList.list_id).then((response) => {
|
||||
createCustomRule(
|
||||
{
|
||||
...getNewRule(),
|
||||
customQuery: 'agent.name:*',
|
||||
dataSource: { index: ['exceptions*'], type: 'indexPatterns' },
|
||||
exceptionLists: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: exceptionList.list_id,
|
||||
type: exceptionList.type,
|
||||
namespace_type: exceptionList.namespace_type,
|
||||
},
|
||||
],
|
||||
},
|
||||
'2'
|
||||
);
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
query: 'agent.name:*',
|
||||
index: ['exceptions*'],
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: exceptionList.list_id,
|
||||
type: exceptionList.type,
|
||||
namespace_type: exceptionList.namespace_type,
|
||||
},
|
||||
],
|
||||
rule_id: '2',
|
||||
});
|
||||
createExceptionListItem(exceptionList.list_id, {
|
||||
list_id: exceptionList.list_id,
|
||||
item_id: 'simple_list_item',
|
||||
|
@ -251,19 +249,13 @@ describe('Add/edit exception from rule details', () => {
|
|||
describe('rule without existing exceptions', () => {
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(
|
||||
{
|
||||
...getNewRule(),
|
||||
customQuery: 'agent.name:*',
|
||||
dataSource: { index: ['exceptions*'], type: 'indexPatterns' },
|
||||
runsEvery: {
|
||||
interval: '10',
|
||||
timeType: 'Seconds',
|
||||
type: 's',
|
||||
},
|
||||
},
|
||||
'rule_testing'
|
||||
);
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
query: 'agent.name:*',
|
||||
index: ['exceptions*'],
|
||||
interval: '10s',
|
||||
rule_id: 'rule_testing',
|
||||
});
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
goToExceptionsTab();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { LOADING_INDICATOR } from '../../../screens/security_header';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { ALERTS_COUNT, EMPTY_ALERT_TABLE, NUMBER_OF_ALERTS } from '../../../screens/alerts';
|
||||
import { createCustomRuleEnabled } from '../../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { goToRuleDetails } from '../../../tasks/alerts_detection_rules';
|
||||
import {
|
||||
addExceptionFromFirstAlert,
|
||||
|
@ -69,19 +69,13 @@ describe('Add exception using data views from rule details', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
deleteAlertsAndRules();
|
||||
createCustomRuleEnabled(
|
||||
{
|
||||
...getNewRule(),
|
||||
customQuery: 'agent.name:*',
|
||||
dataSource: { dataView: 'exceptions-*', type: 'dataView' },
|
||||
runsEvery: {
|
||||
interval: '10',
|
||||
timeType: 'Seconds',
|
||||
type: 's',
|
||||
},
|
||||
},
|
||||
'rule_testing'
|
||||
);
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
query: 'agent.name:*',
|
||||
data_view_id: 'exceptions-*',
|
||||
interval: '10s',
|
||||
rule_id: 'rule_testing',
|
||||
});
|
||||
visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL);
|
||||
goToRuleDetails();
|
||||
waitForAlertsToPopulate();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { getExceptionList } from '../../../objects/exception';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { ROLES } from '../../../../common/test';
|
||||
import { createCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { esArchiverResetKibana } from '../../../tasks/es_archiver';
|
||||
import { login, visitWithoutDateRange } from '../../../tasks/login';
|
||||
import { goToExceptionsTab, goToAlertsTab } from '../../../tasks/rule_details';
|
||||
|
@ -35,22 +35,20 @@ describe('Exceptions viewer read only', () => {
|
|||
esArchiverResetKibana();
|
||||
// create rule with exceptions
|
||||
createExceptionList(exceptionList, exceptionList.list_id).then((response) => {
|
||||
createCustomRule(
|
||||
{
|
||||
...getNewRule(),
|
||||
customQuery: 'agent.name:*',
|
||||
dataSource: { index: ['exceptions*'], type: 'indexPatterns' },
|
||||
exceptionLists: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: exceptionList.list_id,
|
||||
type: exceptionList.type,
|
||||
namespace_type: exceptionList.namespace_type,
|
||||
},
|
||||
],
|
||||
},
|
||||
'2'
|
||||
);
|
||||
createRule({
|
||||
...getNewRule(),
|
||||
query: 'agent.name:*',
|
||||
index: ['exceptions*'],
|
||||
exceptions_list: [
|
||||
{
|
||||
id: response.body.id,
|
||||
list_id: exceptionList.list_id,
|
||||
type: exceptionList.type,
|
||||
namespace_type: exceptionList.namespace_type,
|
||||
},
|
||||
],
|
||||
rule_id: '2',
|
||||
});
|
||||
});
|
||||
|
||||
login(ROLES.reader);
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
startTour,
|
||||
} from '../../tasks/guided_onboarding';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { ALERTS_URL, DASHBOARDS_URL } from '../../urls/navigation';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
|
@ -32,7 +32,7 @@ describe('Guided onboarding tour', () => {
|
|||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
createCustomRuleEnabled({ ...getNewRule(), customQuery: 'user.name:*' });
|
||||
createRule({ ...getNewRule(), query: 'user.name:*' });
|
||||
});
|
||||
beforeEach(() => {
|
||||
startAlertsCasesTour();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { getNewRule } from '../../objects/rule';
|
||||
import { SELECTED_ALERTS } from '../../screens/alerts';
|
||||
import { SERVER_SIDE_EVENT_COUNT } from '../../screens/timeline';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import {
|
||||
bulkInvestigateSelectedEventsInTimeline,
|
||||
|
@ -57,7 +57,7 @@ describe('Bulk Investigate in Timeline', () => {
|
|||
|
||||
context('Alerts', () => {
|
||||
before(() => {
|
||||
createCustomRuleEnabled(getNewRule());
|
||||
createRule(getNewRule());
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { ALERT_FLYOUT } from '../../screens/alerts_details';
|
||||
import { createCustomRuleEnabled } from '../../tasks/api_calls/rules';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login, visitWithoutDateRange } from '../../tasks/login';
|
||||
|
@ -28,7 +28,7 @@ describe('user details flyout', () => {
|
|||
|
||||
it('shows user detail flyout from alert table', () => {
|
||||
visitWithoutDateRange(ALERTS_URL);
|
||||
createCustomRuleEnabled({ ...getNewRule(), customQuery: 'user.name:*' });
|
||||
createRule({ ...getNewRule(), query: 'user.name:*' });
|
||||
refreshPage();
|
||||
waitForAlertsToPopulate();
|
||||
|
||||
|
|
|
@ -5,18 +5,30 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Mitre } from '../objects/rule';
|
||||
import dateMath from '@kbn/datemath';
|
||||
import moment from 'moment';
|
||||
|
||||
export const formatMitreAttackDescription = (mitre: Mitre[]) => {
|
||||
import type { ThreatArray } from '../../common/detection_engine/rule_schema';
|
||||
|
||||
export const formatMitreAttackDescription = (mitre: ThreatArray) => {
|
||||
return mitre
|
||||
.map(
|
||||
(threat) =>
|
||||
threat.tactic +
|
||||
threat.techniques
|
||||
.map((technique) => {
|
||||
return technique.name + technique.subtechniques.join('');
|
||||
})
|
||||
.join('')
|
||||
`${threat.tactic.name} (${threat.tactic.id})${
|
||||
threat.technique
|
||||
? threat.technique
|
||||
.map((technique) => {
|
||||
return `${technique.name} (${technique.id})${
|
||||
technique.subtechnique
|
||||
? technique.subtechnique
|
||||
.map((subtechnique) => `${subtechnique.name} (${subtechnique.id})`)
|
||||
.join('')
|
||||
: ''
|
||||
}`;
|
||||
})
|
||||
.join('')
|
||||
: ''
|
||||
}`
|
||||
)
|
||||
.join('');
|
||||
};
|
||||
|
@ -35,3 +47,33 @@ export const elementsOverlap = ($element1: JQuery<HTMLElement>, $element2: JQuer
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
export const getHumanizedDuration = (from: string, interval: string): string => {
|
||||
const fromValue = dateMath.parse(from) ?? moment();
|
||||
const intervalValue = dateMath.parse(`now-${interval}`) ?? moment();
|
||||
|
||||
const fromDuration = moment.duration(intervalValue.diff(fromValue));
|
||||
|
||||
// Basing calculations off floored seconds count as moment durations weren't precise
|
||||
const intervalDuration = Math.floor(fromDuration.asSeconds());
|
||||
// For consistency of display value
|
||||
if (intervalDuration === 0) {
|
||||
return `0s`;
|
||||
}
|
||||
|
||||
if (intervalDuration % 3600 === 0) {
|
||||
return `${intervalDuration / 3600}h`;
|
||||
} else if (intervalDuration % 60 === 0) {
|
||||
return `${intervalDuration / 60}m`;
|
||||
} else {
|
||||
return `${intervalDuration}s`;
|
||||
}
|
||||
};
|
||||
|
||||
export const convertHistoryStartToSize = (relativeTime: string) => {
|
||||
if (relativeTime.startsWith('now-')) {
|
||||
return relativeTime.substring(4);
|
||||
} else {
|
||||
return relativeTime;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,120 +5,30 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { RuleActionThrottle } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import type {
|
||||
RuleActionThrottle,
|
||||
SeverityMappingItem,
|
||||
Threat,
|
||||
} from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import { getMockThreatData } from '../../public/detections/mitre/mitre_tactics_techniques';
|
||||
import type { CompleteTimeline } from './timeline';
|
||||
import { getTimeline, getIndicatorMatchTimelineTemplate } from './timeline';
|
||||
import type { RuleResponse } from '../../common/detection_engine/rule_schema';
|
||||
import type {
|
||||
EqlRuleCreateProps,
|
||||
MachineLearningRuleCreateProps,
|
||||
NewTermsRuleCreateProps,
|
||||
QueryRuleCreateProps,
|
||||
RuleResponse,
|
||||
ThreatMatchRuleCreateProps,
|
||||
ThresholdRuleCreateProps,
|
||||
} from '../../common/detection_engine/rule_schema';
|
||||
import type { Connectors } from './connector';
|
||||
|
||||
const ccsRemoteName: string = Cypress.env('CCS_REMOTE_NAME');
|
||||
|
||||
interface MitreAttackTechnique {
|
||||
name: string;
|
||||
subtechniques: string[];
|
||||
}
|
||||
|
||||
export interface Mitre {
|
||||
tactic: string;
|
||||
techniques: MitreAttackTechnique[];
|
||||
}
|
||||
|
||||
interface SeverityOverride {
|
||||
sourceField: string;
|
||||
sourceValue: string;
|
||||
}
|
||||
|
||||
interface Interval {
|
||||
interval: string;
|
||||
timeType: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface Actions {
|
||||
throttle: RuleActionThrottle;
|
||||
connectors: Connectors[];
|
||||
}
|
||||
|
||||
export type RuleDataSource =
|
||||
| { type: 'indexPatterns'; index: string[] }
|
||||
| { type: 'dataView'; dataView: string };
|
||||
|
||||
export interface CustomRule {
|
||||
customQuery?: string;
|
||||
name: string;
|
||||
description: string;
|
||||
dataSource: RuleDataSource;
|
||||
severity?: string;
|
||||
riskScore?: string;
|
||||
tags?: string[];
|
||||
timelineTemplate?: string;
|
||||
referenceUrls?: string[];
|
||||
falsePositivesExamples?: string[];
|
||||
mitre?: Mitre[];
|
||||
note?: string;
|
||||
runsEvery?: Interval;
|
||||
interval?: string;
|
||||
lookBack?: Interval;
|
||||
timeline?: CompleteTimeline;
|
||||
maxSignals?: number;
|
||||
buildingBlockType?: string;
|
||||
exceptionLists?: Array<{ id: string; list_id: string; type: string; namespace_type: string }>;
|
||||
actions?: Actions;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ThresholdRule extends CustomRule {
|
||||
thresholdField: string;
|
||||
threshold: string;
|
||||
}
|
||||
|
||||
export interface SavedQueryRule extends CustomRule {
|
||||
savedId: string;
|
||||
}
|
||||
|
||||
export interface OverrideRule extends CustomRule {
|
||||
severityOverride: SeverityOverride[];
|
||||
riskOverride: string;
|
||||
nameOverride: string;
|
||||
timestampOverride: string;
|
||||
}
|
||||
|
||||
export interface ThreatIndicatorRule extends CustomRule {
|
||||
indicatorIndexPattern: string[];
|
||||
indicatorMappingField: string;
|
||||
indicatorIndexField: string;
|
||||
threatIndicatorPath: string;
|
||||
type?: string;
|
||||
atomic?: string;
|
||||
matchedType?: string;
|
||||
matchedId?: string;
|
||||
matchedIndex?: string;
|
||||
}
|
||||
|
||||
export interface NewTermsRule extends CustomRule {
|
||||
newTermsFields: string[];
|
||||
historyWindowSize: Interval;
|
||||
}
|
||||
|
||||
export interface MachineLearningRule {
|
||||
machineLearningJobs: string[];
|
||||
anomalyScoreThreshold: number;
|
||||
name: string;
|
||||
description: string;
|
||||
severity: string;
|
||||
riskScore: string;
|
||||
tags: string[];
|
||||
timelineTemplate?: string;
|
||||
referenceUrls: string[];
|
||||
falsePositivesExamples: string[];
|
||||
mitre: Mitre[];
|
||||
note: string;
|
||||
runsEvery: Interval;
|
||||
lookBack: Interval;
|
||||
interval?: string;
|
||||
}
|
||||
|
||||
export const getIndexPatterns = (): string[] => [
|
||||
'apm-*-transaction*',
|
||||
'auditbeat-*',
|
||||
|
@ -133,368 +43,408 @@ export const getIndexPatterns = (): string[] => [
|
|||
|
||||
export const getThreatIndexPatterns = (): string[] => ['logs-ti_*'];
|
||||
|
||||
const getMitre1 = (): Mitre => ({
|
||||
tactic: `${getMockThreatData().tactic.name} (${getMockThreatData().tactic.id})`,
|
||||
techniques: [
|
||||
const getMitre1 = (): Threat => ({
|
||||
framework: 'MITRE ATT&CK',
|
||||
tactic: {
|
||||
name: getMockThreatData().tactic.name,
|
||||
id: getMockThreatData().tactic.id,
|
||||
reference: getMockThreatData().tactic.reference,
|
||||
},
|
||||
technique: [
|
||||
{
|
||||
name: `${getMockThreatData().technique.name} (${getMockThreatData().technique.id})`,
|
||||
subtechniques: [
|
||||
`${getMockThreatData().subtechnique.name} (${getMockThreatData().subtechnique.id})`,
|
||||
id: getMockThreatData().technique.id,
|
||||
reference: getMockThreatData().technique.reference,
|
||||
name: getMockThreatData().technique.name,
|
||||
subtechnique: [
|
||||
{
|
||||
id: getMockThreatData().subtechnique.id,
|
||||
name: getMockThreatData().subtechnique.name,
|
||||
reference: getMockThreatData().subtechnique.reference,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: `${getMockThreatData().technique.name} (${getMockThreatData().technique.id})`,
|
||||
subtechniques: [],
|
||||
name: getMockThreatData().technique.name,
|
||||
id: getMockThreatData().technique.id,
|
||||
reference: getMockThreatData().technique.reference,
|
||||
subtechnique: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const getMitre2 = (): Mitre => ({
|
||||
tactic: `${getMockThreatData().tactic.name} (${getMockThreatData().tactic.id})`,
|
||||
techniques: [
|
||||
const getMitre2 = (): Threat => ({
|
||||
framework: 'MITRE ATT&CK',
|
||||
tactic: {
|
||||
name: getMockThreatData().tactic.name,
|
||||
id: getMockThreatData().tactic.id,
|
||||
reference: getMockThreatData().tactic.reference,
|
||||
},
|
||||
technique: [
|
||||
{
|
||||
name: `${getMockThreatData().technique.name} (${getMockThreatData().technique.id})`,
|
||||
subtechniques: [
|
||||
`${getMockThreatData().subtechnique.name} (${getMockThreatData().subtechnique.id})`,
|
||||
id: getMockThreatData().technique.id,
|
||||
reference: getMockThreatData().technique.reference,
|
||||
name: getMockThreatData().technique.name,
|
||||
subtechnique: [
|
||||
{
|
||||
id: getMockThreatData().subtechnique.id,
|
||||
name: getMockThreatData().subtechnique.name,
|
||||
reference: getMockThreatData().subtechnique.reference,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const getSeverityOverride1 = (): SeverityOverride => ({
|
||||
sourceField: 'host.name',
|
||||
sourceValue: 'host',
|
||||
const getSeverityOverride1 = (): SeverityMappingItem => ({
|
||||
field: 'host.name',
|
||||
value: 'host',
|
||||
operator: 'equals',
|
||||
severity: 'low',
|
||||
});
|
||||
|
||||
const getSeverityOverride2 = (): SeverityOverride => ({
|
||||
sourceField: '@timestamp',
|
||||
sourceValue: '10/02/2020',
|
||||
const getSeverityOverride2 = (): SeverityMappingItem => ({
|
||||
field: '@timestamp',
|
||||
value: '10/02/2020',
|
||||
operator: 'equals',
|
||||
severity: 'medium',
|
||||
});
|
||||
|
||||
const getSeverityOverride3 = (): SeverityOverride => ({
|
||||
sourceField: 'host.geo.name',
|
||||
sourceValue: 'atack',
|
||||
const getSeverityOverride3 = (): SeverityMappingItem => ({
|
||||
field: 'host.geo.name',
|
||||
value: 'atack',
|
||||
operator: 'equals',
|
||||
severity: 'high',
|
||||
});
|
||||
|
||||
const getSeverityOverride4 = (): SeverityOverride => ({
|
||||
sourceField: 'agent.type',
|
||||
sourceValue: 'auditbeat',
|
||||
const getSeverityOverride4 = (): SeverityMappingItem => ({
|
||||
field: 'agent.type',
|
||||
value: 'auditbeat',
|
||||
operator: 'equals',
|
||||
severity: 'critical',
|
||||
});
|
||||
|
||||
const getRunsEvery = (): Interval => ({
|
||||
interval: '100',
|
||||
timeType: 'Minutes',
|
||||
type: 'm',
|
||||
});
|
||||
|
||||
const getLookBack = (): Interval => ({
|
||||
interval: '50000',
|
||||
timeType: 'Hours',
|
||||
type: 'h',
|
||||
});
|
||||
|
||||
export const getDataViewRule = (): CustomRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
dataSource: { dataView: 'auditbeat-2022', type: 'dataView' },
|
||||
export const getDataViewRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: 'host.name: *',
|
||||
data_view_id: 'auditbeat-2022',
|
||||
name: 'New Data View Rule',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getNewRule = (): CustomRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
export const getNewRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: 'host.name: *',
|
||||
index: getIndexPatterns(),
|
||||
name: 'New Rule Test',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getSimpleCustomQueryRule = (): CustomRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
export const getSimpleCustomQueryRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: 'host.name: *',
|
||||
index: getIndexPatterns(),
|
||||
name: 'New Rule Test',
|
||||
description: 'The new rule description.',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
severity: 'low',
|
||||
risk_score: 21,
|
||||
});
|
||||
|
||||
export const getBuildingBlockRule = (): CustomRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
export const getBuildingBlockRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: 'host.name: *',
|
||||
index: getIndexPatterns(),
|
||||
name: 'Building Block Rule Test',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
buildingBlockType: 'default',
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
building_block_type: 'default',
|
||||
});
|
||||
|
||||
export const getUnmappedRule = (): CustomRule => ({
|
||||
customQuery: '*:*',
|
||||
dataSource: { index: ['unmapped*'], type: 'indexPatterns' },
|
||||
export const getUnmappedRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: '*:*',
|
||||
index: ['unmapped*'],
|
||||
name: 'Rule with unmapped fields',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getUnmappedCCSRule = (): CustomRule => ({
|
||||
customQuery: '*:*',
|
||||
dataSource: { index: [`${ccsRemoteName}:unmapped*`], type: 'indexPatterns' },
|
||||
export const getUnmappedCCSRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: '*:*',
|
||||
index: [`${ccsRemoteName}:unmapped*`],
|
||||
name: 'Rule with unmapped fields',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getExistingRule = (): CustomRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
export const getExistingRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: 'host.name: *',
|
||||
name: 'Rule 1',
|
||||
description: 'Description for Rule 1',
|
||||
dataSource: { index: ['auditbeat-*'], type: 'indexPatterns' },
|
||||
severity: 'High',
|
||||
riskScore: '19',
|
||||
index: ['auditbeat-*'],
|
||||
severity: 'high',
|
||||
risk_score: 19,
|
||||
tags: ['rule1'],
|
||||
referenceUrls: [],
|
||||
falsePositivesExamples: [],
|
||||
mitre: [],
|
||||
references: [],
|
||||
false_positives: [],
|
||||
threat: [],
|
||||
note: 'This is my note',
|
||||
runsEvery: getRunsEvery(),
|
||||
interval: '100m',
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
from: 'now-50000h',
|
||||
// Please do not change, or if you do, needs
|
||||
// to be any number other than default value
|
||||
maxSignals: 500,
|
||||
max_signals: 500,
|
||||
});
|
||||
|
||||
export const getNewOverrideRule = (): OverrideRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
export const getNewOverrideRule = (): QueryRuleCreateProps => ({
|
||||
type: 'query',
|
||||
query: 'host.name: *',
|
||||
index: getIndexPatterns(),
|
||||
name: 'Override Rule',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
severityOverride: [
|
||||
severity_mapping: [
|
||||
getSeverityOverride1(),
|
||||
getSeverityOverride2(),
|
||||
getSeverityOverride3(),
|
||||
getSeverityOverride4(),
|
||||
],
|
||||
riskOverride: 'destination.port',
|
||||
nameOverride: 'agent.type',
|
||||
timestampOverride: '@timestamp',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
risk_score_mapping: [
|
||||
{ field: 'destination.port', value: '', operator: 'equals', risk_score: undefined },
|
||||
],
|
||||
rule_name_override: 'agent.type',
|
||||
timestamp_override: '@timestamp',
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getNewThresholdRule = (): ThresholdRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
export const getNewThresholdRule = (): ThresholdRuleCreateProps => ({
|
||||
type: 'threshold',
|
||||
query: 'host.name: *',
|
||||
index: getIndexPatterns(),
|
||||
name: 'Threshold Rule',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
thresholdField: 'host.name',
|
||||
threshold: '1',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
threshold: {
|
||||
field: 'host.name',
|
||||
value: 1,
|
||||
},
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getNewTermsRule = (): NewTermsRule => ({
|
||||
customQuery: 'host.name: *',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
export const getNewTermsRule = (): NewTermsRuleCreateProps => ({
|
||||
type: 'new_terms',
|
||||
query: 'host.name: *',
|
||||
index: getIndexPatterns(),
|
||||
name: 'New Terms Rule',
|
||||
description: 'The new rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
newTermsFields: ['host.name'],
|
||||
historyWindowSize: {
|
||||
// historyWindowSize needs to be larger than the rule's lookback value
|
||||
interval: '51000',
|
||||
timeType: 'Hours',
|
||||
type: 'h',
|
||||
},
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
new_terms_fields: ['host.name'],
|
||||
history_window_start: 'now-51000h',
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getMachineLearningRule = (): MachineLearningRule => ({
|
||||
machineLearningJobs: [
|
||||
export const getMachineLearningRule = (): MachineLearningRuleCreateProps => ({
|
||||
type: 'machine_learning',
|
||||
machine_learning_job_id: [
|
||||
'Unusual Linux Network Activity',
|
||||
'Anomalous Process for a Linux Population',
|
||||
],
|
||||
anomalyScoreThreshold: 20,
|
||||
anomaly_threshold: 20,
|
||||
name: 'New ML Rule Test',
|
||||
description: 'The new ML rule description.',
|
||||
severity: 'Critical',
|
||||
riskScore: '70',
|
||||
severity: 'critical',
|
||||
risk_score: 70,
|
||||
tags: ['ML'],
|
||||
referenceUrls: ['https://elastic.co/'],
|
||||
falsePositivesExamples: ['False1'],
|
||||
mitre: [getMitre1()],
|
||||
references: ['https://elastic.co/'],
|
||||
false_positives: ['False1'],
|
||||
threat: [getMitre1()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
});
|
||||
|
||||
export const getEqlRule = (): CustomRule => ({
|
||||
customQuery: 'any where process.name == "zsh"',
|
||||
export const getEqlRule = (): EqlRuleCreateProps => ({
|
||||
type: 'eql',
|
||||
language: 'eql',
|
||||
query: 'any where process.name == "zsh"',
|
||||
name: 'New EQL Rule',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
index: getIndexPatterns(),
|
||||
description: 'New EQL rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getCCSEqlRule = (): CustomRule => ({
|
||||
customQuery: 'any where process.name == "run-parts"',
|
||||
export const getCCSEqlRule = (): EqlRuleCreateProps => ({
|
||||
type: 'eql',
|
||||
language: 'eql',
|
||||
query: 'any where process.name == "run-parts"',
|
||||
name: 'New EQL Rule',
|
||||
dataSource: { index: [`${ccsRemoteName}:run-parts`], type: 'indexPatterns' },
|
||||
index: [`${ccsRemoteName}:run-parts`],
|
||||
description: 'New EQL rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getEqlSequenceRule = (): CustomRule => ({
|
||||
customQuery:
|
||||
export const getEqlSequenceRule = (): EqlRuleCreateProps => ({
|
||||
type: 'eql',
|
||||
language: 'eql',
|
||||
query:
|
||||
'sequence with maxspan=30s\
|
||||
[any where agent.name == "test.local"]\
|
||||
[any where host.name == "test.local"]',
|
||||
name: 'New EQL Sequence Rule',
|
||||
dataSource: { index: getIndexPatterns(), type: 'indexPatterns' },
|
||||
index: getIndexPatterns(),
|
||||
description: 'New EQL rule description.',
|
||||
severity: 'High',
|
||||
riskScore: '17',
|
||||
severity: 'high',
|
||||
risk_score: 17,
|
||||
tags: ['test', 'newRule'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
timeline: getTimeline(),
|
||||
maxSignals: 100,
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
max_signals: 100,
|
||||
});
|
||||
|
||||
export const getNewThreatIndicatorRule = (): ThreatIndicatorRule => ({
|
||||
export const getNewThreatIndicatorRule = (): ThreatMatchRuleCreateProps => ({
|
||||
type: 'threat_match',
|
||||
name: 'Threat Indicator Rule Test',
|
||||
description: 'The threat indicator rule description.',
|
||||
dataSource: { index: ['suspicious-*'], type: 'indexPatterns' },
|
||||
severity: 'Critical',
|
||||
riskScore: '20',
|
||||
query: '*:*',
|
||||
threat_query: '*:*',
|
||||
index: ['suspicious-*'],
|
||||
severity: 'critical',
|
||||
risk_score: 20,
|
||||
tags: ['test', 'threat'],
|
||||
referenceUrls: ['http://example.com/', 'https://example.com/'],
|
||||
falsePositivesExamples: ['False1', 'False2'],
|
||||
mitre: [getMitre1(), getMitre2()],
|
||||
references: ['http://example.com/', 'https://example.com/'],
|
||||
false_positives: ['False1', 'False2'],
|
||||
threat: [getMitre1(), getMitre2()],
|
||||
note: '# test markdown',
|
||||
runsEvery: getRunsEvery(),
|
||||
lookBack: getLookBack(),
|
||||
indicatorIndexPattern: ['filebeat-*'],
|
||||
indicatorMappingField: 'myhash.mysha256',
|
||||
indicatorIndexField: 'threat.indicator.file.hash.sha256',
|
||||
type: 'file',
|
||||
interval: '100m',
|
||||
from: 'now-50000h',
|
||||
threat_index: ['filebeat-*'],
|
||||
threat_mapping: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
field: 'myhash.mysha256',
|
||||
value: 'threat.indicator.file.hash.sha256',
|
||||
type: 'mapping',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
max_signals: 100,
|
||||
threat_indicator_path: 'threat.indicator',
|
||||
timeline_title: 'Generic Threat Match Timeline',
|
||||
timeline_id: '495ad7a7-316e-4544-8a0f-9c098daee76e',
|
||||
});
|
||||
|
||||
export const indicatorRuleMatchingDoc = {
|
||||
atomic: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
timeline: getIndicatorMatchTimelineTemplate(),
|
||||
maxSignals: 100,
|
||||
threatIndicatorPath: 'threat.indicator',
|
||||
matchedType: 'indicator_match_rule',
|
||||
matchedId: '84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f',
|
||||
matchedIndex: 'logs-ti_abusech.malware',
|
||||
});
|
||||
};
|
||||
|
||||
export const duplicatedRuleName = `${getNewThreatIndicatorRule().name} [Duplicate]`;
|
||||
|
||||
export const getSeveritiesOverride = (): string[] => ['Low', 'Medium', 'High', 'Critical'];
|
||||
|
||||
export const getEditedRule = (): CustomRule => ({
|
||||
export const getEditedRule = (): QueryRuleCreateProps => ({
|
||||
...getExistingRule(),
|
||||
severity: 'Medium',
|
||||
severity: 'medium',
|
||||
description: 'Edited Rule description',
|
||||
tags: [...(getExistingRule().tags || []), 'edited'],
|
||||
});
|
||||
|
@ -505,13 +455,30 @@ export const expectedExportedRule = (ruleResponse: Cypress.Response<RuleResponse
|
|||
updated_at: updatedAt,
|
||||
updated_by: updatedBy,
|
||||
created_at: createdAt,
|
||||
created_by: createdBy,
|
||||
description,
|
||||
name,
|
||||
risk_score: riskScore,
|
||||
severity,
|
||||
note,
|
||||
tags,
|
||||
timeline_id: timelineId,
|
||||
timeline_title: timelineTitle,
|
||||
interval,
|
||||
enabled,
|
||||
author,
|
||||
false_positives: falsePositives,
|
||||
from,
|
||||
rule_id: ruleId,
|
||||
max_signals: maxSignals,
|
||||
risk_score_mapping: riskScoreMapping,
|
||||
severity_mapping: severityMapping,
|
||||
threat,
|
||||
to,
|
||||
references,
|
||||
version,
|
||||
exceptions_list: exceptionsList,
|
||||
immutable,
|
||||
related_integrations: relatedIntegrations,
|
||||
setup,
|
||||
} = ruleResponse.body;
|
||||
|
||||
let query: string | undefined;
|
||||
|
@ -527,39 +494,38 @@ export const expectedExportedRule = (ruleResponse: Cypress.Response<RuleResponse
|
|||
updated_at: updatedAt,
|
||||
updated_by: updatedBy,
|
||||
created_at: createdAt,
|
||||
created_by: 'elastic',
|
||||
created_by: createdBy,
|
||||
name,
|
||||
tags,
|
||||
interval: '100m',
|
||||
enabled: false,
|
||||
interval,
|
||||
enabled,
|
||||
description,
|
||||
risk_score: riskScore,
|
||||
severity,
|
||||
note,
|
||||
output_index: '',
|
||||
author: [],
|
||||
false_positives: [],
|
||||
from: 'now-50000h',
|
||||
rule_id: 'rule_testing',
|
||||
max_signals: 100,
|
||||
risk_score_mapping: [],
|
||||
severity_mapping: [],
|
||||
threat: [],
|
||||
to: 'now',
|
||||
references: [],
|
||||
version: 1,
|
||||
exceptions_list: [],
|
||||
immutable: false,
|
||||
related_integrations: [],
|
||||
author,
|
||||
false_positives: falsePositives,
|
||||
from,
|
||||
rule_id: ruleId,
|
||||
max_signals: maxSignals,
|
||||
risk_score_mapping: riskScoreMapping,
|
||||
severity_mapping: severityMapping,
|
||||
threat,
|
||||
to,
|
||||
references,
|
||||
version,
|
||||
exceptions_list: exceptionsList,
|
||||
immutable,
|
||||
related_integrations: relatedIntegrations,
|
||||
required_fields: [],
|
||||
setup: '',
|
||||
setup,
|
||||
type: 'query',
|
||||
language: 'kuery',
|
||||
index: getIndexPatterns(),
|
||||
query,
|
||||
throttle: 'no_actions',
|
||||
actions: [],
|
||||
timeline_id: timelineId,
|
||||
timeline_title: timelineTitle,
|
||||
};
|
||||
|
||||
// NOTE: Order of the properties in this object matters for the tests to work.
|
||||
|
|
|
@ -22,6 +22,12 @@ export const ADD_FALSE_POSITIVE_BTN =
|
|||
export const ADD_REFERENCE_URL_BTN =
|
||||
'[data-test-subj="detectionEngineStepAboutRuleReferenceUrls"] .euiButtonEmpty__text';
|
||||
|
||||
export const ALERT_SUPPRESSION_FIELDS =
|
||||
'[data-test-subj="alertSuppressionInput"] [data-test-subj="comboBoxInput"]';
|
||||
|
||||
export const ALERT_SUPPRESSION_DURATION_OPTIONS =
|
||||
'[data-test-subj="alertSuppressionDuration"] [data-test-subj="groupByDurationOptions"]';
|
||||
|
||||
export const ANOMALY_THRESHOLD_INPUT = '[data-test-subj="anomalyThresholdSlider"] .euiFieldNumber';
|
||||
|
||||
export const ADVANCED_SETTINGS_BTN = '[data-test-subj="advancedSettings"] .euiAccordion__button';
|
||||
|
|
|
@ -112,6 +112,10 @@ export const TIMELINE_TEMPLATE_DETAILS = 'Timeline template';
|
|||
|
||||
export const TIMESTAMP_OVERRIDE_DETAILS = 'Timestamp override';
|
||||
|
||||
export const SUPPRESS_BY_DETAILS = 'Suppress alerts by';
|
||||
|
||||
export const SUPPRESS_FOR_DETAILS = 'Suppress alerts for';
|
||||
|
||||
export const TIMELINE_FIELD = (field: string) => {
|
||||
return `[data-test-subj="formatted-field-${field}"]`;
|
||||
};
|
||||
|
|
|
@ -5,323 +5,19 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
|
||||
import type {
|
||||
CustomRule,
|
||||
ThreatIndicatorRule,
|
||||
MachineLearningRule,
|
||||
ThresholdRule,
|
||||
NewTermsRule,
|
||||
SavedQueryRule,
|
||||
} from '../../objects/rule';
|
||||
|
||||
export const createMachineLearningRule = (rule: MachineLearningRule, ruleId = 'ml_rule_testing') =>
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: parseInt(rule.riskScore, 10),
|
||||
description: rule.description,
|
||||
interval: rule.interval,
|
||||
name: rule.name,
|
||||
severity: rule.severity.toLocaleLowerCase(),
|
||||
type: 'machine_learning',
|
||||
from: 'now-50000h',
|
||||
enabled: false,
|
||||
machine_learning_job_id: rule.machineLearningJobs,
|
||||
anomaly_threshold: rule.anomalyScoreThreshold,
|
||||
tags: rule.tags,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
|
||||
export const createCustomRule = (
|
||||
rule: CustomRule,
|
||||
ruleId = 'rule_testing'
|
||||
): Cypress.Chainable<Cypress.Response<unknown>> => {
|
||||
const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined;
|
||||
const severity = rule.severity != null ? rule.severity.toLocaleLowerCase() : undefined;
|
||||
const timeline = rule.timeline != null ? rule.timeline : undefined;
|
||||
const interval = rule.runsEvery ? `${rule.runsEvery.interval}${rule.runsEvery.type}` : '100m';
|
||||
import { DETECTION_ENGINE_RULES_URL } from '../../../common/constants';
|
||||
import type { RuleCreateProps } from '../../../common/detection_engine/rule_schema';
|
||||
|
||||
export const createRule = (rule: RuleCreateProps) => {
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'query',
|
||||
from: 'now-50000h',
|
||||
index: rule.dataSource.type === 'indexPatterns' ? rule.dataSource.index : undefined,
|
||||
data_view_id: rule.dataSource.type === 'dataView' ? rule.dataSource.dataView : undefined,
|
||||
query: rule.customQuery,
|
||||
language: 'kuery',
|
||||
enabled: rule.enabled ?? false,
|
||||
exceptions_list: rule.exceptionLists ?? [],
|
||||
tags: rule.tags,
|
||||
...(timeline?.id ?? timeline?.templateTimelineId
|
||||
? {
|
||||
timeline_id: timeline.id ?? timeline.templateTimelineId,
|
||||
timeline_title: timeline.title,
|
||||
}
|
||||
: {}),
|
||||
actions: rule.actions,
|
||||
},
|
||||
url: DETECTION_ENGINE_RULES_URL,
|
||||
body: rule,
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const createEventCorrelationRule = (rule: CustomRule, ruleId = 'rule_testing') => {
|
||||
const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined;
|
||||
const severity = rule.severity != null ? rule.severity.toLowerCase() : undefined;
|
||||
const interval = rule.runsEvery ? `${rule.runsEvery.interval}${rule.runsEvery.type}` : '100m';
|
||||
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
from: `now-${rule.lookBack?.interval}${rule.lookBack?.type}`,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'eql',
|
||||
index: rule.dataSource.type === 'indexPatterns' ? rule.dataSource.index : undefined,
|
||||
data_view_id: rule.dataSource.type === 'dataView' ? rule.dataSource.dataView : undefined,
|
||||
query: rule.customQuery,
|
||||
language: 'eql',
|
||||
enabled: true,
|
||||
tags: rule.tags,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
});
|
||||
};
|
||||
|
||||
export const createThresholdRule = (rule: ThresholdRule, ruleId = 'rule_testing') => {
|
||||
const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined;
|
||||
const severity = rule.severity != null ? rule.severity.toLocaleLowerCase() : undefined;
|
||||
const interval = rule.runsEvery ? `${rule.runsEvery.interval}${rule.runsEvery.type}` : '100m';
|
||||
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
from: `now-${rule.lookBack?.interval}${rule.lookBack?.type}`,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'threshold',
|
||||
index: rule.dataSource.type === 'indexPatterns' ? rule.dataSource.index : undefined,
|
||||
data_view_id: rule.dataSource.type === 'dataView' ? rule.dataSource.dataView : undefined,
|
||||
query: rule.customQuery,
|
||||
threshold: {
|
||||
field: [rule.thresholdField],
|
||||
value: parseInt(rule.threshold, 10),
|
||||
cardinality: [],
|
||||
},
|
||||
enabled: true,
|
||||
tags: rule.tags,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
});
|
||||
};
|
||||
|
||||
export const createNewTermsRule = (rule: NewTermsRule, ruleId = 'rule_testing') => {
|
||||
const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined;
|
||||
const severity = rule.severity != null ? rule.severity.toLocaleLowerCase() : undefined;
|
||||
const interval = rule.runsEvery ? `${rule.runsEvery.interval}${rule.runsEvery.type}` : '100m';
|
||||
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
from: `now-${rule.lookBack?.interval}${rule.lookBack?.type}`,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'new_terms',
|
||||
index: rule.dataSource.type === 'indexPatterns' ? rule.dataSource.index : undefined,
|
||||
data_view_id: rule.dataSource.type === 'dataView' ? rule.dataSource.dataView : undefined,
|
||||
query: rule.customQuery,
|
||||
new_terms_fields: rule.newTermsFields,
|
||||
history_window_start: `now-${rule.historyWindowSize.interval}${rule.historyWindowSize.type}`,
|
||||
enabled: true,
|
||||
tags: rule.tags,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
});
|
||||
};
|
||||
|
||||
export const createSavedQueryRule = (
|
||||
rule: SavedQueryRule,
|
||||
ruleId = 'saved_query_rule_testing'
|
||||
): Cypress.Chainable<Cypress.Response<unknown>> => {
|
||||
const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined;
|
||||
const severity = rule.severity != null ? rule.severity.toLocaleLowerCase() : undefined;
|
||||
const timeline = rule.timeline != null ? rule.timeline : undefined;
|
||||
const interval = rule.runsEvery ? `${rule.runsEvery.interval}${rule.runsEvery.type}` : '100m';
|
||||
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'saved_query',
|
||||
from: 'now-50000h',
|
||||
index: rule.dataSource.type === 'indexPatterns' ? rule.dataSource.index : undefined,
|
||||
data_view_id: rule.dataSource.type === 'dataView' ? rule.dataSource.dataView : undefined,
|
||||
saved_id: rule.savedId,
|
||||
language: 'kuery',
|
||||
enabled: false,
|
||||
exceptions_list: rule.exceptionLists ?? [],
|
||||
tags: rule.tags,
|
||||
...(timeline?.id ?? timeline?.templateTimelineId
|
||||
? {
|
||||
timeline_id: timeline.id ?? timeline.templateTimelineId,
|
||||
timeline_title: timeline.title,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const createCustomIndicatorRule = (rule: ThreatIndicatorRule, ruleId = 'rule_testing') => {
|
||||
const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined;
|
||||
const severity = rule.severity != null ? rule.severity.toLocaleLowerCase() : undefined;
|
||||
const timeline = rule.timeline != null ? rule.timeline : undefined;
|
||||
const interval = rule.runsEvery ? `${rule.runsEvery.interval}${rule.runsEvery.type}` : '100m';
|
||||
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'threat_match',
|
||||
timeline_id: timeline?.templateTimelineId,
|
||||
timeline_title: timeline?.title,
|
||||
threat_mapping: [
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
field: rule.indicatorMappingField,
|
||||
type: 'mapping',
|
||||
value: rule.indicatorIndexField,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
threat_query: '*:*',
|
||||
threat_language: 'kuery',
|
||||
threat_filters: [],
|
||||
threat_index: rule.indicatorIndexPattern,
|
||||
threat_indicator_path: rule.threatIndicatorPath,
|
||||
from: 'now-50000h',
|
||||
index: rule.dataSource.type === 'indexPatterns' ? rule.dataSource.index : undefined,
|
||||
data_view_id: rule.dataSource.type === 'dataView' ? rule.dataSource.dataView : undefined,
|
||||
query: rule.customQuery || '*:*',
|
||||
language: 'kuery',
|
||||
enabled: true,
|
||||
tags: rule.tags,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const createCustomRuleEnabled = (
|
||||
rule: CustomRule,
|
||||
ruleId = '1',
|
||||
maxSignals = 500,
|
||||
actions?: RuleActionArray
|
||||
) => {
|
||||
const riskScore = rule.riskScore != null ? parseInt(rule.riskScore, 10) : undefined;
|
||||
const severity = rule.severity != null ? rule.severity.toLocaleLowerCase() : undefined;
|
||||
const interval = rule.runsEvery ? `${rule.runsEvery.interval}${rule.runsEvery.type}` : '100m';
|
||||
|
||||
if (rule.dataSource.type === 'indexPatterns') {
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'query',
|
||||
from: 'now-50000h',
|
||||
index: rule.dataSource.index,
|
||||
query: rule.customQuery,
|
||||
language: 'kuery',
|
||||
enabled: true,
|
||||
exceptions_list: rule.exceptionLists ?? [],
|
||||
tags: ['rule1'],
|
||||
max_signals: maxSignals,
|
||||
building_block_type: rule.buildingBlockType,
|
||||
actions,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
} else if (rule.dataSource.type === 'dataView') {
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: 'api/detection_engine/rules',
|
||||
body: {
|
||||
rule_id: ruleId,
|
||||
risk_score: riskScore,
|
||||
description: rule.description,
|
||||
interval,
|
||||
name: rule.name,
|
||||
severity,
|
||||
type: 'query',
|
||||
from: 'now-50000h',
|
||||
index: [],
|
||||
data_view_id: rule.dataSource.dataView,
|
||||
query: rule.customQuery,
|
||||
language: 'kuery',
|
||||
enabled: true,
|
||||
exceptions_list: rule.exceptionLists ?? [],
|
||||
tags: ['rule1'],
|
||||
max_signals: maxSignals,
|
||||
building_block_type: rule.buildingBlockType,
|
||||
actions,
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteCustomRule = (ruleId = '1') => {
|
||||
cy.request({
|
||||
method: 'DELETE',
|
||||
|
|
|
@ -5,22 +5,20 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isArray, parseInt } from 'lodash';
|
||||
|
||||
import type {
|
||||
RuleIntervalFrom,
|
||||
Threat,
|
||||
ThreatSubtechnique,
|
||||
ThreatTechnique,
|
||||
} from '@kbn/securitysolution-io-ts-alerting-types';
|
||||
import type {
|
||||
CustomRule,
|
||||
MachineLearningRule,
|
||||
OverrideRule,
|
||||
ThreatIndicatorRule,
|
||||
ThresholdRule,
|
||||
NewTermsRule,
|
||||
Mitre,
|
||||
} from '../objects/rule';
|
||||
import { getMachineLearningRule } from '../objects/rule';
|
||||
import type { Actions } from '../objects/rule';
|
||||
// For some reason importing these functions from ../../public/detections/pages/detection_engine/rules/helpers
|
||||
// causes a "Webpack Compilation Error" in this file specifically, even though it imports fine in the test files
|
||||
// in ../e2e/*, so we have a copy of the implementations in the cypress helpers.
|
||||
import { convertHistoryStartToSize, getHumanizedDuration } from '../helpers/rules';
|
||||
|
||||
import {
|
||||
ABOUT_CONTINUE_BTN,
|
||||
ABOUT_EDIT_TAB,
|
||||
|
@ -120,6 +118,15 @@ import { refreshPage } from './security_header';
|
|||
import { EUI_FILTER_SELECT_ITEM, COMBO_BOX_INPUT } from '../screens/common/controls';
|
||||
import { ruleFields } from '../data/detection_engine';
|
||||
import { BACK_TO_RULES_TABLE } from '../screens/rule_details';
|
||||
import type {
|
||||
EqlRuleCreateProps,
|
||||
MachineLearningRuleCreateProps,
|
||||
NewTermsRuleCreateProps,
|
||||
QueryRuleCreateProps,
|
||||
RuleCreateProps,
|
||||
ThreatMatchRuleCreateProps,
|
||||
ThresholdRuleCreateProps,
|
||||
} from '../../common/detection_engine/rule_schema';
|
||||
|
||||
export const createAndEnableRule = () => {
|
||||
cy.get(CREATE_AND_ENABLE_BTN).click({ force: true });
|
||||
|
@ -135,32 +142,30 @@ export const createRuleWithoutEnabling = () => {
|
|||
cy.get(BACK_TO_RULES_TABLE).should('not.exist');
|
||||
};
|
||||
|
||||
export const fillAboutRule = (
|
||||
rule: CustomRule | MachineLearningRule | ThresholdRule | ThreatIndicatorRule
|
||||
) => {
|
||||
export const fillAboutRule = (rule: RuleCreateProps) => {
|
||||
cy.get(RULE_NAME_INPUT).clear({ force: true }).type(rule.name, { force: true });
|
||||
cy.get(RULE_DESCRIPTION_INPUT).clear({ force: true }).type(rule.description, { force: true });
|
||||
if (rule.severity) {
|
||||
fillSeverity(rule.severity);
|
||||
}
|
||||
if (rule.riskScore) {
|
||||
fillRiskScore(rule.riskScore);
|
||||
if (rule.risk_score) {
|
||||
fillRiskScore(rule.risk_score);
|
||||
}
|
||||
if (rule.tags) {
|
||||
fillRuleTags(rule.tags);
|
||||
}
|
||||
cy.get(ADVANCED_SETTINGS_BTN).click({ force: true });
|
||||
|
||||
if (rule.referenceUrls) {
|
||||
fillReferenceUrls(rule.referenceUrls);
|
||||
if (rule.references) {
|
||||
fillReferenceUrls(rule.references);
|
||||
}
|
||||
|
||||
if (rule.falsePositivesExamples) {
|
||||
fillFalsePositiveExamples(rule.falsePositivesExamples);
|
||||
if (rule.false_positives) {
|
||||
fillFalsePositiveExamples(rule.false_positives);
|
||||
}
|
||||
|
||||
if (rule.mitre) {
|
||||
fillMitre(rule.mitre);
|
||||
if (rule.threat) {
|
||||
fillMitre(rule.threat);
|
||||
}
|
||||
if (rule.note) {
|
||||
fillNote(rule.note);
|
||||
|
@ -176,28 +181,31 @@ export const fillNote = (note: string = ruleFields.investigationGuide) => {
|
|||
return note;
|
||||
};
|
||||
|
||||
export const fillMitre = (mitreAttacks: Mitre[]) => {
|
||||
export const fillMitre = (mitreAttacks: Threat[]) => {
|
||||
let techniqueIndex = 0;
|
||||
let subtechniqueInputIndex = 0;
|
||||
mitreAttacks.forEach((mitre, tacticIndex) => {
|
||||
cy.get(MITRE_ATTACK_TACTIC_DROPDOWN).eq(tacticIndex).click({ force: true });
|
||||
cy.contains(MITRE_TACTIC, mitre.tactic).click();
|
||||
cy.contains(MITRE_TACTIC, `${mitre.tactic.name} (${mitre.tactic.id})`).click();
|
||||
|
||||
mitre.techniques.forEach((technique) => {
|
||||
cy.get(MITRE_ATTACK_ADD_TECHNIQUE_BUTTON).eq(tacticIndex).click({ force: true });
|
||||
cy.get(MITRE_ATTACK_TECHNIQUE_DROPDOWN).eq(techniqueIndex).click({ force: true });
|
||||
cy.contains(MITRE_TACTIC, technique.name).click();
|
||||
|
||||
technique.subtechniques.forEach((subtechnique) => {
|
||||
cy.get(MITRE_ATTACK_ADD_SUBTECHNIQUE_BUTTON).eq(techniqueIndex).click({ force: true });
|
||||
cy.get(MITRE_ATTACK_SUBTECHNIQUE_DROPDOWN)
|
||||
.eq(subtechniqueInputIndex)
|
||||
.click({ force: true });
|
||||
cy.contains(MITRE_TACTIC, subtechnique).click();
|
||||
subtechniqueInputIndex++;
|
||||
if (mitre.technique) {
|
||||
mitre.technique.forEach((technique) => {
|
||||
cy.get(MITRE_ATTACK_ADD_TECHNIQUE_BUTTON).eq(tacticIndex).click({ force: true });
|
||||
cy.get(MITRE_ATTACK_TECHNIQUE_DROPDOWN).eq(techniqueIndex).click({ force: true });
|
||||
cy.contains(MITRE_TACTIC, `${technique.name} (${technique.id})`).click();
|
||||
if (technique.subtechnique) {
|
||||
technique.subtechnique.forEach((subtechnique) => {
|
||||
cy.get(MITRE_ATTACK_ADD_SUBTECHNIQUE_BUTTON).eq(techniqueIndex).click({ force: true });
|
||||
cy.get(MITRE_ATTACK_SUBTECHNIQUE_DROPDOWN)
|
||||
.eq(subtechniqueInputIndex)
|
||||
.click({ force: true });
|
||||
cy.contains(MITRE_TACTIC, `${subtechnique.name} (${subtechnique.id})`).click();
|
||||
subtechniqueInputIndex++;
|
||||
});
|
||||
techniqueIndex++;
|
||||
}
|
||||
});
|
||||
techniqueIndex++;
|
||||
});
|
||||
}
|
||||
|
||||
cy.get(MITRE_ATTACK_ADD_TACTIC_BUTTON).click({ force: true });
|
||||
});
|
||||
|
@ -260,7 +268,7 @@ export const fillSeverity = (severity: string = ruleFields.ruleSeverity) => {
|
|||
return severity;
|
||||
};
|
||||
|
||||
export const fillRiskScore = (riskScore: string = ruleFields.riskScore.toString()) => {
|
||||
export const fillRiskScore = (riskScore: number = ruleFields.riskScore) => {
|
||||
cy.get(DEFAULT_RISK_SCORE_INPUT).type(`{selectall}${riskScore}`, { force: true });
|
||||
return riskScore;
|
||||
};
|
||||
|
@ -280,37 +288,40 @@ export const fillReferenceUrls = (referenceUrls: string[] = ruleFields.reference
|
|||
return referenceUrls;
|
||||
};
|
||||
|
||||
export const fillAboutRuleAndContinue = (
|
||||
rule: CustomRule | MachineLearningRule | ThresholdRule | ThreatIndicatorRule
|
||||
) => {
|
||||
export const fillAboutRuleAndContinue = (rule: RuleCreateProps) => {
|
||||
fillAboutRule(rule);
|
||||
getAboutContinueButton().should('exist').click({ force: true });
|
||||
};
|
||||
|
||||
export const fillAboutRuleWithOverrideAndContinue = (rule: OverrideRule) => {
|
||||
export const fillAboutRuleWithOverrideAndContinue = (rule: RuleCreateProps) => {
|
||||
cy.get(RULE_NAME_INPUT).type(rule.name, { force: true });
|
||||
cy.get(RULE_DESCRIPTION_INPUT).type(rule.description, { force: true });
|
||||
|
||||
cy.get(SEVERITY_MAPPING_OVERRIDE_OPTION).click();
|
||||
rule.severityOverride.forEach((severity, i) => {
|
||||
cy.get(SEVERITY_OVERRIDE_ROW)
|
||||
.eq(i)
|
||||
.within(() => {
|
||||
cy.get(COMBO_BOX_INPUT).eq(0).type(`${severity.sourceField}{enter}`);
|
||||
cy.get(COMBO_BOX_INPUT).eq(1).type(`${severity.sourceValue}{enter}`);
|
||||
});
|
||||
});
|
||||
if (rule.severity_mapping) {
|
||||
rule.severity_mapping.forEach((severity, i) => {
|
||||
cy.get(SEVERITY_OVERRIDE_ROW)
|
||||
.eq(i)
|
||||
.within(() => {
|
||||
cy.get(COMBO_BOX_INPUT).eq(0).type(`${severity.field}{enter}`);
|
||||
cy.get(COMBO_BOX_INPUT).eq(1).type(`${severity.value}{enter}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (rule.severity) {
|
||||
fillSeverity(rule.severity);
|
||||
}
|
||||
|
||||
cy.get(RISK_MAPPING_OVERRIDE_OPTION).click();
|
||||
cy.get(RISK_OVERRIDE).within(() => {
|
||||
cy.get(COMBO_BOX_INPUT).type(`${rule.riskOverride}{enter}`);
|
||||
});
|
||||
if (rule.risk_score_mapping) {
|
||||
const field = rule.risk_score_mapping[0].field;
|
||||
cy.get(RISK_OVERRIDE).within(() => {
|
||||
cy.get(COMBO_BOX_INPUT).type(`${field}{enter}`);
|
||||
});
|
||||
}
|
||||
|
||||
cy.get(DEFAULT_RISK_SCORE_INPUT).type(`{selectall}${rule.riskScore}`, { force: true });
|
||||
cy.get(DEFAULT_RISK_SCORE_INPUT).type(`{selectall}${rule.risk_score}`, { force: true });
|
||||
|
||||
if (rule.tags) {
|
||||
fillRuleTags(rule.tags);
|
||||
|
@ -318,45 +329,30 @@ export const fillAboutRuleWithOverrideAndContinue = (rule: OverrideRule) => {
|
|||
|
||||
cy.get(ADVANCED_SETTINGS_BTN).click({ force: true });
|
||||
|
||||
if (rule.referenceUrls) {
|
||||
fillReferenceUrls(rule.referenceUrls);
|
||||
if (rule.references) {
|
||||
fillReferenceUrls(rule.references);
|
||||
}
|
||||
if (rule.falsePositivesExamples) {
|
||||
fillFalsePositiveExamples(rule.falsePositivesExamples);
|
||||
if (rule.false_positives) {
|
||||
fillFalsePositiveExamples(rule.false_positives);
|
||||
}
|
||||
if (rule.mitre) {
|
||||
fillMitre(rule.mitre);
|
||||
if (rule.threat) {
|
||||
fillMitre(rule.threat);
|
||||
}
|
||||
if (rule.note) {
|
||||
fillNote(rule.note);
|
||||
}
|
||||
|
||||
cy.get(RULE_NAME_OVERRIDE).within(() => {
|
||||
cy.get(COMBO_BOX_INPUT).type(`${rule.nameOverride}{enter}`);
|
||||
cy.get(COMBO_BOX_INPUT).type(`${rule.rule_name_override}{enter}`);
|
||||
});
|
||||
|
||||
cy.get(RULE_TIMESTAMP_OVERRIDE).within(() => {
|
||||
cy.get(COMBO_BOX_INPUT).type(`${rule.timestampOverride}{enter}`);
|
||||
cy.get(COMBO_BOX_INPUT).type(`${rule.timestamp_override}{enter}`);
|
||||
});
|
||||
|
||||
getAboutContinueButton().should('exist').click({ force: true });
|
||||
};
|
||||
|
||||
const fillCustomQuery = (rule: CustomRule | OverrideRule) => {
|
||||
if (rule.timeline?.id) {
|
||||
cy.get(IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK).click();
|
||||
cy.get(TIMELINE(rule.timeline.id)).click();
|
||||
cy.get(CUSTOM_QUERY_INPUT).should('have.value', rule.customQuery);
|
||||
if (rule.dataSource.type === 'indexPatterns') {
|
||||
removeAlertsIndex();
|
||||
}
|
||||
} else {
|
||||
cy.get(CUSTOM_QUERY_INPUT)
|
||||
.first()
|
||||
.type(rule.customQuery || '');
|
||||
}
|
||||
};
|
||||
|
||||
// called after import rule from saved timeline
|
||||
// if alerts index is created, it is included in the timeline
|
||||
// to be consistent in multiple test runs, remove it if it's there
|
||||
|
@ -372,24 +368,31 @@ export const continueWithNextSection = () => {
|
|||
cy.get(CONTINUE_BUTTON).should('exist').click();
|
||||
};
|
||||
|
||||
export const fillDefineCustomRuleAndContinue = (rule: CustomRule | OverrideRule) => {
|
||||
if (rule.dataSource.type === 'dataView') {
|
||||
export const fillDefineCustomRuleAndContinue = (rule: QueryRuleCreateProps) => {
|
||||
if (rule.data_view_id !== undefined) {
|
||||
cy.get(DATA_VIEW_OPTION).click();
|
||||
cy.get(DATA_VIEW_COMBO_BOX).type(`${rule.dataSource.dataView}{enter}`);
|
||||
cy.get(DATA_VIEW_COMBO_BOX).type(`${rule.data_view_id}{enter}`);
|
||||
}
|
||||
fillCustomQuery(rule);
|
||||
cy.get(CUSTOM_QUERY_INPUT)
|
||||
.first()
|
||||
.type(rule.query || '');
|
||||
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });
|
||||
cy.get(CUSTOM_QUERY_INPUT).should('not.exist');
|
||||
};
|
||||
|
||||
export const fillScheduleRuleAndContinue = (rule: CustomRule | MachineLearningRule) => {
|
||||
if (rule.runsEvery) {
|
||||
cy.get(RUNS_EVERY_INTERVAL).type('{selectall}').type(rule.runsEvery.interval);
|
||||
cy.get(RUNS_EVERY_TIME_TYPE).select(rule.runsEvery.timeType);
|
||||
export const fillScheduleRuleAndContinue = (rule: RuleCreateProps) => {
|
||||
if (rule.interval) {
|
||||
const intervalNumber = rule.interval.slice(0, rule.interval.length - 1);
|
||||
const intervalType = rule.interval.charAt(rule.interval.length - 1);
|
||||
cy.get(RUNS_EVERY_INTERVAL).type('{selectall}').type(intervalNumber);
|
||||
cy.get(RUNS_EVERY_TIME_TYPE).select(intervalType);
|
||||
}
|
||||
if (rule.lookBack) {
|
||||
cy.get(LOOK_BACK_INTERVAL).type('{selectAll}').type(rule.lookBack.interval);
|
||||
cy.get(LOOK_BACK_TIME_TYPE).select(rule.lookBack.timeType);
|
||||
if (rule.from) {
|
||||
const additionalLookback = getHumanizedDuration(rule.from, rule.interval ?? '5m');
|
||||
const additionalLookbackNumber = additionalLookback.slice(0, additionalLookback.length - 1);
|
||||
const additionalLookbackType = additionalLookback.charAt(additionalLookback.length - 1);
|
||||
cy.get(LOOK_BACK_INTERVAL).type('{selectAll}').type(additionalLookbackNumber);
|
||||
cy.get(LOOK_BACK_TIME_TYPE).select(additionalLookbackType);
|
||||
}
|
||||
cy.get(SCHEDULE_CONTINUE_BUTTON).click({ force: true });
|
||||
};
|
||||
|
@ -401,55 +404,55 @@ export const fillFrom = (from: RuleIntervalFrom = ruleFields.ruleIntervalFrom) =
|
|||
cy.get(LOOK_BACK_TIME_TYPE).select(type);
|
||||
};
|
||||
|
||||
export const fillRuleAction = (rule: CustomRule) => {
|
||||
if (rule.actions) {
|
||||
cy.get(ACTIONS_THROTTLE_INPUT).select(rule.actions.throttle);
|
||||
rule.actions?.connectors.forEach((connector) => {
|
||||
switch (connector.type) {
|
||||
case 'index':
|
||||
cy.get(INDEX_SELECTOR).click();
|
||||
cy.get(CREATE_ACTION_CONNECTOR_BTN).click();
|
||||
fillIndexConnectorForm(connector);
|
||||
break;
|
||||
case 'email':
|
||||
cy.get(EMAIL_ACTION_BTN).click();
|
||||
cy.get(CREATE_ACTION_CONNECTOR_BTN).click();
|
||||
fillEmailConnectorForm(connector);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
export const fillRuleAction = (actions: Actions) => {
|
||||
cy.get(ACTIONS_THROTTLE_INPUT).select(actions.throttle);
|
||||
actions.connectors.forEach((connector) => {
|
||||
switch (connector.type) {
|
||||
case 'index':
|
||||
cy.get(INDEX_SELECTOR).click();
|
||||
cy.get(CREATE_ACTION_CONNECTOR_BTN).click();
|
||||
fillIndexConnectorForm(connector);
|
||||
break;
|
||||
case 'email':
|
||||
cy.get(EMAIL_ACTION_BTN).click();
|
||||
cy.get(CREATE_ACTION_CONNECTOR_BTN).click();
|
||||
fillEmailConnectorForm(connector);
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRule) => {
|
||||
export const fillDefineThresholdRuleAndContinue = (rule: ThresholdRuleCreateProps) => {
|
||||
const thresholdField = 0;
|
||||
const threshold = 1;
|
||||
|
||||
const typeThresholdField = ($el: Cypress.ObjectLike) =>
|
||||
cy.wrap($el).type(rule.thresholdField, { delay: 35 });
|
||||
cy
|
||||
.wrap($el)
|
||||
.type(isArray(rule.threshold.field) ? rule.threshold.field[0] : rule.threshold.field, {
|
||||
delay: 35,
|
||||
});
|
||||
|
||||
fillCustomQuery(rule);
|
||||
cy.get(CUSTOM_QUERY_INPUT)
|
||||
.first()
|
||||
.type(rule.query || '');
|
||||
cy.get(THRESHOLD_INPUT_AREA)
|
||||
.find(INPUT)
|
||||
.then((inputs) => {
|
||||
cy.wrap(inputs[thresholdField]).click();
|
||||
cy.wrap(inputs[thresholdField]).pipe(typeThresholdField);
|
||||
cy.get(EUI_FILTER_SELECT_ITEM).click({ force: true });
|
||||
cy.wrap(inputs[threshold]).clear().type(rule.threshold);
|
||||
cy.wrap(inputs[threshold]).clear().type(`${rule.threshold.value}`);
|
||||
});
|
||||
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });
|
||||
|
||||
cy.get(CUSTOM_QUERY_INPUT).should('not.exist');
|
||||
};
|
||||
|
||||
export const fillDefineEqlRuleAndContinue = (rule: CustomRule) => {
|
||||
if (rule.customQuery == null) {
|
||||
throw new TypeError('The rule custom query should never be undefined or null ');
|
||||
}
|
||||
|
||||
export const fillDefineEqlRuleAndContinue = (rule: EqlRuleCreateProps) => {
|
||||
cy.get(RULES_CREATION_FORM).find(EQL_QUERY_INPUT).should('exist');
|
||||
cy.get(RULES_CREATION_FORM).find(EQL_QUERY_INPUT).should('be.visible');
|
||||
cy.get(RULES_CREATION_FORM).find(EQL_QUERY_INPUT).type(rule.customQuery);
|
||||
cy.get(RULES_CREATION_FORM).find(EQL_QUERY_INPUT).type(rule.query);
|
||||
cy.get(RULES_CREATION_FORM).find(EQL_QUERY_VALIDATION_SPINNER).should('not.exist');
|
||||
cy.get(RULES_CREATION_PREVIEW_BUTTON).should('not.be.disabled').click({ force: true });
|
||||
cy.get(RULES_CREATION_PREVIEW_REFRESH_BUTTON).should('not.be.disabled').click({ force: true });
|
||||
|
@ -467,18 +470,21 @@ export const fillDefineEqlRuleAndContinue = (rule: CustomRule) => {
|
|||
cy.get(`${RULES_CREATION_FORM} ${EQL_QUERY_INPUT}`).should('not.exist');
|
||||
};
|
||||
|
||||
export const fillDefineNewTermsRuleAndContinue = (rule: NewTermsRule) => {
|
||||
fillCustomQuery(rule);
|
||||
cy.get(NEW_TERMS_INPUT_AREA).find(INPUT).click().type(rule.newTermsFields[0], { delay: 35 });
|
||||
export const fillDefineNewTermsRuleAndContinue = (rule: NewTermsRuleCreateProps) => {
|
||||
cy.get(CUSTOM_QUERY_INPUT)
|
||||
.first()
|
||||
.type(rule.query || '');
|
||||
cy.get(NEW_TERMS_INPUT_AREA).find(INPUT).click().type(rule.new_terms_fields[0], { delay: 35 });
|
||||
cy.get(EUI_FILTER_SELECT_ITEM).click({ force: true });
|
||||
cy.focused().type('{esc}'); // Close combobox dropdown so next inputs can be interacted with
|
||||
const historySize = convertHistoryStartToSize(rule.history_window_start);
|
||||
const historySizeNumber = historySize.slice(0, historySize.length - 1);
|
||||
const historySizeType = historySize.charAt(historySize.length - 1);
|
||||
cy.get(NEW_TERMS_INPUT_AREA)
|
||||
.find(NEW_TERMS_HISTORY_SIZE)
|
||||
.type('{selectAll}')
|
||||
.type(rule.historyWindowSize.interval);
|
||||
cy.get(NEW_TERMS_INPUT_AREA)
|
||||
.find(NEW_TERMS_HISTORY_TIME_TYPE)
|
||||
.select(rule.historyWindowSize.timeType);
|
||||
.type(historySizeNumber);
|
||||
cy.get(NEW_TERMS_INPUT_AREA).find(NEW_TERMS_HISTORY_TIME_TYPE).select(historySizeType);
|
||||
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });
|
||||
|
||||
cy.get(CUSTOM_QUERY_INPUT).should('not.exist');
|
||||
|
@ -603,21 +609,24 @@ export const getCustomQueryInvalidationText = () => cy.contains(CUSTOM_QUERY_REQ
|
|||
* Fills in the define indicator match rules and then presses the continue button
|
||||
* @param rule The rule to use to fill in everything
|
||||
*/
|
||||
export const fillDefineIndicatorMatchRuleAndContinue = (rule: ThreatIndicatorRule) => {
|
||||
if (rule.dataSource.type === 'indexPatterns') {
|
||||
fillIndexAndIndicatorIndexPattern(rule.dataSource.index, rule.indicatorIndexPattern);
|
||||
export const fillDefineIndicatorMatchRuleAndContinue = (rule: ThreatMatchRuleCreateProps) => {
|
||||
if (rule.index) {
|
||||
fillIndexAndIndicatorIndexPattern(rule.index, rule.threat_index);
|
||||
}
|
||||
fillIndicatorMatchRow({
|
||||
indexField: rule.indicatorMappingField,
|
||||
indicatorIndexField: rule.indicatorIndexField,
|
||||
indexField: rule.threat_mapping[0].entries[0].field,
|
||||
indicatorIndexField: rule.threat_mapping[0].entries[0].value,
|
||||
});
|
||||
getCustomIndicatorQueryInput().type('{selectall}{enter}*:*');
|
||||
getDefineContinueButton().should('exist').click({ force: true });
|
||||
cy.get(CUSTOM_QUERY_INPUT).should('not.exist');
|
||||
};
|
||||
|
||||
export const fillDefineMachineLearningRuleAndContinue = (rule: MachineLearningRule) => {
|
||||
const text = rule.machineLearningJobs
|
||||
export const fillDefineMachineLearningRuleAndContinue = (rule: MachineLearningRuleCreateProps) => {
|
||||
const jobsAsArray = isArray(rule.machine_learning_job_id)
|
||||
? rule.machine_learning_job_id
|
||||
: [rule.machine_learning_job_id];
|
||||
const text = jobsAsArray
|
||||
.map((machineLearningJob) => `${machineLearningJob}{downArrow}{enter}`)
|
||||
.join('');
|
||||
cy.get(MACHINE_LEARNING_DROPDOWN_INPUT).click({ force: true });
|
||||
|
@ -625,12 +634,9 @@ export const fillDefineMachineLearningRuleAndContinue = (rule: MachineLearningRu
|
|||
|
||||
cy.get(MACHINE_LEARNING_DROPDOWN_INPUT).type('{esc}');
|
||||
|
||||
cy.get(ANOMALY_THRESHOLD_INPUT).type(
|
||||
`{selectall}${getMachineLearningRule().anomalyScoreThreshold}`,
|
||||
{
|
||||
force: true,
|
||||
}
|
||||
);
|
||||
cy.get(ANOMALY_THRESHOLD_INPUT).type(`{selectall}${rule.anomaly_threshold}`, {
|
||||
force: true,
|
||||
});
|
||||
getDefineContinueButton().should('exist').click({ force: true });
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { HOSTS_URL } from '../urls/navigation';
|
|||
import { waitForPage } from './login';
|
||||
import { openTimelineUsingToggle } from './security_main';
|
||||
import { DEFAULT_ALERTS_INDEX } from '../../common/constants';
|
||||
import { createCustomRuleEnabled } from './api_calls/rules';
|
||||
import { createRule } from './api_calls/rules';
|
||||
import { getNewRule } from '../objects/rule';
|
||||
|
||||
export const openSourcerer = (sourcererScope?: string) => {
|
||||
|
@ -148,6 +148,6 @@ const refreshUntilAlertsIndexExists = async () => {
|
|||
};
|
||||
|
||||
export const waitForAlertsIndexToExist = () => {
|
||||
createCustomRuleEnabled(getNewRule(), '1', 100);
|
||||
createRule({ ...getNewRule(), rule_id: '1', max_signals: 100 });
|
||||
refreshUntilAlertsIndexExists();
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"path": "../tsconfig.json",
|
||||
"force": true
|
||||
},
|
||||
"@kbn/rison"
|
||||
"@kbn/rison",
|
||||
"@kbn/datemath"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -555,6 +555,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
onChange={(id: string) => {
|
||||
groupByRadioSelection.setValue(id);
|
||||
}}
|
||||
data-test-subj="groupByDurationOptions"
|
||||
/>
|
||||
),
|
||||
[license, groupByFields]
|
||||
|
@ -867,7 +868,10 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
</>
|
||||
)}
|
||||
|
||||
<RuleTypeEuiFormRow $isVisible={isQueryRule(ruleType)}>
|
||||
<RuleTypeEuiFormRow
|
||||
$isVisible={isQueryRule(ruleType)}
|
||||
data-test-subj="alertSuppressionInput"
|
||||
>
|
||||
<UseField
|
||||
path="groupByFields"
|
||||
component={GroupByFields}
|
||||
|
@ -879,7 +883,10 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
|
|||
}}
|
||||
/>
|
||||
</RuleTypeEuiFormRow>
|
||||
<RuleTypeEuiFormRow $isVisible={isQueryRule(ruleType)}>
|
||||
<RuleTypeEuiFormRow
|
||||
$isVisible={isQueryRule(ruleType)}
|
||||
data-test-subj="alertSuppressionDuration"
|
||||
>
|
||||
<UseMultiFields
|
||||
fields={{
|
||||
groupByRadioSelection: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue