mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Detection Engine][Cypress] Reenable and reorganize some detection_alerts and data_sources tests (#168426)
## Summary #### Code update: `/detection_engine/routes/signals/set_alert_tags_route.ts` - When enabling the alert tags cypress test, noticed it was failing as the tag updates did not show in the UI until a few seconds later upon a second refresh. I was able to recreate this locally on serverless, not on ESS. I updated the alerts tag route to include `refresh: true` and that seemed to fix this issue. - `/detection_engine/routes/signals/open_close_signals_route.ts` - When testing on serverless, alert status was stale after update. Confirmed this with tests that were failing for ESS. Upon updating route to use `refresh: true`, tests began passing and could see expected behavior. This may make the call a bit heavier so we will want to see if there are any performance impacts.
This commit is contained in:
parent
a9a8c96d95
commit
6d3449162d
26 changed files with 1051 additions and 989 deletions
|
@ -63,7 +63,7 @@ steps:
|
|||
queue: n2-4-spot
|
||||
depends_on: build
|
||||
timeout_in_minutes: 60
|
||||
parallelism: 2
|
||||
parallelism: 4
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: '*'
|
||||
|
|
5
.github/CODEOWNERS
vendored
5
.github/CODEOWNERS
vendored
|
@ -1159,6 +1159,7 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
/x-pack/plugins/security_solution/common/types/timeline @elastic/security-threat-hunting-investigations
|
||||
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/investigations @elastic/security-threat-hunting-investigations
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/sourcerer/sourcerer_timeline.cy.ts @elastic/security-threat-hunting-investigations
|
||||
|
||||
/x-pack/plugins/security_solution/public/common/components/alerts_viewer @elastic/security-threat-hunting-investigations
|
||||
/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_action @elastic/security-threat-hunting-investigations
|
||||
|
@ -1297,8 +1298,8 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib
|
|||
/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals @elastic/security-detection-engine
|
||||
/x-pack/plugins/security_solution/server/lib/sourcerer @elastic/security-detection-engine
|
||||
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/data_sources @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_alerts @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/sourcerer @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_actions @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation @elastic/security-detection-engine
|
||||
/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_edit @elastic/security-detection-engine
|
||||
|
|
|
@ -131,7 +131,7 @@ const updateSignalsStatusByIds = async (
|
|||
) =>
|
||||
esClient.updateByQuery({
|
||||
index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`,
|
||||
refresh: false,
|
||||
refresh: true,
|
||||
body: {
|
||||
script: getUpdateSignalStatusScript(status),
|
||||
query: {
|
||||
|
@ -158,7 +158,7 @@ const updateSignalsStatusByQuery = async (
|
|||
esClient.updateByQuery({
|
||||
index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`,
|
||||
conflicts: options.conflicts,
|
||||
refresh: false,
|
||||
refresh: true,
|
||||
body: {
|
||||
script: getUpdateSignalStatusScript(status),
|
||||
query: {
|
||||
|
|
|
@ -100,7 +100,7 @@ export const setAlertTagsRoute = (router: SecuritySolutionPluginRouter) => {
|
|||
try {
|
||||
const body = await esClient.updateByQuery({
|
||||
index: `${DEFAULT_ALERTS_INDEX}-${spaceId}`,
|
||||
refresh: false,
|
||||
refresh: true,
|
||||
body: {
|
||||
script: painlessScript,
|
||||
query: {
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { login } from '../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../tasks/navigation';
|
||||
import { openTimelineUsingToggle } from '../../tasks/security_main';
|
||||
import { openTimelineFieldsBrowser, populateTimeline } from '../../tasks/timeline';
|
||||
|
||||
import { hostsUrl, ALERTS_URL } from '../../urls/navigation';
|
||||
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { refreshPage } from '../../tasks/security_header';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { createField } from '../../tasks/create_runtime_field';
|
||||
import { openAlertsFieldBrowser } from '../../tasks/alerts';
|
||||
import { deleteRuntimeField } from '../../tasks/sourcerer';
|
||||
import { GET_DATA_GRID_HEADER } from '../../screens/common/data_grid';
|
||||
import { GET_TIMELINE_HEADER } from '../../screens/timeline';
|
||||
|
||||
const alertRunTimeField = 'field.name.alert.page';
|
||||
const timelineRuntimeField = 'field.name.timeline';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe(
|
||||
'Create DataView runtime field',
|
||||
{ tags: ['@ess', '@serverless', '@brokenInServerless'] },
|
||||
() => {
|
||||
before(() => {
|
||||
deleteRuntimeField('security-solution-default', alertRunTimeField);
|
||||
deleteRuntimeField('security-solution-default', timelineRuntimeField);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
it('adds field to alert table', () => {
|
||||
visitWithTimeRange(ALERTS_URL);
|
||||
createRule(getNewRule());
|
||||
refreshPage();
|
||||
waitForAlertsToPopulate();
|
||||
openAlertsFieldBrowser();
|
||||
createField(alertRunTimeField);
|
||||
cy.get(GET_DATA_GRID_HEADER(alertRunTimeField)).should('exist');
|
||||
});
|
||||
|
||||
it('adds field to timeline', () => {
|
||||
visitWithTimeRange(hostsUrl('allHosts'));
|
||||
openTimelineUsingToggle();
|
||||
populateTimeline();
|
||||
openTimelineFieldsBrowser();
|
||||
|
||||
createField(timelineRuntimeField);
|
||||
cy.get(GET_TIMELINE_HEADER(timelineRuntimeField)).should('exist');
|
||||
});
|
||||
}
|
||||
);
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { DEFAULT_INDEX_PATTERN } from '@kbn/security-solution-plugin/common/constants';
|
||||
|
||||
import { login, loginWithUser } from '../../tasks/login';
|
||||
import { visitWithTimeRange, visitWithUser } from '../../tasks/navigation';
|
||||
|
||||
import { hostsUrl } from '../../urls/navigation';
|
||||
import {
|
||||
addIndexToDefault,
|
||||
deselectSourcererOptions,
|
||||
isDataViewSelection,
|
||||
isHostsStatValue,
|
||||
isKibanaDataViewOption,
|
||||
isNotSourcererSelection,
|
||||
isSourcererOptions,
|
||||
isSourcererSelection,
|
||||
openAdvancedSettings,
|
||||
openDataViewSelection,
|
||||
openSourcerer,
|
||||
resetSourcerer,
|
||||
saveSourcerer,
|
||||
} from '../../tasks/sourcerer';
|
||||
import { postDataView } from '../../tasks/common';
|
||||
import { createUsersAndRoles, secReadCasesAll, secReadCasesAllUser } from '../../tasks/privileges';
|
||||
import { TOASTER } from '../../screens/configure_cases';
|
||||
import { SOURCERER } from '../../screens/sourcerer';
|
||||
|
||||
const usersToCreate = [secReadCasesAllUser];
|
||||
const rolesToCreate = [secReadCasesAll];
|
||||
const siemDataViewTitle = 'Security Default Data View';
|
||||
const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*'];
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe('Sourcerer', { tags: ['@ess', '@serverless', '@skipInServerless'] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
dataViews.forEach((dataView: string) => postDataView(dataView));
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe('permissions', { tags: ['@ess', '@brokenInServerless'] }, () => {
|
||||
before(() => {
|
||||
createUsersAndRoles(usersToCreate, rolesToCreate);
|
||||
});
|
||||
it(`role(s) ${secReadCasesAllUser.roles.join()} shows error when user does not have permissions`, () => {
|
||||
loginWithUser(secReadCasesAllUser);
|
||||
visitWithUser(hostsUrl('allHosts'), secReadCasesAllUser);
|
||||
cy.get(TOASTER).should('have.text', 'Write role required to generate data');
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/165766
|
||||
describe('Default scope', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
login();
|
||||
visitWithTimeRange(hostsUrl('allHosts'));
|
||||
});
|
||||
|
||||
it('correctly loads SIEM data view', () => {
|
||||
openSourcerer();
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*'));
|
||||
});
|
||||
|
||||
describe('Modified badge', () => {
|
||||
it('Selecting new data view does not add a modified badge', () => {
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
openDataViewSelection();
|
||||
isKibanaDataViewOption(dataViews);
|
||||
cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle);
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
});
|
||||
|
||||
it('shows modified badge when index patterns change and removes when reset', () => {
|
||||
openSourcerer();
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
openAdvancedSettings();
|
||||
const patterns = dataViews[1].split(',');
|
||||
deselectSourcererOptions([patterns[0]]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`exist`);
|
||||
resetSourcerer();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
});
|
||||
});
|
||||
|
||||
it('disables save when no patterns are selected', () => {
|
||||
openSourcerer();
|
||||
openAdvancedSettings();
|
||||
cy.get(SOURCERER.saveButton).should('be.enabled');
|
||||
deselectSourcererOptions(['auditbeat-*']);
|
||||
cy.get(SOURCERER.saveButton).should('be.disabled');
|
||||
});
|
||||
|
||||
it(
|
||||
'adds a pattern to the default index and correctly filters out auditbeat-*',
|
||||
{ tags: '@brokenInServerless' },
|
||||
() => {
|
||||
openSourcerer();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isNotSourcererSelection('*beat*');
|
||||
addIndexToDefault('*beat*');
|
||||
isHostsStatValue('1');
|
||||
openSourcerer();
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection('*beat*');
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
DEFAULT_ALERTS_INDEX,
|
||||
DEFAULT_INDEX_PATTERN,
|
||||
} from '@kbn/security-solution-plugin/common/constants';
|
||||
|
||||
import { login } from '../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../tasks/navigation';
|
||||
|
||||
import { TIMELINES_URL } from '../../urls/navigation';
|
||||
import {
|
||||
clickAlertCheckbox,
|
||||
deselectSourcererOptions,
|
||||
isDataViewSelection,
|
||||
isKibanaDataViewOption,
|
||||
isNotSourcererOption,
|
||||
isNotSourcererSelection,
|
||||
isSourcererOptions,
|
||||
isSourcererSelection,
|
||||
openAdvancedSettings,
|
||||
openDataViewSelection,
|
||||
openSourcerer,
|
||||
refreshUntilAlertsIndexExists,
|
||||
resetSourcerer,
|
||||
saveSourcerer,
|
||||
} from '../../tasks/sourcerer';
|
||||
import { openTimelineUsingToggle } from '../../tasks/security_main';
|
||||
import { SOURCERER } from '../../screens/sourcerer';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { getTimeline, getTimelineModifiedSourcerer } from '../../objects/timeline';
|
||||
import { closeTimeline, openTimelineById } from '../../tasks/timeline';
|
||||
|
||||
const siemDataViewTitle = 'Security Default Data View';
|
||||
const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*'];
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe('Timeline scope', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
login();
|
||||
visitWithTimeRange(TIMELINES_URL);
|
||||
});
|
||||
|
||||
it('correctly loads SIEM data view', () => {
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*'));
|
||||
isNotSourcererOption(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
});
|
||||
|
||||
describe('Modified badge', () => {
|
||||
it('Selecting new data view does not add a modified badge', () => {
|
||||
openTimelineUsingToggle();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
openDataViewSelection();
|
||||
isKibanaDataViewOption(dataViews);
|
||||
cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle);
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
});
|
||||
|
||||
it('shows modified badge when index patterns change and removes when reset', () => {
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
openAdvancedSettings();
|
||||
const patterns = dataViews[1].split(',');
|
||||
deselectSourcererOptions([patterns[0]]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`exist`);
|
||||
resetSourcerer();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
});
|
||||
});
|
||||
describe('Alerts checkbox', () => {
|
||||
before(() => {
|
||||
login();
|
||||
createTimeline(getTimeline()).then((response) =>
|
||||
cy.wrap(response.body.data.persistTimeline.timeline.savedObjectId).as('timelineId')
|
||||
);
|
||||
createTimeline(getTimelineModifiedSourcerer()).then((response) =>
|
||||
cy.wrap(response.body.data.persistTimeline.timeline.savedObjectId).as('auditbeatTimelineId')
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithTimeRange(TIMELINES_URL);
|
||||
refreshUntilAlertsIndexExists();
|
||||
});
|
||||
|
||||
it('Modifies timeline to alerts only, and switches to different saved timeline without issue', function () {
|
||||
openTimelineById(this.timelineId).then(() => {
|
||||
cy.get(SOURCERER.badgeAlerts).should(`not.exist`);
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
clickAlertCheckbox();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeAlerts).should(`exist`);
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
closeTimeline();
|
||||
|
||||
openTimelineById(this.auditbeatTimelineId).then(() => {
|
||||
cy.get(SOURCERER.badgeModified).should(`exist`);
|
||||
cy.get(SOURCERER.badgeAlerts).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const defaultPatterns = [`auditbeat-*`, `${DEFAULT_ALERTS_INDEX}-default`];
|
||||
it('alerts checkbox behaves as expected', () => {
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
defaultPatterns.forEach((pattern) => isSourcererSelection(pattern));
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
dataViews[1]
|
||||
.split(',')
|
||||
.filter((pattern) => pattern !== 'fakebeat-*' && pattern !== 'siem-read*')
|
||||
.forEach((pattern) => isSourcererSelection(pattern));
|
||||
|
||||
clickAlertCheckbox();
|
||||
isNotSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
cy.get(SOURCERER.alertCheckbox).uncheck({ force: true });
|
||||
defaultPatterns.forEach((pattern) => isSourcererSelection(pattern));
|
||||
});
|
||||
|
||||
it('shows alerts badge when index patterns change and removes when reset', () => {
|
||||
clickAlertCheckbox();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeAlerts).should(`exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeAlertsOption).should(`exist`);
|
||||
resetSourcerer();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeAlerts).should(`not.exist`);
|
||||
openSourcerer('timeline');
|
||||
cy.get(SOURCERER.badgeAlertsOption).should(`not.exist`);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { disableExpandableFlyout } from '../../tasks/api_calls/kibana_advanced_settings';
|
||||
import { getNewThreatIndicatorRule, indicatorRuleMatchingDoc } from '../../objects/rule';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { login } from '../../tasks/login';
|
||||
import {
|
||||
JSON_TEXT,
|
||||
TABLE_CELL,
|
||||
TABLE_ROWS,
|
||||
THREAT_DETAILS_VIEW,
|
||||
ENRICHMENT_COUNT_NOTIFICATION,
|
||||
INDICATOR_MATCH_ENRICHMENT_SECTION,
|
||||
INVESTIGATION_TIME_ENRICHMENT_SECTION,
|
||||
THREAT_DETAILS_ACCORDION,
|
||||
} from '../../screens/alerts_details';
|
||||
import { TIMELINE_FIELD } from '../../screens/rule_details';
|
||||
import { expandFirstAlert, setEnrichmentDates, viewThreatIntelTab } from '../../tasks/alerts';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { openJsonView, openThreatIndicatorDetails } from '../../tasks/alerts_details';
|
||||
import { addsFieldsToTimeline, visitRuleDetailsPage } from '../../tasks/rule_details';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe('CTI Enrichment', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
// illegal_argument_exception: unknown setting [index.lifecycle.rollover_alias]
|
||||
cy.task('esArchiverLoad', { archiveName: 'threat_indicator' });
|
||||
cy.task('esArchiverLoad', { archiveName: 'suspicious_source_event' });
|
||||
login();
|
||||
|
||||
disableExpandableFlyout();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'threat_indicator');
|
||||
cy.task('esArchiverUnload', 'suspicious_source_event');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
createRule({ ...getNewThreatIndicatorRule(), rule_id: 'rule_testing', enabled: true }).then(
|
||||
(rule) => visitRuleDetailsPage(rule.body.id)
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
// Skipped: https://github.com/elastic/kibana/issues/162818
|
||||
it.skip('Displays enrichment matched.* fields on the timeline', () => {
|
||||
const expectedFields = {
|
||||
'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>;
|
||||
|
||||
addsFieldsToTimeline('threat.enrichments.matched', fields);
|
||||
|
||||
fields.forEach((field) => {
|
||||
cy.get(TIMELINE_FIELD(field)).should('have.text', expectedFields[field]);
|
||||
});
|
||||
});
|
||||
|
||||
it('Displays persisted enrichments on the JSON view', () => {
|
||||
const expectedEnrichment = [
|
||||
{
|
||||
'indicator.file.hash.md5': ['9b6c3518a91d23ed77504b5416bfb5b3'],
|
||||
'matched.index': ['logs-ti_abusech.malware'],
|
||||
'indicator.file.type': ['elf'],
|
||||
'indicator.file.hash.tlsh': [
|
||||
'6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE',
|
||||
],
|
||||
'feed.name': ['AbuseCH malware'],
|
||||
'indicator.file.hash.ssdeep': [
|
||||
'1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL',
|
||||
],
|
||||
'indicator.file.hash.sha256': [
|
||||
'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
],
|
||||
'indicator.first_seen': ['2021-03-10T08:02:14.000Z'],
|
||||
'matched.field': ['myhash.mysha256'],
|
||||
'indicator.type': ['file'],
|
||||
'matched.type': ['indicator_match_rule'],
|
||||
'matched.id': ['84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f'],
|
||||
'matched.atomic': ['a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3'],
|
||||
'indicator.file.size': [80280],
|
||||
},
|
||||
];
|
||||
|
||||
expandFirstAlert();
|
||||
openJsonView();
|
||||
|
||||
cy.get(JSON_TEXT).then((x) => {
|
||||
const parsed = JSON.parse(x.text());
|
||||
expect(parsed.fields['threat.enrichments']).to.deep.equal(expectedEnrichment);
|
||||
});
|
||||
});
|
||||
|
||||
it('Displays threat indicator details on the threat intel tab', () => {
|
||||
const expectedThreatIndicatorData = [
|
||||
{ field: 'feed.name', value: 'AbuseCH malware' },
|
||||
{ field: 'indicator.file.hash.md5', value: '9b6c3518a91d23ed77504b5416bfb5b3' },
|
||||
{
|
||||
field: 'indicator.file.hash.sha256',
|
||||
value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
},
|
||||
{
|
||||
field: 'indicator.file.hash.ssdeep',
|
||||
value: '1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL',
|
||||
},
|
||||
{
|
||||
field: 'indicator.file.hash.tlsh',
|
||||
value: '6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE',
|
||||
},
|
||||
{ field: 'indicator.file.size', value: '80280' },
|
||||
{ field: 'indicator.file.type', value: 'elf' },
|
||||
{ field: 'indicator.first_seen', value: '2021-03-10T08:02:14.000Z' },
|
||||
{ field: 'indicator.type', value: 'file' },
|
||||
{
|
||||
field: 'matched.atomic',
|
||||
value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
},
|
||||
{ field: 'matched.field', value: 'myhash.mysha256' },
|
||||
{
|
||||
field: 'matched.id',
|
||||
value: '84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f',
|
||||
},
|
||||
{ field: 'matched.index', value: 'logs-ti_abusech.malware' },
|
||||
{ field: 'matched.type', value: 'indicator_match_rule' },
|
||||
];
|
||||
|
||||
expandFirstAlert();
|
||||
openThreatIndicatorDetails();
|
||||
|
||||
cy.get(ENRICHMENT_COUNT_NOTIFICATION).should('have.text', '1');
|
||||
cy.get(THREAT_DETAILS_VIEW).within(() => {
|
||||
cy.get(TABLE_ROWS).should('have.length', expectedThreatIndicatorData.length);
|
||||
expectedThreatIndicatorData.forEach((row, index) => {
|
||||
cy.get(TABLE_ROWS)
|
||||
.eq(index)
|
||||
.within(() => {
|
||||
cy.get(TABLE_CELL).eq(0).should('have.text', row.field);
|
||||
cy.get(TABLE_CELL).eq(1).should('have.text', row.value);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with additional indicators', () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverLoad', { archiveName: 'threat_indicator2' });
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'threat_indicator2');
|
||||
});
|
||||
|
||||
it('Displays matched fields from both indicator match rules and investigation time enrichments on Threat Intel tab', () => {
|
||||
const indicatorMatchRuleEnrichment = {
|
||||
field: 'myhash.mysha256',
|
||||
value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
feedName: 'AbuseCH malware',
|
||||
};
|
||||
const investigationTimeEnrichment = {
|
||||
field: 'source.ip',
|
||||
value: '192.168.1.1',
|
||||
feedName: 'feed_name',
|
||||
};
|
||||
|
||||
expandFirstAlert();
|
||||
viewThreatIntelTab();
|
||||
setEnrichmentDates('08/05/2018 10:00 AM');
|
||||
|
||||
cy.get(`${INDICATOR_MATCH_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`)
|
||||
.should('exist')
|
||||
.should(
|
||||
'have.text',
|
||||
`${indicatorMatchRuleEnrichment.field} ${indicatorMatchRuleEnrichment.value} from ${indicatorMatchRuleEnrichment.feedName}`
|
||||
);
|
||||
|
||||
cy.get(`${INVESTIGATION_TIME_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`)
|
||||
.should('exist')
|
||||
.should(
|
||||
'have.text',
|
||||
`${investigationTimeEnrichment.field} ${investigationTimeEnrichment.value} from ${investigationTimeEnrichment.feedName}`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login } from '../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../tasks/navigation';
|
||||
|
||||
import { ALERTS_URL, TIMELINES_URL } from '../../urls/navigation';
|
||||
import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../screens/alerts';
|
||||
import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timeline';
|
||||
import { selectAlertsHistogram } from '../../tasks/alerts';
|
||||
import { createTimeline } from '../../tasks/timelines';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe(
|
||||
'Ransomware Detection Alerts',
|
||||
{ tags: ['@ess', '@serverless', '@brokenInServerless'] },
|
||||
() => {
|
||||
before(() => {
|
||||
cy.task('esArchiverLoad', {
|
||||
archiveName: 'ransomware_detection',
|
||||
useCreate: true,
|
||||
docsOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ransomware display in Alerts Section', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithTimeRange(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
describe('Alerts table', () => {
|
||||
it('shows Ransomware Alerts', () => {
|
||||
cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Detection Alert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Trend Chart', () => {
|
||||
beforeEach(() => {
|
||||
selectAlertsHistogram();
|
||||
});
|
||||
|
||||
it('shows Ransomware Detection Alert in the trend chart', () => {
|
||||
cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Detection Alert');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/168602
|
||||
describe.skip('Ransomware in Timelines', () => {
|
||||
before(() => {
|
||||
login();
|
||||
visitWithTimeRange(TIMELINES_URL);
|
||||
createTimeline();
|
||||
});
|
||||
|
||||
it('Renders ransomware entries in timelines table', () => {
|
||||
cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}');
|
||||
|
||||
// Wait for grid to load, it should have an analyzer icon
|
||||
cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist');
|
||||
|
||||
cy.get(MESSAGE).should('have.text', 'Ransomware Detection Alert');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
import { login } from '../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../tasks/navigation';
|
||||
|
||||
import { ALERTS_URL, TIMELINES_URL } from '../../urls/navigation';
|
||||
import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../screens/alerts';
|
||||
import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../screens/timeline';
|
||||
import { selectAlertsHistogram } from '../../tasks/alerts';
|
||||
import { createTimeline } from '../../tasks/timelines';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe(
|
||||
'Ransomware Prevention Alerts',
|
||||
{ tags: ['@ess', '@serverless', '@brokenInServerless'] },
|
||||
() => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
cy.task('esArchiverLoad', {
|
||||
archiveName: 'ransomware_prevention',
|
||||
useCreate: true,
|
||||
docsOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'ransomware_prevention');
|
||||
});
|
||||
|
||||
describe('Ransomware display in Alerts Section', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithTimeRange(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
describe('Alerts table', () => {
|
||||
it('shows Ransomware Alerts', () => {
|
||||
cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Prevention Alert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Trend Chart', () => {
|
||||
beforeEach(() => {
|
||||
selectAlertsHistogram();
|
||||
});
|
||||
|
||||
it('shows Ransomware Prevention Alert in the trend chart', () => {
|
||||
cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Prevention Alert');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ransomware in Timelines', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithTimeRange(TIMELINES_URL);
|
||||
|
||||
createTimeline();
|
||||
});
|
||||
|
||||
it('Renders ransomware entries in timelines table', () => {
|
||||
cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}');
|
||||
|
||||
// Wait for grid to load, it should have an analyzer icon
|
||||
cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist');
|
||||
|
||||
cy.get(MESSAGE).should('have.text', 'Ransomware Prevention Alert');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { ALERTS_COUNT, SELECTED_ALERTS } from '../../../screens/alerts';
|
||||
|
||||
import {
|
||||
selectNumberOfAlerts,
|
||||
waitForAlerts,
|
||||
markAcknowledgedFirstAlert,
|
||||
markAlertsAcknowledged,
|
||||
goToAcknowledgedAlerts,
|
||||
closeFirstAlert,
|
||||
closeAlerts,
|
||||
goToClosedAlerts,
|
||||
goToOpenedAlerts,
|
||||
openAlerts,
|
||||
openFirstAlert,
|
||||
} from '../../../tasks/alerts';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visit } from '../../../tasks/navigation';
|
||||
|
||||
import { ALERTS_URL } from '../../../urls/navigation';
|
||||
|
||||
describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' });
|
||||
});
|
||||
|
||||
context('Opening alerts', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
createRule(getNewRule());
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
selectNumberOfAlerts(3);
|
||||
cy.get(SELECTED_ALERTS).should('have.text', `Selected 3 alerts`);
|
||||
closeAlerts();
|
||||
waitForAlerts();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'auditbeat_big');
|
||||
});
|
||||
|
||||
it('can mark a closed alert as open', () => {
|
||||
waitForAlertsToPopulate();
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((numberOfOpenedAlertsText) => {
|
||||
const numberOfOpenedAlerts = parseInt(numberOfOpenedAlertsText, 10);
|
||||
goToClosedAlerts();
|
||||
waitForAlerts();
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
const numberOfAlerts = alertNumberString.split(' ')[0];
|
||||
const numberOfAlertsToBeOpened = 1;
|
||||
|
||||
openFirstAlert();
|
||||
waitForAlerts();
|
||||
|
||||
const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeOpened;
|
||||
cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts);
|
||||
|
||||
goToOpenedAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
cy.get(ALERTS_COUNT).contains(`${numberOfOpenedAlerts + numberOfAlertsToBeOpened}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can bulk open alerts', () => {
|
||||
waitForAlertsToPopulate();
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((numberOfOpenedAlertsText) => {
|
||||
const numberOfOpenedAlerts = parseInt(numberOfOpenedAlertsText, 10);
|
||||
goToClosedAlerts();
|
||||
waitForAlerts();
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
const numberOfAlerts = alertNumberString.split(' ')[0];
|
||||
const numberOfAlertsToBeOpened = 2;
|
||||
const numberOfAlertsToBeSelected = 2;
|
||||
|
||||
selectNumberOfAlerts(numberOfAlertsToBeSelected);
|
||||
cy.get(SELECTED_ALERTS).should(
|
||||
'have.text',
|
||||
`Selected ${numberOfAlertsToBeSelected} alerts`
|
||||
);
|
||||
|
||||
openAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeOpened;
|
||||
cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts);
|
||||
|
||||
goToOpenedAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
cy.get(ALERTS_COUNT).contains(`${numberOfOpenedAlerts + numberOfAlertsToBeOpened}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Marking alerts as acknowledged', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
createRule(getNewRule());
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
it('can mark alert as acknowledged', () => {
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
const numberOfAlerts = alertNumberString.split(' ')[0];
|
||||
const numberOfAlertsToBeMarkedAcknowledged = 1;
|
||||
|
||||
markAcknowledgedFirstAlert();
|
||||
waitForAlerts();
|
||||
const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeMarkedAcknowledged;
|
||||
cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts);
|
||||
|
||||
goToAcknowledgedAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
cy.get(ALERTS_COUNT).contains(`${numberOfAlertsToBeMarkedAcknowledged}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('can bulk mark alerts as acknowledged', () => {
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
const numberOfAlerts = alertNumberString.split(' ')[0];
|
||||
const numberOfAlertsToBeMarkedAcknowledged = 2;
|
||||
const numberOfAlertsToBeSelected = 2;
|
||||
|
||||
selectNumberOfAlerts(numberOfAlertsToBeSelected);
|
||||
|
||||
markAlertsAcknowledged();
|
||||
waitForAlerts();
|
||||
const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeMarkedAcknowledged;
|
||||
cy.get(ALERTS_COUNT).contains(expectedNumberOfAlerts);
|
||||
|
||||
goToAcknowledgedAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
cy.get(ALERTS_COUNT).contains(numberOfAlertsToBeMarkedAcknowledged);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Closing alerts', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteAlertsAndRules();
|
||||
createRule(getNewRule({ rule_id: '1', max_signals: 100 }));
|
||||
visit(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
it('can close an alert', () => {
|
||||
const numberOfAlertsToBeClosed = 1;
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
const numberOfAlerts = alertNumberString.split(' ')[0];
|
||||
cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`);
|
||||
|
||||
selectNumberOfAlerts(numberOfAlertsToBeClosed);
|
||||
|
||||
cy.get(SELECTED_ALERTS).should('have.text', `Selected ${numberOfAlertsToBeClosed} alert`);
|
||||
|
||||
closeFirstAlert();
|
||||
waitForAlerts();
|
||||
|
||||
const expectedNumberOfAlertsAfterClosing = +numberOfAlerts - numberOfAlertsToBeClosed;
|
||||
cy.get(ALERTS_COUNT).contains(expectedNumberOfAlertsAfterClosing);
|
||||
|
||||
goToClosedAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
cy.get(ALERTS_COUNT).contains(numberOfAlertsToBeClosed);
|
||||
});
|
||||
});
|
||||
|
||||
it('can bulk close alerts', () => {
|
||||
const numberOfAlertsToBeClosed = 2;
|
||||
cy.get(ALERTS_COUNT)
|
||||
.invoke('text')
|
||||
.then((alertNumberString) => {
|
||||
const numberOfAlerts = alertNumberString.split(' ')[0];
|
||||
cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`);
|
||||
|
||||
selectNumberOfAlerts(numberOfAlertsToBeClosed);
|
||||
|
||||
cy.get(SELECTED_ALERTS).should(
|
||||
'have.text',
|
||||
`Selected ${numberOfAlertsToBeClosed} alerts`
|
||||
);
|
||||
|
||||
closeAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
const expectedNumberOfAlertsAfterClosing = +numberOfAlerts - numberOfAlertsToBeClosed;
|
||||
cy.get(ALERTS_COUNT).contains(expectedNumberOfAlertsAfterClosing);
|
||||
|
||||
goToClosedAlerts();
|
||||
waitForAlerts();
|
||||
|
||||
cy.get(ALERTS_COUNT).contains(numberOfAlertsToBeClosed);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,28 +5,27 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import {
|
||||
clickAlertTag,
|
||||
openAlertTaggingBulkActionMenu,
|
||||
selectNumberOfAlerts,
|
||||
updateAlertTags,
|
||||
} from '../../tasks/alerts';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../tasks/common';
|
||||
import { login } from '../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../tasks/navigation';
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
|
||||
} from '../../../tasks/alerts';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { cleanKibana, deleteAlertsAndRules } from '../../../tasks/common';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../../tasks/navigation';
|
||||
import { ALERTS_URL } from '../../../urls/navigation';
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
import {
|
||||
ALERTS_TABLE_ROW_LOADER,
|
||||
MIXED_ALERT_TAG,
|
||||
SELECTED_ALERT_TAG,
|
||||
UNSELECTED_ALERT_TAG,
|
||||
} from '../../screens/alerts';
|
||||
} from '../../../screens/alerts';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe('Alert tagging', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
describe('Alert tagging', { tags: ['@ess', '@serverless'] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
cy.task('esArchiverResetKibana');
|
|
@ -7,21 +7,21 @@
|
|||
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
import { RULES_MANAGEMENT_URL } from '../../urls/rules_management';
|
||||
import { ruleDetailsUrl } from '../../urls/rule_details';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { PAGE_TITLE } from '../../screens/common/page';
|
||||
import { ALERTS_URL } from '../../../urls/navigation';
|
||||
import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management';
|
||||
import { ruleDetailsUrl } from '../../../urls/rule_details';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { PAGE_TITLE } from '../../../screens/common/page';
|
||||
|
||||
import { login } from '../../tasks/login';
|
||||
import { visit } from '../../tasks/navigation';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visit } from '../../../tasks/navigation';
|
||||
|
||||
import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { createRule, deleteCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import {
|
||||
getCallOut,
|
||||
NEED_ADMIN_FOR_UPDATE_CALLOUT,
|
||||
waitForCallOutToBeShown,
|
||||
} from '../../tasks/common/callouts';
|
||||
} from '../../../tasks/common/callouts';
|
||||
|
||||
const loadPageAsPlatformEngineerUser = (url: string) => {
|
||||
login(ROLES.soc_manager);
|
||||
|
@ -33,7 +33,6 @@ const waitForPageTitleToBeShown = () => {
|
|||
cy.get(PAGE_TITLE).should('be.visible');
|
||||
};
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539 Does it need to run in Serverless?
|
||||
describe(
|
||||
'Detections > Need Admin Callouts indicating an admin is needed to migrate the alert data set',
|
||||
{ tags: ['@ess', '@skipInServerless'] },
|
|
@ -7,21 +7,21 @@
|
|||
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
import { RULES_MANAGEMENT_URL } from '../../urls/rules_management';
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { PAGE_TITLE } from '../../screens/common/page';
|
||||
import { ALERTS_URL } from '../../../urls/navigation';
|
||||
import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { PAGE_TITLE } from '../../../screens/common/page';
|
||||
|
||||
import { login } from '../../tasks/login';
|
||||
import { visit } from '../../tasks/navigation';
|
||||
import { createRule, deleteCustomRule } from '../../tasks/api_calls/rules';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visit } from '../../../tasks/navigation';
|
||||
import { createRule, deleteCustomRule } from '../../../tasks/api_calls/rules';
|
||||
import {
|
||||
getCallOut,
|
||||
waitForCallOutToBeShown,
|
||||
dismissCallOut,
|
||||
MISSING_PRIVILEGES_CALLOUT,
|
||||
} from '../../tasks/common/callouts';
|
||||
import { ruleDetailsUrl } from '../../urls/rule_details';
|
||||
} from '../../../tasks/common/callouts';
|
||||
import { ruleDetailsUrl } from '../../../urls/rule_details';
|
||||
|
||||
const loadPageAsReadOnlyUser = (url: string) => {
|
||||
login(ROLES.reader);
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { disableExpandableFlyout } from '../../../tasks/api_calls/kibana_advanced_settings';
|
||||
import { getNewThreatIndicatorRule, indicatorRuleMatchingDoc } from '../../../objects/rule';
|
||||
import { cleanKibana } from '../../../tasks/common';
|
||||
import { login } from '../../../tasks/login';
|
||||
import {
|
||||
JSON_TEXT,
|
||||
TABLE_CELL,
|
||||
TABLE_ROWS,
|
||||
THREAT_DETAILS_VIEW,
|
||||
ENRICHMENT_COUNT_NOTIFICATION,
|
||||
INDICATOR_MATCH_ENRICHMENT_SECTION,
|
||||
INVESTIGATION_TIME_ENRICHMENT_SECTION,
|
||||
THREAT_DETAILS_ACCORDION,
|
||||
} from '../../../screens/alerts_details';
|
||||
import { TIMELINE_FIELD } from '../../../screens/rule_details';
|
||||
import { expandFirstAlert, setEnrichmentDates, viewThreatIntelTab } from '../../../tasks/alerts';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { openJsonView, openThreatIndicatorDetails } from '../../../tasks/alerts_details';
|
||||
import { addsFieldsToTimeline, visitRuleDetailsPage } from '../../../tasks/rule_details';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe(
|
||||
'Threat Match Enrichment',
|
||||
{ tags: ['@ess', '@serverless', '@brokenInServerless'] },
|
||||
() => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
// illegal_argument_exception: unknown setting [index.lifecycle.rollover_alias]
|
||||
cy.task('esArchiverLoad', { archiveName: 'threat_indicator' });
|
||||
cy.task('esArchiverLoad', { archiveName: 'suspicious_source_event' });
|
||||
login();
|
||||
|
||||
disableExpandableFlyout();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'threat_indicator');
|
||||
cy.task('esArchiverUnload', 'suspicious_source_event');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
createRule({ ...getNewThreatIndicatorRule(), rule_id: 'rule_testing', enabled: true }).then(
|
||||
(rule) => visitRuleDetailsPage(rule.body.id)
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
// Skipped: https://github.com/elastic/kibana/issues/162818
|
||||
it.skip('Displays enrichment matched.* fields on the timeline', () => {
|
||||
const expectedFields = {
|
||||
'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>;
|
||||
|
||||
addsFieldsToTimeline('threat.enrichments.matched', fields);
|
||||
|
||||
fields.forEach((field) => {
|
||||
cy.get(TIMELINE_FIELD(field)).should('have.text', expectedFields[field]);
|
||||
});
|
||||
});
|
||||
|
||||
it('Displays persisted enrichments on the JSON view', () => {
|
||||
const expectedEnrichment = [
|
||||
{
|
||||
'indicator.file.hash.md5': ['9b6c3518a91d23ed77504b5416bfb5b3'],
|
||||
'matched.index': ['logs-ti_abusech.malware'],
|
||||
'indicator.file.type': ['elf'],
|
||||
'indicator.file.hash.tlsh': [
|
||||
'6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE',
|
||||
],
|
||||
'feed.name': ['AbuseCH malware'],
|
||||
'indicator.file.hash.ssdeep': [
|
||||
'1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL',
|
||||
],
|
||||
'indicator.file.hash.sha256': [
|
||||
'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
],
|
||||
'indicator.first_seen': ['2021-03-10T08:02:14.000Z'],
|
||||
'matched.field': ['myhash.mysha256'],
|
||||
'indicator.type': ['file'],
|
||||
'matched.type': ['indicator_match_rule'],
|
||||
'matched.id': ['84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f'],
|
||||
'matched.atomic': ['a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3'],
|
||||
'indicator.file.size': [80280],
|
||||
},
|
||||
];
|
||||
|
||||
expandFirstAlert();
|
||||
openJsonView();
|
||||
|
||||
cy.get(JSON_TEXT).then((x) => {
|
||||
const parsed = JSON.parse(x.text());
|
||||
expect(parsed.fields['threat.enrichments']).to.deep.equal(expectedEnrichment);
|
||||
});
|
||||
});
|
||||
|
||||
it('Displays threat indicator details on the threat intel tab', () => {
|
||||
const expectedThreatIndicatorData = [
|
||||
{ field: 'feed.name', value: 'AbuseCH malware' },
|
||||
{ field: 'indicator.file.hash.md5', value: '9b6c3518a91d23ed77504b5416bfb5b3' },
|
||||
{
|
||||
field: 'indicator.file.hash.sha256',
|
||||
value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
},
|
||||
{
|
||||
field: 'indicator.file.hash.ssdeep',
|
||||
value: '1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL',
|
||||
},
|
||||
{
|
||||
field: 'indicator.file.hash.tlsh',
|
||||
value: '6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE',
|
||||
},
|
||||
{ field: 'indicator.file.size', value: '80280' },
|
||||
{ field: 'indicator.file.type', value: 'elf' },
|
||||
{ field: 'indicator.first_seen', value: '2021-03-10T08:02:14.000Z' },
|
||||
{ field: 'indicator.type', value: 'file' },
|
||||
{
|
||||
field: 'matched.atomic',
|
||||
value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
},
|
||||
{ field: 'matched.field', value: 'myhash.mysha256' },
|
||||
{
|
||||
field: 'matched.id',
|
||||
value: '84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f',
|
||||
},
|
||||
{ field: 'matched.index', value: 'logs-ti_abusech.malware' },
|
||||
{ field: 'matched.type', value: 'indicator_match_rule' },
|
||||
];
|
||||
|
||||
expandFirstAlert();
|
||||
openThreatIndicatorDetails();
|
||||
|
||||
cy.get(ENRICHMENT_COUNT_NOTIFICATION).should('have.text', '1');
|
||||
cy.get(THREAT_DETAILS_VIEW).within(() => {
|
||||
cy.get(TABLE_ROWS).should('have.length', expectedThreatIndicatorData.length);
|
||||
expectedThreatIndicatorData.forEach((row, index) => {
|
||||
cy.get(TABLE_ROWS)
|
||||
.eq(index)
|
||||
.within(() => {
|
||||
cy.get(TABLE_CELL).eq(0).should('have.text', row.field);
|
||||
cy.get(TABLE_CELL).eq(1).should('have.text', row.value);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with additional indicators', () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverLoad', { archiveName: 'threat_indicator2' });
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'threat_indicator2');
|
||||
});
|
||||
|
||||
it('Displays matched fields from both indicator match rules and investigation time enrichments on Threat Intel tab', () => {
|
||||
const indicatorMatchRuleEnrichment = {
|
||||
field: 'myhash.mysha256',
|
||||
value: 'a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3',
|
||||
feedName: 'AbuseCH malware',
|
||||
};
|
||||
const investigationTimeEnrichment = {
|
||||
field: 'source.ip',
|
||||
value: '192.168.1.1',
|
||||
feedName: 'feed_name',
|
||||
};
|
||||
|
||||
expandFirstAlert();
|
||||
viewThreatIntelTab();
|
||||
setEnrichmentDates('08/05/2018 10:00 AM');
|
||||
|
||||
cy.get(`${INDICATOR_MATCH_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`)
|
||||
.should('exist')
|
||||
.should(
|
||||
'have.text',
|
||||
`${indicatorMatchRuleEnrichment.field} ${indicatorMatchRuleEnrichment.value} from ${indicatorMatchRuleEnrichment.feedName}`
|
||||
);
|
||||
|
||||
cy.get(`${INVESTIGATION_TIME_ENRICHMENT_SECTION} ${THREAT_DETAILS_ACCORDION}`)
|
||||
.should('exist')
|
||||
.should(
|
||||
'have.text',
|
||||
`${investigationTimeEnrichment.field} ${investigationTimeEnrichment.value} from ${investigationTimeEnrichment.feedName}`
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../../tasks/navigation';
|
||||
import { openTimelineUsingToggle } from '../../../tasks/security_main';
|
||||
import { openTimelineFieldsBrowser, populateTimeline } from '../../../tasks/timeline';
|
||||
|
||||
import { hostsUrl, ALERTS_URL } from '../../../urls/navigation';
|
||||
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { refreshPage } from '../../../tasks/security_header';
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
import { createField } from '../../../tasks/create_runtime_field';
|
||||
import { openAlertsFieldBrowser } from '../../../tasks/alerts';
|
||||
import { deleteRuntimeField } from '../../../tasks/sourcerer';
|
||||
import { GET_DATA_GRID_HEADER } from '../../../screens/common/data_grid';
|
||||
import { GET_TIMELINE_HEADER } from '../../../screens/timeline';
|
||||
|
||||
const alertRunTimeField = 'field.name.alert.page';
|
||||
const timelineRuntimeField = 'field.name.timeline';
|
||||
|
||||
describe('Create DataView runtime field', { tags: ['@ess', '@serverless'] }, () => {
|
||||
before(() => {
|
||||
deleteRuntimeField('security-solution-default', alertRunTimeField);
|
||||
deleteRuntimeField('security-solution-default', timelineRuntimeField);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
it('adds field to alert table', () => {
|
||||
visitWithTimeRange(ALERTS_URL);
|
||||
createRule(getNewRule());
|
||||
refreshPage();
|
||||
waitForAlertsToPopulate();
|
||||
openAlertsFieldBrowser();
|
||||
createField(alertRunTimeField);
|
||||
cy.get(GET_DATA_GRID_HEADER(alertRunTimeField)).should('exist');
|
||||
});
|
||||
|
||||
it('adds field to timeline', () => {
|
||||
visitWithTimeRange(hostsUrl('allHosts'));
|
||||
openTimelineUsingToggle();
|
||||
populateTimeline();
|
||||
openTimelineFieldsBrowser();
|
||||
|
||||
createField(timelineRuntimeField);
|
||||
cy.get(GET_TIMELINE_HEADER(timelineRuntimeField)).should('exist');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { DEFAULT_INDEX_PATTERN } from '@kbn/security-solution-plugin/common/constants';
|
||||
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../../tasks/navigation';
|
||||
|
||||
import { hostsUrl } from '../../../urls/navigation';
|
||||
import {
|
||||
addIndexToDefault,
|
||||
deselectSourcererOptions,
|
||||
isDataViewSelection,
|
||||
isHostsStatValue,
|
||||
isKibanaDataViewOption,
|
||||
isNotSourcererSelection,
|
||||
isSourcererOptions,
|
||||
isSourcererSelection,
|
||||
openAdvancedSettings,
|
||||
openDataViewSelection,
|
||||
openSourcerer,
|
||||
resetSourcerer,
|
||||
saveSourcerer,
|
||||
} from '../../../tasks/sourcerer';
|
||||
import { postDataView } from '../../../tasks/common';
|
||||
import { SOURCERER } from '../../../screens/sourcerer';
|
||||
|
||||
const siemDataViewTitle = 'Security Default Data View';
|
||||
const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*'];
|
||||
|
||||
describe('Sourcerer', { tags: ['@ess', '@serverless'] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
dataViews.forEach((dataView: string) => postDataView(dataView));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
login();
|
||||
visitWithTimeRange(hostsUrl('allHosts'));
|
||||
});
|
||||
|
||||
it('correctly loads SIEM data view', () => {
|
||||
openSourcerer();
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*'));
|
||||
});
|
||||
|
||||
describe('Modified badge', () => {
|
||||
it('Selecting new data view does not add a modified badge', () => {
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
openDataViewSelection();
|
||||
isKibanaDataViewOption(dataViews);
|
||||
cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle);
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
});
|
||||
|
||||
it('shows modified badge when index patterns change and removes when reset', () => {
|
||||
openSourcerer();
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
openAdvancedSettings();
|
||||
const patterns = dataViews[1].split(',');
|
||||
deselectSourcererOptions([patterns[0]]);
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`exist`);
|
||||
resetSourcerer();
|
||||
saveSourcerer();
|
||||
cy.get(SOURCERER.badgeModified).should(`not.exist`);
|
||||
openSourcerer();
|
||||
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
});
|
||||
});
|
||||
|
||||
it('disables save when no patterns are selected', () => {
|
||||
openSourcerer();
|
||||
openAdvancedSettings();
|
||||
cy.get(SOURCERER.saveButton).should('be.enabled');
|
||||
deselectSourcererOptions(['auditbeat-*']);
|
||||
cy.get(SOURCERER.saveButton).should('be.disabled');
|
||||
});
|
||||
|
||||
it(
|
||||
'adds a pattern to the default index and correctly filters out auditbeat-*',
|
||||
{ tags: '@brokenInServerless' },
|
||||
() => {
|
||||
openSourcerer();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isNotSourcererSelection('*beat*');
|
||||
addIndexToDefault('*beat*');
|
||||
isHostsStatValue('1');
|
||||
openSourcerer();
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isSourcererSelection('*beat*');
|
||||
}
|
||||
);
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { loginWithUser } from '../../../tasks/login';
|
||||
import { visitWithUser } from '../../../tasks/navigation';
|
||||
|
||||
import { hostsUrl } from '../../../urls/navigation';
|
||||
import { postDataView } from '../../../tasks/common';
|
||||
import {
|
||||
createUsersAndRoles,
|
||||
secReadCasesAll,
|
||||
secReadCasesAllUser,
|
||||
} from '../../../tasks/privileges';
|
||||
import { TOASTER } from '../../../screens/configure_cases';
|
||||
|
||||
const usersToCreate = [secReadCasesAllUser];
|
||||
const rolesToCreate = [secReadCasesAll];
|
||||
const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*'];
|
||||
|
||||
describe('Sourcerer permissions', { tags: ['@ess', '@skipInServerless'] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverResetKibana');
|
||||
dataViews.forEach((dataView: string) => postDataView(dataView));
|
||||
createUsersAndRoles(usersToCreate, rolesToCreate);
|
||||
});
|
||||
|
||||
it(`role(s) ${secReadCasesAllUser.roles.join()} shows error when user does not have permissions`, () => {
|
||||
loginWithUser(secReadCasesAllUser);
|
||||
visitWithUser(hostsUrl('allHosts'), secReadCasesAllUser);
|
||||
cy.get(TOASTER).should('have.text', 'Write role required to generate data');
|
||||
});
|
||||
});
|
|
@ -10,10 +10,10 @@ import {
|
|||
DEFAULT_INDEX_PATTERN,
|
||||
} from '@kbn/security-solution-plugin/common/constants';
|
||||
|
||||
import { login } from '../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../tasks/navigation';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../../tasks/navigation';
|
||||
|
||||
import { TIMELINES_URL } from '../../urls/navigation';
|
||||
import { TIMELINES_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
clickAlertCheckbox,
|
||||
deselectSourcererOptions,
|
||||
|
@ -29,12 +29,12 @@ import {
|
|||
refreshUntilAlertsIndexExists,
|
||||
resetSourcerer,
|
||||
saveSourcerer,
|
||||
} from '../../tasks/sourcerer';
|
||||
import { openTimelineUsingToggle } from '../../tasks/security_main';
|
||||
import { SOURCERER } from '../../screens/sourcerer';
|
||||
import { createTimeline } from '../../tasks/api_calls/timelines';
|
||||
import { getTimeline, getTimelineModifiedSourcerer } from '../../objects/timeline';
|
||||
import { closeTimeline, openTimelineById } from '../../tasks/timeline';
|
||||
} from '../../../tasks/sourcerer';
|
||||
import { openTimelineUsingToggle } from '../../../tasks/security_main';
|
||||
import { SOURCERER } from '../../../screens/sourcerer';
|
||||
import { createTimeline } from '../../../tasks/api_calls/timelines';
|
||||
import { getTimeline, getTimelineModifiedSourcerer } from '../../../objects/timeline';
|
||||
import { closeTimeline, openTimelineById } from '../../../tasks/timeline';
|
||||
|
||||
const siemDataViewTitle = 'Security Default Data View';
|
||||
const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*'];
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visit } from '../../../tasks/navigation';
|
||||
import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management';
|
||||
import { VALUE_LISTS_MODAL_ACTIVATOR } from '../../../screens/lists';
|
||||
|
||||
describe('value list permissions', { tags: ['@ess', '@skipInServerless'] }, () => {
|
||||
describe('user with restricted access role', () => {
|
||||
it('Does not allow a t1 analyst user to upload a value list', () => {
|
||||
login(ROLES.t1_analyst);
|
||||
visit(RULES_MANAGEMENT_URL, { role: ROLES.t1_analyst });
|
||||
cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,8 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ROLES } from '@kbn/security-solution-plugin/common/test';
|
||||
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visit } from '../../../tasks/navigation';
|
||||
import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management';
|
||||
|
@ -25,253 +23,224 @@ import {
|
|||
deleteValueLists,
|
||||
KNOWN_VALUE_LIST_FILES,
|
||||
} from '../../../tasks/lists';
|
||||
import {
|
||||
VALUE_LISTS_TABLE,
|
||||
VALUE_LISTS_ROW,
|
||||
VALUE_LISTS_MODAL_ACTIVATOR,
|
||||
} from '../../../screens/lists';
|
||||
import { VALUE_LISTS_TABLE, VALUE_LISTS_ROW } from '../../../screens/lists';
|
||||
import { refreshIndex } from '../../../tasks/api_calls/elasticsearch';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/165699
|
||||
describe('value lists', { tags: ['@ess', '@serverless', '@skipInServerless'] }, () => {
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe('management modal', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
describe('value lists management modal', { tags: ['@ess', '@serverless'] }, () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteValueLists([
|
||||
KNOWN_VALUE_LIST_FILES.TEXT,
|
||||
KNOWN_VALUE_LIST_FILES.IPs,
|
||||
KNOWN_VALUE_LIST_FILES.CIDRs,
|
||||
]);
|
||||
createListsIndex();
|
||||
visit(RULES_MANAGEMENT_URL);
|
||||
waitForListsIndex();
|
||||
waitForValueListsModalToBeLoaded();
|
||||
});
|
||||
|
||||
it('can open and close the modal', () => {
|
||||
openValueListsModal();
|
||||
closeValueListsModal();
|
||||
});
|
||||
|
||||
describe('create list types', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
deleteValueLists([
|
||||
KNOWN_VALUE_LIST_FILES.TEXT,
|
||||
KNOWN_VALUE_LIST_FILES.IPs,
|
||||
KNOWN_VALUE_LIST_FILES.CIDRs,
|
||||
]);
|
||||
createListsIndex();
|
||||
visit(RULES_MANAGEMENT_URL);
|
||||
waitForListsIndex();
|
||||
waitForValueListsModalToBeLoaded();
|
||||
});
|
||||
|
||||
it('can open and close the modal', () => {
|
||||
openValueListsModal();
|
||||
closeValueListsModal();
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
// Flaky in serverless tests
|
||||
describe('create list types', { tags: ['@brokenInServerless'] }, () => {
|
||||
beforeEach(() => {
|
||||
openValueListsModal();
|
||||
});
|
||||
it('creates a "keyword" list from an uploaded file', () => {
|
||||
selectValueListType('keyword');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
uploadValueList();
|
||||
|
||||
it('creates a "keyword" list from an uploaded file', () => {
|
||||
selectValueListType('keyword');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
uploadValueList();
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
expect($row.text()).to.contain('Keywords');
|
||||
});
|
||||
});
|
||||
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
expect($row.text()).to.contain('Keywords');
|
||||
});
|
||||
});
|
||||
it('creates a "text" list from an uploaded file', () => {
|
||||
selectValueListType('text');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
uploadValueList();
|
||||
|
||||
it('creates a "text" list from an uploaded file', () => {
|
||||
selectValueListType('text');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
uploadValueList();
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
expect($row.text()).to.contain('Text');
|
||||
});
|
||||
});
|
||||
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
expect($row.text()).to.contain('Text');
|
||||
});
|
||||
});
|
||||
it('creates a "ip" list from an uploaded file', () => {
|
||||
selectValueListType('ip');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
uploadValueList();
|
||||
|
||||
it('creates a "ip" list from an uploaded file', () => {
|
||||
selectValueListType('ip');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
uploadValueList();
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
expect($row.text()).to.contain('IP addresses');
|
||||
});
|
||||
});
|
||||
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
expect($row.text()).to.contain('IP addresses');
|
||||
});
|
||||
});
|
||||
it('creates a "ip_range" list from an uploaded file', () => {
|
||||
selectValueListType('ip_range');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
uploadValueList();
|
||||
|
||||
it('creates a "ip_range" list from an uploaded file', () => {
|
||||
selectValueListType('ip_range');
|
||||
selectValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
uploadValueList();
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
expect($row.text()).to.contain('IP ranges');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
expect($row.text()).to.contain('IP ranges');
|
||||
});
|
||||
describe('delete list types', () => {
|
||||
it('deletes a "keyword" list from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword');
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes a "text" list from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text');
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes a "ip" from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip');
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes a "ip_range" from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']);
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('export list types', () => {
|
||||
it('exports a "keyword" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword');
|
||||
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => {
|
||||
const [lineOne, lineTwo] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
expect(response?.body).to.contain(lineTwo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
// Flaky in serverless tests
|
||||
describe('delete list types', { tags: ['@brokenInServerless'] }, () => {
|
||||
it('deletes a "keyword" list from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword');
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
});
|
||||
});
|
||||
it('exports a "text" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text');
|
||||
|
||||
it('deletes a "text" list from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text');
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.TEXT);
|
||||
});
|
||||
});
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
|
||||
it('deletes a "ip" from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip');
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.IPs);
|
||||
});
|
||||
});
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
|
||||
it('deletes a "ip_range" from an uploaded file', () => {
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']);
|
||||
openValueListsModal();
|
||||
deleteValueListsFile(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).not.to.contain(KNOWN_VALUE_LIST_FILES.CIDRs);
|
||||
});
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => {
|
||||
const [lineOne, lineTwo] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
expect(response?.body).to.contain(lineTwo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
// Flaky in serverless tests
|
||||
describe('export list types', { tags: ['@brokenInServerless'] }, () => {
|
||||
it('exports a "keyword" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'keyword');
|
||||
it('exports a "ip" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.IPs}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip');
|
||||
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => {
|
||||
const [lineOne, lineTwo] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
expect(response?.body).to.contain(lineTwo);
|
||||
});
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.IPs).then((list: string) => {
|
||||
const [lineOne, lineTwo] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
expect(response?.body).to.contain(lineTwo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('exports a "text" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.TEXT}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.TEXT, 'text');
|
||||
it('exports a "ip_range" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.CIDRs}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']);
|
||||
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.TEXT).then((list: string) => {
|
||||
const [lineOne, lineTwo] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
expect(response?.body).to.contain(lineTwo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('exports a "ip" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.IPs}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.IPs, 'ip');
|
||||
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.IPs).then((list: string) => {
|
||||
const [lineOne, lineTwo] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
expect(response?.body).to.contain(lineTwo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('exports a "ip_range" list from an uploaded file', () => {
|
||||
cy.intercept('POST', `/api/lists/items/_export?list_id=${KNOWN_VALUE_LIST_FILES.CIDRs}`).as(
|
||||
'exportList'
|
||||
);
|
||||
importValueList(KNOWN_VALUE_LIST_FILES.CIDRs, 'ip_range', ['192.168.100.0']);
|
||||
|
||||
// Importing value lists includes bulk creation of list items with refresh=wait_for
|
||||
// While it should wait for data update and return after that it's not always a case with bulk operations.
|
||||
// Sometimes list items are empty making this test flaky.
|
||||
// To fix it refresh used list items index (for the default space)
|
||||
refreshIndex('.items-default');
|
||||
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.CIDRs).then((list: string) => {
|
||||
const [lineOne] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
});
|
||||
openValueListsModal();
|
||||
exportValueList();
|
||||
cy.wait('@exportList').then(({ response }) => {
|
||||
cy.fixture(KNOWN_VALUE_LIST_FILES.CIDRs).then((list: string) => {
|
||||
const [lineOne] = list.split('\n');
|
||||
expect(response?.body).to.contain(lineOne);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/164451 We should find a way to make this spec work in Serverless
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe(
|
||||
'user with restricted access role',
|
||||
{ tags: ['@ess', '@serverless', '@skipInServerless'] },
|
||||
() => {
|
||||
it('Does not allow a t1 analyst user to upload a value list', () => {
|
||||
login(ROLES.t1_analyst);
|
||||
visit(RULES_MANAGEMENT_URL, { role: ROLES.t1_analyst });
|
||||
cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('have.attr', 'disabled');
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -5,25 +5,25 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getNewRule } from '../../objects/rule';
|
||||
import { ALERTS_COUNT } from '../../screens/alerts';
|
||||
import { getNewRule } from '../../../objects/rule';
|
||||
import { ALERTS_COUNT } from '../../../screens/alerts';
|
||||
import {
|
||||
clickAlertsHistogramLegend,
|
||||
clickAlertsHistogramLegendAddToTimeline,
|
||||
clickAlertsHistogramLegendFilterFor,
|
||||
clickAlertsHistogramLegendFilterOut,
|
||||
selectAlertsHistogram,
|
||||
} from '../../tasks/alerts';
|
||||
import { createRule } from '../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../tasks/common';
|
||||
import { login } from '../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../tasks/navigation';
|
||||
import { ALERTS_URL } from '../../urls/navigation';
|
||||
} from '../../../tasks/alerts';
|
||||
import { createRule } from '../../../tasks/api_calls/rules';
|
||||
import { cleanKibana } from '../../../tasks/common';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../../tasks/navigation';
|
||||
import { ALERTS_URL } from '../../../urls/navigation';
|
||||
import {
|
||||
GLOBAL_SEARCH_BAR_FILTER_ITEM,
|
||||
GLOBAL_SEARCH_BAR_FILTER_ITEM_DELETE,
|
||||
} from '../../screens/search_bar';
|
||||
import { TOASTER } from '../../screens/alerts_detection_rules';
|
||||
} from '../../../screens/search_bar';
|
||||
import { TOASTER } from '../../../screens/alerts_detection_rules';
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/161539
|
||||
describe(
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../../tasks/navigation';
|
||||
|
||||
import { ALERTS_URL, TIMELINES_URL } from '../../../urls/navigation';
|
||||
import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../../screens/alerts';
|
||||
import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../../screens/timeline';
|
||||
import { selectAlertsHistogram } from '../../../tasks/alerts';
|
||||
import { createTimeline } from '../../../tasks/timelines';
|
||||
|
||||
describe('Ransomware Detection Alerts', { tags: ['@ess', '@serverless'] }, () => {
|
||||
before(() => {
|
||||
cy.task('esArchiverLoad', {
|
||||
archiveName: 'ransomware_detection',
|
||||
useCreate: true,
|
||||
docsOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ransomware display in Alerts Section', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithTimeRange(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
describe('Alerts table', () => {
|
||||
it('shows Ransomware Alerts', () => {
|
||||
cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Detection Alert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Trend Chart', () => {
|
||||
beforeEach(() => {
|
||||
selectAlertsHistogram();
|
||||
});
|
||||
|
||||
it('shows Ransomware Detection Alert in the trend chart', () => {
|
||||
cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Detection Alert');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/168602
|
||||
describe.skip('Ransomware in Timelines', () => {
|
||||
before(() => {
|
||||
login();
|
||||
visitWithTimeRange(TIMELINES_URL);
|
||||
createTimeline();
|
||||
});
|
||||
|
||||
it('Renders ransomware entries in timelines table', () => {
|
||||
cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}');
|
||||
|
||||
// Wait for grid to load, it should have an analyzer icon
|
||||
cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist');
|
||||
|
||||
cy.get(MESSAGE).should('have.text', 'Ransomware Detection Alert');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { waitForAlertsToPopulate } from '../../../tasks/create_new_rule';
|
||||
import { login } from '../../../tasks/login';
|
||||
import { visitWithTimeRange } from '../../../tasks/navigation';
|
||||
|
||||
import { ALERTS_URL, TIMELINES_URL } from '../../../urls/navigation';
|
||||
import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../../screens/alerts';
|
||||
import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../../screens/timeline';
|
||||
import { selectAlertsHistogram } from '../../../tasks/alerts';
|
||||
import { createTimeline } from '../../../tasks/timelines';
|
||||
import { cleanKibana } from '../../../tasks/common';
|
||||
|
||||
describe('Ransomware Prevention Alerts', { tags: ['@ess', '@serverless'] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
cy.task('esArchiverLoad', {
|
||||
archiveName: 'ransomware_prevention',
|
||||
useCreate: true,
|
||||
docsOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.task('esArchiverUnload', 'ransomware_prevention');
|
||||
});
|
||||
|
||||
describe('Ransomware display in Alerts Section', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithTimeRange(ALERTS_URL);
|
||||
waitForAlertsToPopulate();
|
||||
});
|
||||
|
||||
describe('Alerts table', () => {
|
||||
it('shows Ransomware Alerts', () => {
|
||||
cy.get(ALERT_RULE_NAME).should('have.text', 'Ransomware Prevention Alert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Trend Chart', () => {
|
||||
beforeEach(() => {
|
||||
selectAlertsHistogram();
|
||||
});
|
||||
|
||||
it('shows Ransomware Prevention Alert in the trend chart', () => {
|
||||
cy.get(ALERTS_HISTOGRAM_SERIES).should('have.text', 'Ransomware Prevention Alert');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ransomware in Timelines', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
visitWithTimeRange(TIMELINES_URL);
|
||||
|
||||
createTimeline();
|
||||
});
|
||||
|
||||
it('Renders ransomware entries in timelines table', () => {
|
||||
cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}');
|
||||
|
||||
// Wait for grid to load, it should have an analyzer icon
|
||||
cy.get(TIMELINE_VIEW_IN_ANALYZER).should('exist');
|
||||
|
||||
cy.get(MESSAGE).should('have.text', 'Ransomware Prevention Alert');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -304,6 +304,12 @@ export const goToAcknowledgedAlerts = () => {
|
|||
cy.get(TIMELINE_COLUMN_SPINNER).should('not.exist');
|
||||
};
|
||||
|
||||
export const markAlertsAcknowledged = () => {
|
||||
cy.get(TAKE_ACTION_POPOVER_BTN).click({ force: true });
|
||||
cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).should('be.visible');
|
||||
cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).click();
|
||||
};
|
||||
|
||||
export const markAcknowledgedFirstAlert = () => {
|
||||
expandFirstAlertActions();
|
||||
cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).should('be.visible');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue