Skip to content

Commit

Permalink
Add warning for EQL and Threshold rules if exception list contains va…
Browse files Browse the repository at this point in the history
…lue list items (elastic#92914)
  • Loading branch information
marshallmain committed Feb 26, 2021
1 parent 12a223e commit 5b4d3de
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@
* 2.0.
*/

import { EntriesArray } from '../shared_imports';
import {
CreateExceptionListItemSchema,
EntriesArray,
ExceptionListItemSchema,
} from '../shared_imports';
import { Type } from './schemas/common/schemas';

export const hasLargeValueItem = (
exceptionItems: Array<ExceptionListItemSchema | CreateExceptionListItemSchema>
) => {
return exceptionItems.some((exceptionItem) => hasLargeValueList(exceptionItem.entries));
};

export const hasLargeValueList = (entries: EntriesArray): boolean => {
const found = entries.filter(({ type }) => type === 'list');
return found.length > 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,35 @@ export const getMlResult = (): RuleAlertType => {
};
};

export const getThresholdResult = (): RuleAlertType => {
const result = getResult();

return {
...result,
params: {
...result.params,
type: 'threshold',
threshold: {
field: 'host.ip',
value: 5,
},
},
};
};

export const getEqlResult = (): RuleAlertType => {
const result = getResult();

return {
...result,
params: {
...result.params,
type: 'eql',
query: 'process where true',
},
};
};

export const updateActionResult = (): ActionResult => ({
id: 'result-1',
actionTypeId: 'action-id-1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

import moment from 'moment';
import { loggingSystemMock } from 'src/core/server/mocks';
import { getResult, getMlResult } from '../routes/__mocks__/request_responses';
import {
getResult,
getMlResult,
getThresholdResult,
getEqlResult,
} from '../routes/__mocks__/request_responses';
import { signalRulesAlertType } from './signal_rule_alert_type';
import { alertsMock, AlertServicesMock } from '../../../../../alerts/server/mocks';
import { ruleStatusServiceFactory } from './rule_status_service';
Expand All @@ -24,6 +29,7 @@ import { getListClientMock } from '../../../../../lists/server/services/lists/li
import { getExceptionListClientMock } from '../../../../../lists/server/services/exception_lists/exception_list_client.mock';
import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
import { ApiResponse } from '@elastic/elasticsearch/lib/Transport';
import { getEntryListMock } from '../../../../../lists/common/schemas/types/entry_list.mock';

jest.mock('./rule_status_saved_objects_client');
jest.mock('./rule_status_service');
Expand Down Expand Up @@ -211,6 +217,30 @@ describe('rules_notification_alert_type', () => {
);
});

it('should set a warning when exception list for threshold rule contains value list exceptions', async () => {
(getExceptions as jest.Mock).mockReturnValue([
getExceptionListItemSchemaMock({ entries: [getEntryListMock()] }),
]);
payload = getPayload(getThresholdResult(), alertServices);
await alert.executor(payload);
expect(ruleStatusService.warning).toHaveBeenCalled();
expect(ruleStatusService.warning.mock.calls[0][0]).toContain(
'Exceptions that use "is in list" or "is not in list" operators are not applied to Threshold rules'
);
});

it('should set a warning when exception list for EQL rule contains value list exceptions', async () => {
(getExceptions as jest.Mock).mockReturnValue([
getExceptionListItemSchemaMock({ entries: [getEntryListMock()] }),
]);
payload = getPayload(getEqlResult(), alertServices);
await alert.executor(payload);
expect(ruleStatusService.warning).toHaveBeenCalled();
expect(ruleStatusService.warning.mock.calls[0][0]).toContain(
'Exceptions that use "is in list" or "is not in list" operators are not applied to EQL rules'
);
});

it('should set a failure status for when rules cannot read ANY provided indices', async () => {
(checkPrivileges as jest.Mock).mockResolvedValueOnce({
username: 'elastic',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
isThresholdRule,
isEqlRule,
isThreatMatchRule,
hasLargeValueItem,
} from '../../../../common/detection_engine/utils';
import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates';
import { SetupPlugins } from '../../../plugin';
Expand Down Expand Up @@ -365,6 +366,12 @@ export const signalRulesAlertType = ({
}),
]);
} else if (isThresholdRule(type) && threshold) {
if (hasLargeValueItem(exceptionItems ?? [])) {
await ruleStatusService.warning(
'Exceptions that use "is in list" or "is not in list" operators are not applied to Threshold rules'
);
wroteWarningStatus = true;
}
const inputIndex = await getInputIndex(services, version, index);

const thresholdFields = Array.isArray(threshold.field)
Expand Down Expand Up @@ -552,6 +559,12 @@ export const signalRulesAlertType = ({
if (query === undefined) {
throw new Error('EQL query rule must have a query defined');
}
if (hasLargeValueItem(exceptionItems ?? [])) {
await ruleStatusService.warning(
'Exceptions that use "is in list" or "is not in list" operators are not applied to EQL rules'
);
wroteWarningStatus = true;
}
try {
const signalIndexVersion = await getIndexVersion(services.callCluster, outputIndex);
if (isOutdated({ current: signalIndexVersion, target: MIN_EQL_RULE_INDEX_VERSION })) {
Expand Down

0 comments on commit 5b4d3de

Please sign in to comment.