mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Security Solution] Sourcerer fix bug 121380 (#121581)
This commit is contained in:
parent
2150e74224
commit
78d15cd7f0
5 changed files with 153 additions and 84 deletions
|
@ -36,6 +36,9 @@ import { createUsersAndRoles, secReadCasesAll, secReadCasesAllUser } from '../..
|
|||
import { TOASTER } from '../../screens/configure_cases';
|
||||
import { DEFAULT_ALERTS_INDEX, DEFAULT_INDEX_PATTERN } from '../../../common/constants';
|
||||
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 usersToCreate = [secReadCasesAllUser];
|
||||
const rolesToCreate = [secReadCasesAll];
|
||||
|
@ -129,103 +132,132 @@ describe('Sourcerer', () => {
|
|||
isSourcererSelection('beats*');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Timeline scope', () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
loginAndWaitForPage(TIMELINES_URL);
|
||||
});
|
||||
|
||||
describe('Timeline scope', () => {
|
||||
beforeEach(() => {
|
||||
cy.clearLocalStorage();
|
||||
loginAndWaitForPage(TIMELINES_URL);
|
||||
it('correctly loads SIEM data view before and after signals index exists', () => {
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isNotSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
isSourcererOptions(
|
||||
[...DEFAULT_INDEX_PATTERN, `${DEFAULT_ALERTS_INDEX}-default`].filter(
|
||||
(pattern) => pattern !== 'auditbeat-*'
|
||||
)
|
||||
);
|
||||
waitForAlertsIndexToExist();
|
||||
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('correctly loads SIEM data view before and after signals index exists', () => {
|
||||
it('shows modified badge when index patterns change and removes when reset', () => {
|
||||
openTimelineUsingToggle();
|
||||
openSourcerer('timeline');
|
||||
isDataViewSelection(siemDataViewTitle);
|
||||
openDataViewSelection();
|
||||
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
|
||||
isDataViewSelection(dataViews[1]);
|
||||
openAdvancedSettings();
|
||||
isSourcererSelection(`auditbeat-*`);
|
||||
isNotSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
|
||||
isSourcererOptions(
|
||||
[...DEFAULT_INDEX_PATTERN, `${DEFAULT_ALERTS_INDEX}-default`].filter(
|
||||
(pattern) => pattern !== 'auditbeat-*'
|
||||
)
|
||||
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(() => {
|
||||
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(() => {
|
||||
loginAndWaitForPage(TIMELINES_URL);
|
||||
waitForAlertsIndexToExist();
|
||||
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();
|
||||
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');
|
||||
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', () => {
|
||||
beforeEach(() => {
|
||||
waitForAlertsIndexToExist();
|
||||
});
|
||||
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-*')
|
||||
.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`);
|
||||
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-*')
|
||||
.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`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,6 +12,8 @@ export interface Timeline {
|
|||
description: string;
|
||||
query: string;
|
||||
id?: string;
|
||||
dataViewId?: string;
|
||||
indexNames?: string[];
|
||||
}
|
||||
|
||||
export interface CompleteTimeline extends Timeline {
|
||||
|
@ -46,6 +48,12 @@ export const getIndicatorMatchTimelineTemplate = (): CompleteTimeline => ({
|
|||
templateTimelineId: '495ad7a7-316e-4544-8a0f-9c098daee76e',
|
||||
});
|
||||
|
||||
export const getTimelineModifiedSourcerer = () => ({
|
||||
...getTimeline(),
|
||||
title: 'Auditbeat Timeline',
|
||||
dataViewId: 'security-solution-default',
|
||||
indexNames: ['auditbeat-*'],
|
||||
});
|
||||
/**
|
||||
* Timeline query that finds no valid data to cut down on test failures
|
||||
* or other issues for when we want to test one specific thing and not also
|
||||
|
|
|
@ -46,6 +46,9 @@ export const createTimeline = (timeline: CompleteTimeline) =>
|
|||
description: timeline.description,
|
||||
title: timeline.title,
|
||||
savedQueryId: null,
|
||||
...(timeline.dataViewId != null && timeline.indexNames != null
|
||||
? { dataViewId: timeline.dataViewId, indexNames: timeline.indexNames }
|
||||
: {}),
|
||||
},
|
||||
},
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
|
|
|
@ -66,8 +66,20 @@ export const Sourcerer = React.memo<SourcererComponentProps>(({ scope: scopeId }
|
|||
isTimelineSourcerer && selectedPatterns.join() === signalIndexName
|
||||
);
|
||||
|
||||
const onUpdateDetectionAlertsChecked = useCallback(() => {
|
||||
setIsOnlyDetectionAlertsChecked(
|
||||
isTimelineSourcerer && selectedPatterns.join() === signalIndexName
|
||||
);
|
||||
}, [isTimelineSourcerer, selectedPatterns, signalIndexName]);
|
||||
|
||||
useEffect(() => {
|
||||
onUpdateDetectionAlertsChecked();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedPatterns]);
|
||||
|
||||
const isOnlyDetectionAlerts: boolean =
|
||||
isDetectionsSourcerer || (isTimelineSourcerer && isOnlyDetectionAlertsChecked);
|
||||
|
||||
const [isPopoverOpen, setPopoverIsOpen] = useState(false);
|
||||
const [dataViewId, setDataViewId] = useState<string | null>(selectedDataViewId);
|
||||
|
||||
|
@ -75,6 +87,7 @@ export const Sourcerer = React.memo<SourcererComponentProps>(({ scope: scopeId }
|
|||
allOptions,
|
||||
dataViewSelectOptions,
|
||||
isModified,
|
||||
handleOutsideClick,
|
||||
onChangeCombo,
|
||||
renderOption,
|
||||
selectedOptions,
|
||||
|
@ -211,7 +224,14 @@ export const Sourcerer = React.memo<SourcererComponentProps>(({ scope: scopeId }
|
|||
const onOutsideClick = useCallback(() => {
|
||||
setDataViewId(selectedDataViewId);
|
||||
setMissingPatterns(sourcererMissingPatterns);
|
||||
}, [selectedDataViewId, sourcererMissingPatterns]);
|
||||
onUpdateDetectionAlertsChecked();
|
||||
handleOutsideClick();
|
||||
}, [
|
||||
handleOutsideClick,
|
||||
onUpdateDetectionAlertsChecked,
|
||||
selectedDataViewId,
|
||||
sourcererMissingPatterns,
|
||||
]);
|
||||
|
||||
const onExpandAdvancedOptionsClicked = useCallback(() => {
|
||||
setExpandAdvancedOptions((prevState) => !prevState);
|
||||
|
|
|
@ -29,6 +29,7 @@ export type ModifiedTypes = 'modified' | 'alerts' | 'deprecated' | 'missingPatte
|
|||
interface UsePickIndexPatterns {
|
||||
allOptions: Array<EuiComboBoxOptionOption<string>>;
|
||||
dataViewSelectOptions: Array<EuiSuperSelectOption<string>>;
|
||||
handleOutsideClick: () => void;
|
||||
isModified: ModifiedTypes;
|
||||
onChangeCombo: (newSelectedDataViewId: Array<EuiComboBoxOptionOption<string>>) => void;
|
||||
renderOption: ({ value }: EuiComboBoxOptionOption<string>) => React.ReactElement;
|
||||
|
@ -161,7 +162,7 @@ export const usePickIndexPatterns = ({
|
|||
selectedDataViewId
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedDataViewId, missingPatterns, scopeId, selectedPatterns]);
|
||||
}, [isOnlyDetectionAlerts, selectedDataViewId, missingPatterns, scopeId, selectedPatterns]);
|
||||
|
||||
const onChangeCombo = useCallback((newSelectedOptions) => {
|
||||
setSelectedOptions(newSelectedOptions);
|
||||
|
@ -190,9 +191,14 @@ export const usePickIndexPatterns = ({
|
|||
[dataViewId, defaultDataViewId, isModified, isOnlyDetectionAlerts, kibanaDataViews]
|
||||
);
|
||||
|
||||
const handleOutsideClick = useCallback(() => {
|
||||
setSelectedOptions(patternListToOptions(selectedPatterns));
|
||||
}, [selectedPatterns]);
|
||||
|
||||
return {
|
||||
allOptions,
|
||||
dataViewSelectOptions,
|
||||
handleOutsideClick,
|
||||
isModified,
|
||||
onChangeCombo,
|
||||
renderOption,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue