Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution][Detection Engine] adds alert suppression for New Terms rule type #178294

Merged
merged 47 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
12b5eff
[Security Solution][Detection Engine] adds alert suppression for New …
vitaliidm Mar 8, 2024
2444935
add usint tests for converter
vitaliidm Mar 8, 2024
ec467bc
cypress tests
vitaliidm Mar 8, 2024
68ef90c
remove failures
vitaliidm Mar 8, 2024
f7bd2fc
fix tests
vitaliidm Mar 8, 2024
4717113
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Mar 8, 2024
028efcc
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Mar 11, 2024
203cda5
add ftr tests
vitaliidm Mar 11, 2024
b0a311f
split search and bulk create
vitaliidm Mar 12, 2024
0bd4ec8
add BE
vitaliidm Mar 12, 2024
730f0cf
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Mar 12, 2024
42770a9
add more fixes
vitaliidm Mar 12, 2024
529733f
fix tests
vitaliidm Mar 13, 2024
04378e2
Merge branch 'de_8_14/new_terms_suppression' of https://github.com/vi…
vitaliidm Mar 13, 2024
171b2fc
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Mar 13, 2024
97e43cc
fixes some tests
vitaliidm Mar 13, 2024
186ac3d
Merge branch 'de_8_14/new_terms_suppression' of https://github.com/vi…
vitaliidm Mar 13, 2024
25c94b9
fix lint
vitaliidm Mar 13, 2024
a1a7496
fix tests
vitaliidm Mar 14, 2024
b10f6de
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Mar 14, 2024
46ce899
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Mar 22, 2024
710dda5
fixes
vitaliidm Mar 22, 2024
7061dbf
refactoring/fixes
vitaliidm Mar 22, 2024
890391e
fix lints
vitaliidm Mar 22, 2024
3b38b24
add unit test
vitaliidm Mar 22, 2024
65706ea
fix UNIT tests
vitaliidm Mar 22, 2024
0bc01fa
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 2, 2024
c73012e
add more tests
vitaliidm Apr 2, 2024
90243e1
remove IM FF
vitaliidm Apr 2, 2024
ccfc461
add additional ftr exception test
vitaliidm Apr 2, 2024
d1443de
add enrichment tests
vitaliidm Apr 2, 2024
2995b0e
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 3, 2024
bbfb3d4
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 3, 2024
8280b6a
CR feedback
vitaliidm Apr 5, 2024
9af1081
lint errors
vitaliidm Apr 5, 2024
36e06a5
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 5, 2024
08f8eb1
remove unnecessary file
vitaliidm Apr 5, 2024
5c36012
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 5, 2024
d592c79
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 5, 2024
f3152bd
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 8, 2024
d47da36
CR feedback
vitaliidm Apr 8, 2024
778b501
CR: feedback
vitaliidm Apr 8, 2024
ff8a41f
CR: add more test cases
vitaliidm Apr 8, 2024
2f65849
CR feedback
vitaliidm Apr 8, 2024
d6200ff
fix jest test
vitaliidm Apr 8, 2024
1d30c31
Merge branch 'main' into de_8_14/new_terms_suppression
vitaliidm Apr 8, 2024
2237d76
fix FTR test
vitaliidm Apr 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
suppressionWindow,
enrichAlerts,
currentTimeOverride,
isRuleExecutionOnly
isRuleExecutionOnly,
maxAlerts
) => {
const ruleDataClientWriter = await ruleDataClient.getWriter({
namespace: options.spaceId,
Expand All @@ -376,6 +377,8 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
const writeAlerts =
ruleDataClient.isWriteEnabled() && options.services.shouldWriteAlerts();

let alertsWereTruncated = false;

if (writeAlerts && alerts.length > 0) {
const suppressionWindowStart = dateMath.parse(suppressionWindow, {
forceNow: currentTimeOverride,
Expand All @@ -392,7 +395,12 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
});

if (filteredDuplicates.length === 0) {
return { createdAlerts: [], errors: {}, suppressedAlerts: [] };
return {
createdAlerts: [],
errors: {},
suppressedAlerts: [],
alertsWereTruncated,
};
}

const suppressionAlertSearchRequest = {
Expand Down Expand Up @@ -473,7 +481,12 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
});

if (nonSuppressedAlerts.length === 0) {
return { createdAlerts: [], errors: {}, suppressedAlerts: [] };
return {
createdAlerts: [],
errors: {},
suppressedAlerts: [],
alertsWereTruncated,
};
}

const { alertCandidates, suppressedAlerts: suppressedInMemoryAlerts } =
Expand Down Expand Up @@ -535,6 +548,11 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
}
}

if (maxAlerts && enrichedAlerts.length > maxAlerts) {
enrichedAlerts.length = maxAlerts;
alertsWereTruncated = true;
}

const augmentedAlerts = augmentAlerts({
alerts: enrichedAlerts,
options,
Expand All @@ -548,7 +566,12 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
});

if (bulkResponse == null) {
return { createdAlerts: [], errors: {}, suppressedAlerts: [] };
return {
createdAlerts: [],
errors: {},
suppressedAlerts: [],
alertsWereTruncated: false,
};
}

const createdAlerts = augmentedAlerts
Expand Down Expand Up @@ -594,10 +617,16 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper
createdAlerts,
suppressedAlerts: [...duplicateAlerts, ...suppressedInMemoryAlerts],
errors: errorAggregator(bulkResponse.body, [409]),
alertsWereTruncated,
};
} else {
logger.debug('Writing is disabled.');
return { createdAlerts: [], errors: {}, suppressedAlerts: [] };
return {
createdAlerts: [],
errors: {},
suppressedAlerts: [],
alertsWereTruncated: false,
};
}
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ export type SuppressedAlertService = <T extends SuppressionFieldsLatest>(
params: { spaceId: string }
) => Promise<Array<{ _id: string; _source: T }>>,
currentTimeOverride?: Date,
isRuleExecutionOnly?: boolean
isRuleExecutionOnly?: boolean,
maxAlerts?: number
) => Promise<SuppressedAlertServiceResult<T>>;

