-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[Security Solutions][Detection Engine] Adds threat matching API and rule type #77395
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
Changes from 26 commits
ce14648
01c8c88
b49a549
048c2d9
298806c
6af9d85
83d398e
4f6ad76
84f11a7
0f5496d
581c663
2aa838e
fea347c
da7b89c
0a51480
fbab786
b992338
d36e090
f32eb78
575eecf
68599a9
604c893
f3eaff0
404fee3
3a97f89
cf9502e
680150a
903ff63
b43f302
7bfb649
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1596,5 +1596,84 @@ describe('add prepackaged rules schema', () => { | |
| }; | ||
| expect(message.schema).toEqual(expected); | ||
| }); | ||
|
|
||
| describe('threat_mapping', () => { | ||
| test('You can set a threat query, index, mapping, filters on a pre-packaged rule', () => { | ||
| const payload: AddPrepackagedRulesSchema = { | ||
| ...getAddPrepackagedRulesSchemaMock(), | ||
| threat_query: '*:*', | ||
|
||
| threat_index: 'list-index', | ||
| threat_mapping: [ | ||
| { | ||
| entries: [ | ||
| { | ||
| field: 'host.name', | ||
| value: 'host.name', | ||
| type: 'mapping', | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| threat_filters: [ | ||
| { | ||
| bool: { | ||
| must: [ | ||
| { | ||
| query_string: { | ||
| query: 'host.name: linux', | ||
| analyze_wildcard: true, | ||
| time_zone: 'Zulu', | ||
| }, | ||
| }, | ||
| ], | ||
| filter: [], | ||
| should: [], | ||
| must_not: [], | ||
| }, | ||
| }, | ||
| ], | ||
| }; | ||
|
|
||
| const decoded = addPrepackagedRulesSchema.decode(payload); | ||
| const checked = exactCheck(payload, decoded); | ||
| const message = pipe(checked, foldLeftRight); | ||
| expect(getPaths(left(message.errors))).toEqual([]); | ||
| const expected: AddPrepackagedRulesSchema = { | ||
| ...getAddPrepackagedRulesSchemaDecodedMock(), | ||
| threat_query: '*:*', | ||
| threat_index: 'list-index', | ||
| threat_mapping: [ | ||
| { | ||
| entries: [ | ||
| { | ||
| field: 'host.name', | ||
| value: 'host.name', | ||
| type: 'mapping', | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| threat_filters: [ | ||
| { | ||
| bool: { | ||
| must: [ | ||
| { | ||
| query_string: { | ||
| query: 'host.name: linux', | ||
| analyze_wildcard: true, | ||
| time_zone: 'Zulu', | ||
| }, | ||
| }, | ||
| ], | ||
| filter: [], | ||
| should: [], | ||
| must_not: [], | ||
| }, | ||
| }, | ||
| ], | ||
| }; | ||
| expect(message.schema).toEqual(expected); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1660,5 +1660,84 @@ describe('create rules schema', () => { | |||||
| }; | ||||||
| expect(message.schema).toEqual(expected); | ||||||
| }); | ||||||
|
|
||||||
| describe('threat_mapping', () => { | ||||||
| test('You can set a threat query, index, mapping, filters on a pre-packaged rule', () => { | ||||||
|
||||||
| test('You can set a threat query, index, mapping, filters on a pre-packaged rule', () => { | |
| test('You can set a threat query, index, mapping, filters when creating rule', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, good catch, fixed for the next commit
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,4 +87,71 @@ describe('create_rules_type_dependents', () => { | |
| const errors = createRuleValidateTypeDependents(schema); | ||
| expect(errors).toEqual(['"threshold.value" has to be bigger than 0']); | ||
| }); | ||
|
|
||
| test('threat_index, threat_query, and threat_mapping are required when type is "threat_match" and validates with it', () => { | ||
| const schema: CreateRulesSchema = { | ||
| ...getCreateRulesSchemaMock(), | ||
| type: 'threat_match', | ||
| }; | ||
| const errors = createRuleValidateTypeDependents(schema); | ||
| expect(errors).toEqual([ | ||
| 'when "type" is "threat_match", "threat_index" is required', | ||
| 'when "type" is "threat_match", "threat_query" is required', | ||
| 'when "type" is "threat_match", "threat_mapping" is required', | ||
| ]); | ||
| }); | ||
|
|
||
| test('validates with threat_index, threat_query, and threat_mapping when type is "threat_match"', () => { | ||
| const schema: CreateRulesSchema = { | ||
| ...getCreateRulesSchemaMock(), | ||
| type: 'threat_match', | ||
| threat_index: 'index-123', | ||
| threat_mapping: [{ entries: [{ field: '', type: 'mapping', value: '' }] }], | ||
| threat_query: '*:*', | ||
| }; | ||
| const errors = createRuleValidateTypeDependents(schema); | ||
| expect(errors).toEqual([]); | ||
| }); | ||
|
|
||
| test('does NOT validate when threat_mapping is an empty array', () => { | ||
| const schema: CreateRulesSchema = { | ||
| ...getCreateRulesSchemaMock(), | ||
| type: 'threat_match', | ||
| threat_index: 'index-123', | ||
| threat_mapping: [], | ||
| threat_query: '*:*', | ||
| }; | ||
| const errors = createRuleValidateTypeDependents(schema); | ||
| expect(errors).toEqual(['threat_mapping" must have at least one element']); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahhh, I see now here why this value defaults to |
||
| }); | ||
|
|
||
| test('validates with threat_index, threat_query, threat_mapping, and an optional threat_filters, when type is "threat_match"', () => { | ||
| const schema: CreateRulesSchema = { | ||
| ...getCreateRulesSchemaMock(), | ||
| type: 'threat_match', | ||
| threat_index: 'index-123', | ||
| threat_mapping: [{ entries: [{ field: '', type: 'mapping', value: '' }] }], | ||
| threat_query: '*:*', | ||
| threat_filters: [ | ||
| { | ||
| bool: { | ||
| must: [ | ||
| { | ||
| query_string: { | ||
| query: 'host.name: linux', | ||
| analyze_wildcard: true, | ||
| time_zone: 'Zulu', | ||
| }, | ||
| }, | ||
| ], | ||
| filter: [], | ||
| should: [], | ||
| must_not: [], | ||
| }, | ||
| }, | ||
| ], | ||
| }; | ||
| const errors = createRuleValidateTypeDependents(schema); | ||
| expect(errors).toEqual([]); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,6 +107,24 @@ export const validateThreshold = (rule: CreateRulesSchema): string[] => { | |
| return []; | ||
| }; | ||
|
|
||
| export const validateThreatMapping = (rule: CreateRulesSchema): string[] => { | ||
| let errors: string[] = []; | ||
| if (rule.type === 'threat_match') { | ||
|
||
| if (!rule.threat_mapping) { | ||
| errors = ['when "type" is "threat_match", "threat_mapping" is required', ...errors]; | ||
| } else if (rule.threat_mapping.length === 0) { | ||
| errors = ['threat_mapping" must have at least one element', ...errors]; | ||
| } | ||
| if (!rule.threat_query) { | ||
| errors = ['when "type" is "threat_match", "threat_query" is required', ...errors]; | ||
| } | ||
| if (!rule.threat_index) { | ||
| errors = ['when "type" is "threat_match", "threat_index" is required', ...errors]; | ||
| } | ||
| } | ||
| return errors; | ||
| }; | ||
|
|
||
| export const createRuleValidateTypeDependents = (schema: CreateRulesSchema): string[] => { | ||
| return [ | ||
| ...validateAnomalyThreshold(schema), | ||
|
|
@@ -117,5 +135,6 @@ export const createRuleValidateTypeDependents = (schema: CreateRulesSchema): str | |
| ...validateTimelineId(schema), | ||
| ...validateTimelineTitle(schema), | ||
| ...validateThreshold(schema), | ||
| ...validateThreatMapping(schema), | ||
| ]; | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: For fields that are arrays, do we want to default them to empty arrays? Or did you choose to default them to "undefined" to be more explicit about like if a rule is not of type "threat_match" these fields should not be there (as opposed to them being there and being [])?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah you answered the question below so I think we're good here 👍