-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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][Detections] Support arrays in event fields for Severity/Risk overrides #83723
[Security Solution][Detections] Support arrays in event fields for Severity/Risk overrides #83723
Conversation
568f46c
to
75ad0ca
Compare
7c96731
to
80503d9
Compare
80503d9
to
56f0f7f
Compare
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.
Did a cursory code review; most of my comments are nits, FYI.
The additional logic looks good to me, but I'm not going to explicitly approve because I haven't touched/am not familiar with this code. I'm happy to do another pass here when this is out of draft, though!
expected: BuildRiskScoreFromMappingReturn; | ||
} | ||
|
||
function testIt({ fieldValue, scoreDefault, scoreMapping, expected }: TestCase) { |
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.
nit: we tend to prefer arrow functions
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.
nit: I would personally do away with the testIt
function as I find it makes the tests a bit too convoluted, but that's totally subjective.
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.
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.
On functions, arrows vs fn expressions vs fn declarations. Normally, unless there's a different coding standard/guideline, to vertically structure the code I prefer using the "newspaper metaphor" coined by Uncle Bob in his Clean Code book.
Newspaper Metaphor. The source file should be organized like a newspaper article, with the highest level summary at the top, and more and more details further down. Functions called from the top function come directly below it, and so on down to the lowest level and most detailed functions at the bottom. This is a good way to organize the source code, even though IDE:s make the location of functions less important, since it is so easy to navigate in and out of them.
It's a top-down approach, from general things to details, and it's possible with function declarations. With arrows and fn expressions it's possible to use the opposite bottow-up approach, where you first have details, helper functions etc, and at the bottom of the file there's let's say the main function.
Normally I use arrows in all other cases: inline calls, closures to an outer this, just a bunch of small independent functions in a file (e.g. selectors), etc.
Of course I wouldn't go against our guidelines, whether they are documented or not, and against the typical style of the codebase. For the sake of consistency.
Hopefully I managed to explain my motivation. Let me know what you think. Although the styleguide uses fn declarations, it's a general one. If this style looks too foreign for the security_solution
plugin's codebase, I'll change it to the one based on arrows.
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.
On the testIt
helper. Yea, it definitely has pros and cons. It reduces duplication and makes the test suite shorter, but abstracts away some details. One can perceive it as either good or bad thing in terms of readability and easiness to understand the tests. I personally find that as soon as you got what testIt
does, it's easier and faster to read all the tests. On the other hand, it can be just a bit harder to start reading the tests once you opened the file.
If you don't have tests written in such a way and/or don't like it (yes, even subjectively), I'll refactor. But maybe there are people who are ok with that?
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.
Any opinions, clarifications, comments or just votes are super-welcome. This helps me a lot with learning the codebase faster.
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.
"Newspaper metaphor" with fn declarations?
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.
testIt
helper?
return doc; | ||
}; | ||
|
||
export const sampleDocRiskScore = (riskScore?: unknown): SignalSourceHit => ({ |
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.
Nit: we're starting to add a lot of indirection to these tests, and I question the utility of such a method over something like:
const testEventWithDescriptiveName = {
...buildSpecificEventType(),
[fieldName]: overriddenValue,
};
For context: my perception has been that we typically prefer repetitive, inline test logic as opposed to shared helpers, with the exceptions of (normalized) data generation and ad hoc test helpers within the test file.
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.
Discussed with @rylnd. We talked about creating test data factories and all that patterns in general, agreed on a few ideas, but no action required for this PR.
} | ||
|
||
function getMaxOf(array: number[]) { | ||
// NOTE: It's safer to use reduce rather than Math.max(...array). The latter won't handle large input. |
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.
Huh, TIL!
..._solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.test.ts
Outdated
Show resolved
Hide resolved
...urity_solution/server/lib/detection_engine/signals/mappings/build_risk_score_from_mapping.ts
Show resolved
Hide resolved
...ecurity_solution/server/lib/detection_engine/signals/mappings/build_severity_from_mapping.ts
Outdated
Show resolved
Hide resolved
bbb3f75
to
22b227f
Compare
Pinging @elastic/siem (Team:SIEM) |
22b227f
to
713134b
Compare
713134b
to
153063c
Compare
💚 Build SucceededMetrics [docs]
History
To update your PR or re-run it, just comment with: |
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.
LGTM. Tested functionality with various severity and risk score combinations, including array values, and the generated signals respected the mappings and yielded expected results. Thanks for the fix and for the added FTR test coverage as well!
Just for the record, here's the data I used to test the fix manually: ###### Testing mapping as described in the GitHub issue (slightly extended)
PUT delme-test-overrides
{
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": {
"type": "date"
},
"severity_override": {
"type": "keyword"
},
"risk_override": {
"type": "integer"
}
}
}
}
PUT delme-test-overrides/_doc/1
{
"@timestamp": "2020-11-24T13:00:01.000Z",
"severity_override" : "sev_90",
"risk_override": 3.14
}
PUT delme-test-overrides/_doc/2
{
"@timestamp": "2020-11-24T13:00:02.000Z",
"severity_override": ["sev_90", "sev_max"],
"risk_override": [3.14]
}
PUT delme-test-overrides/_doc/3
{
"@timestamp": "2020-11-24T13:00:03.000Z",
"severity_override": ["sev_max", "sev_90"],
"risk_override": "3.14"
}
PUT delme-test-overrides/_doc/4
{
"@timestamp": "2020-11-24T13:00:04.000Z",
"severity_override": "sev_max",
"risk_override": [1.23, "3.14"]
}
PUT delme-test-overrides/_doc/5
{
"@timestamp": "2020-11-24T13:00:05.000Z",
"severity_override": 99
}
###### Testing mapping to integer non-ECS severity field
PUT delme-test-overrides-sev-int
{
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": {
"type": "date"
},
"severity_override": {
"type": "long"
}
}
}
}
PUT delme-test-overrides-sev-int/_doc/1
{
"@timestamp": "2020-11-29T13:00:01.000Z",
"severity_override": 60
}
PUT delme-test-overrides-sev-int/_doc/2
{
"@timestamp": "2020-11-29T13:00:02.000Z",
"severity_override": 70
}
PUT delme-test-overrides-sev-int/_doc/3
{
"@timestamp": "2020-11-29T13:00:03.000Z",
"severity_override": 80
}
PUT delme-test-overrides-sev-int/_doc/4
{
"@timestamp": "2020-11-29T13:00:04.000Z",
"severity_override": 90
}
###### Testing mapping to integer event.severity field from ECS
PUT delme-test-overrides-sev-ecs
{
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": {
"type": "date"
},
"event": {
"properties": {
"severity": {
"type": "long"
}
}
}
}
}
}
PUT delme-test-overrides-sev-ecs/_doc/1
{
"@timestamp": "2020-11-30T13:00:01.000Z",
"event": {
"severity": 60
}
}
PUT delme-test-overrides-sev-ecs/_doc/2
{
"@timestamp": "2020-11-30T13:00:02.000Z",
"event": {
"severity": 70
}
}
PUT delme-test-overrides-sev-ecs/_doc/3
{
"@timestamp": "2020-11-30T13:00:03.000Z",
"event": {
"severity": 80
}
}
PUT delme-test-overrides-sev-ecs/_doc/4
{
"@timestamp": "2020-11-30T13:00:04.000Z",
"event": {
"severity": 90
}
}
###### Testing mapping support in EQL rules
PUT delme-test-overrides-sev-eql
{
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": {
"type": "date"
},
"event": {
"properties": {
"category": {
"type": "keyword"
}
}
},
"params": {
"properties": {
"severity_override": {
"type": "keyword"
}
}
}
}
}
}
PUT delme-test-overrides-sev-eql/_doc/1
{
"@timestamp": "2020-12-01T08:00:01.000Z",
"event": {
"category": "authentication"
},
"params": {
"severity_override": "sev_90"
}
}
PUT delme-test-overrides-sev-eql/_doc/2
{
"@timestamp": "2020-12-01T08:00:02.000Z",
"event": {
"category": "authentication"
},
"params": {
"severity_override": "sev_max"
}
}
#############################
GET _cat/shards/delme-test-overrides*?v&s=shard,prirep
GET delme-test-overrides/_search
GET delme-test-overrides-sev-int/_search
GET delme-test-overrides-sev-ecs/_search
GET delme-test-overrides-sev-eql/_search
DELETE delme-test-overrides* |
…verity/Risk overrides (elastic#83723) This PR changes the behavior of severity and risk score overrides in two ways: - adds support for arrays in the mapped event fields (so a rule can be triggered by an event where e.g. `event.custom_severity` has a value like `[45, 70, 90]`) - makes the logic of overrides more flexible, resilient to the incoming values (filters out junk, extracts meaningful values, does its best to find a value that would fit the mapping)
…verity/Risk overrides (#83723) (#84643) This PR changes the behavior of severity and risk score overrides in two ways: - adds support for arrays in the mapped event fields (so a rule can be triggered by an event where e.g. `event.custom_severity` has a value like `[45, 70, 90]`) - makes the logic of overrides more flexible, resilient to the incoming values (filters out junk, extracts meaningful values, does its best to find a value that would fit the mapping)
* master: (63 commits) Revert the Revert of "[Alerting] renames Resolved action group to Recovered (elastic#84123)" (elastic#84662) declare kbn/monaco dependency on kbn/i18n explicitly (elastic#84660) Remove unscripted fields from sample data index-pattern saved objects (elastic#84659) [ML] Fix unnecessary trigger of wildcard field type search for ML plugin routes. (elastic#84605) Update create.asciidoc (elastic#84046) [Security Solution][Detections] Fix labels and issue with mandatory fields (elastic#84525) Fix flaky test suite (elastic#84602) [Security Solution] [Detections] Create a 'partial failure' status for rules (elastic#84293) Revert "[Alerting] renames Resolved action group to Recovered (elastic#84123)" Update code-comments describing babel plugins (elastic#84622) [Security Solution] [Cases] Cypress for case connector selector options (elastic#80745) [Discover] Unskip doc table tests (elastic#84564) [Lens] (Accessibility) Improve landmarks in Lens (elastic#84511) [Lens] (Accessibility) Focus mistakenly stops on righthand form (elastic#84519) Return early when parallel install process detected (elastic#84190) [Security Solution][Detections] Support arrays in event fields for Severity/Risk overrides (elastic#83723) [Security Solution][Detections] Fix grammatical error in validation message for threshold field in "Create new rule" -> "Define rule" (elastic#84490) [Fleet] Update agent details page (elastic#84434) adding documentation of use of NODE_EXTRA_CA_CERTS env var (elastic#84578) [Search] Integrate "Send to background" UI with session service (elastic#83073) ...
Addresses: #82384
Summary
This PR changes the behavior of severity and risk score overrides in two ways:
event.custom_severity
has a value like[45, 70, 90]
)TODO:
Useful info
You might find useful some background info on severity and risk score overrides, as well as fields from ECS corresponding to them.
event.risk_score
event.risk_score_norm
event.severity
Testing
Frank clearly described how to reproduce the bug in the parent issue: #82384
This instruction can be used to do manual QA and make sure the bug is fixed.
Also, I added a few FTR integration tests for the overrides:
x-pack/test/detection_engine_api_integration/security_and_spaces/tests/generating_signals.ts
x-pack/test/functional/es_archives/signals/severity_risk_overrides
You can run them with:
Tests implementation is based on #83764.
Checklist
Delete any items that are not applicable to this PR.
For maintainers