export interface SuppressedAlertServiceResult<T>
extends Omit<PersistenceAlertServiceResult<T>, 'alertsWereTruncated'> {
export interface SuppressedAlertServiceResult<T> extends PersistenceAlertServiceResult<T> {
suppressedAlerts: Array<{ _id: string; _source: T }>;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getListArrayMock } from '../../../../detection_engine/schemas/types/lis
import {
getCreateEsqlRulesSchemaMock,
getCreateMachineLearningRulesSchemaMock,
getCreateNewTermsRulesSchemaMock,
getCreateRulesSchemaMock,
getCreateRulesSchemaMockWithDataView,
getCreateSavedQueryRulesSchemaMock,
Expand Down Expand Up @@ -1267,6 +1268,7 @@ describe('rules schema', () => {
{ ruleType: 'threat_match', ruleMock: getCreateThreatMatchRulesSchemaMock() },
{ ruleType: 'query', ruleMock: getCreateRulesSchemaMock() },
{ ruleType: 'saved_query', ruleMock: getCreateSavedQueryRulesSchemaMock() },
{ ruleType: 'new_terms', ruleMock: getCreateNewTermsRulesSchemaMock() },
];

cases.forEach(({ ruleType, ruleMock }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ export const NewTermsRuleOptionalFields = z.object({
index: IndexPatternArray.optional(),
data_view_id: DataViewId.optional(),
filters: RuleFilterArray.optional(),
alert_suppression: AlertSuppression.optional(),
});

export type NewTermsRuleDefaultableFields = z.infer<typeof NewTermsRuleDefaultableFields>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,8 @@ components:
$ref: './common_attributes.schema.yaml#/components/schemas/DataViewId'
filters:
$ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray'
alert_suppression:
$ref: './common_attributes.schema.yaml#/components/schemas/AlertSuppression'

NewTermsRuleDefaultableFields:
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ export const SUPPRESSIBLE_ALERT_RULES: Type[] = [
'threshold',
'saved_query',
'query',
'new_terms',
'threat_match',
];
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,11 @@ describe('Alert Suppression Rules', () => {
expect(isSuppressibleAlertRule('saved_query')).toBe(true);
expect(isSuppressibleAlertRule('query')).toBe(true);
expect(isSuppressibleAlertRule('threat_match')).toBe(true);
expect(isSuppressibleAlertRule('new_terms')).toBe(true);

// Rule types that don't support alert suppression:
expect(isSuppressibleAlertRule('eql')).toBe(false);
expect(isSuppressibleAlertRule('machine_learning')).toBe(false);
expect(isSuppressibleAlertRule('new_terms')).toBe(false);
expect(isSuppressibleAlertRule('esql')).toBe(false);
});

Expand All @@ -253,11 +253,11 @@ describe('Alert Suppression Rules', () => {
expect(isSuppressionRuleConfiguredWithDuration('saved_query')).toBe(true);
expect(isSuppressionRuleConfiguredWithDuration('query')).toBe(true);
expect(isSuppressionRuleConfiguredWithDuration('threat_match')).toBe(true);
expect(isSuppressionRuleConfiguredWithDuration('new_terms')).toBe(true);

// Rule types that don't support alert suppression:
expect(isSuppressionRuleConfiguredWithDuration('eql')).toBe(false);
expect(isSuppressionRuleConfiguredWithDuration('machine_learning')).toBe(false);
expect(isSuppressionRuleConfiguredWithDuration('new_terms')).toBe(false);
expect(isSuppressionRuleConfiguredWithDuration('esql')).toBe(false);
});

Expand All @@ -274,11 +274,11 @@ describe('Alert Suppression Rules', () => {
expect(isSuppressionRuleConfiguredWithGroupBy('saved_query')).toBe(true);
expect(isSuppressionRuleConfiguredWithGroupBy('query')).toBe(true);
expect(isSuppressionRuleConfiguredWithGroupBy('threat_match')).toBe(true);
expect(isSuppressionRuleConfiguredWithGroupBy('new_terms')).toBe(true);

// Rule types that don't support alert suppression:
expect(isSuppressionRuleConfiguredWithGroupBy('eql')).toBe(false);
expect(isSuppressionRuleConfiguredWithGroupBy('machine_learning')).toBe(false);
expect(isSuppressionRuleConfiguredWithGroupBy('new_terms')).toBe(false);
expect(isSuppressionRuleConfiguredWithGroupBy('esql')).toBe(false);
});

Expand All @@ -300,11 +300,11 @@ describe('Alert Suppression Rules', () => {
expect(isSuppressionRuleConfiguredWithMissingFields('saved_query')).toBe(true);
expect(isSuppressionRuleConfiguredWithMissingFields('query')).toBe(true);
expect(isSuppressionRuleConfiguredWithMissingFields('threat_match')).toBe(true);
expect(isSuppressionRuleConfiguredWithMissingFields('new_terms')).toBe(true);

// Rule types that don't support alert suppression:
expect(isSuppressionRuleConfiguredWithMissingFields('eql')).toBe(false);
expect(isSuppressionRuleConfiguredWithMissingFields('machine_learning')).toBe(false);
expect(isSuppressionRuleConfiguredWithMissingFields('new_terms')).toBe(false);
expect(isSuppressionRuleConfiguredWithMissingFields('esql')).toBe(false);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ export const allowedExperimentalValues = Object.freeze({
*/
riskEnginePrivilegesRouteEnabled: true,

/**
* Enables alerts suppression for new terms rules
*/
alertSuppressionForNewTermsRuleEnabled: false,

/**
* Enables experimental Experimental S1 integration data to be available in Analyzer
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ describe('description_step', () => {
});

describe('alert suppression', () => {
const ruleTypesWithoutSuppression: Type[] = ['eql', 'esql', 'machine_learning', 'new_terms'];
const ruleTypesWithoutSuppression: Type[] = ['eql', 'esql', 'machine_learning'];
const suppressionFields = {
groupByDuration: {
unit: 'm',
Expand Down
Loading