-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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] Refactor signal ancestry to allow multiple parents #76531
Conversation
"ancestors": { | ||
"properties": { | ||
"rule": { | ||
"type": "keyword" | ||
}, | ||
"index": { |
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.
index
was in parent
but not here
@@ -58,7 +58,10 @@ export const buildBulkBody = ({ | |||
tags, | |||
throttle, | |||
}); | |||
const signal = buildSignal(doc, rule); | |||
const signal: Signal = { | |||
...buildSignal([doc], 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.
buildSignal
now expects an array of documents and handles building the rule, parents, and ancestors. additionalSignalFields
takes a single document and creates the fields for the special case where we only have 1 event triggering the signal (so we can copy the fields from the event into the signal). When we add signals based on EQL sequences we won't be able to copy every event from the sequence into the signal, instead relying on signal.parents
to contain references to the sub-events.
@@ -208,4 +210,102 @@ describe('buildRule', () => { | |||
}; | |||
expect(rule).toEqual(expected); | |||
}); | |||
|
|||
test('it builds a rule and removes internal tags', () => { |
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.
removeInternalTagsFromRule
now happens inside buildRule
so 1 additional test here.
}; | ||
expect(rule).toEqual(expected); | ||
}); | ||
|
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.
Next 4 tests are simply moved from build_signal.test.ts
since removeInternalTagsFromRule
was moved from build_signal.ts
to build_rule.ts
return removeInternalTagsFromRule(rule); | ||
}; | ||
|
||
export const removeInternalTagsFromRule = (rule: Partial<RulesSchema>): Partial<RulesSchema> => { |
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.
Cut/paste from build_signal.ts
since this is rule-related code.
expect(signal).toEqual(expected); | ||
}); | ||
|
||
test('it builds a signal as expected with original_event if is present and without internal tags in them', () => { |
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.
This test was deleted - buildSignal
is no longer responsible for removing internal tags. Test is replaced with the similar test above in build_rule.test.ts
expect(signal).toEqual(expected); | ||
}); | ||
|
||
test('it builds a ancestor correctly if the parent does exist without internal tags in them', () => { |
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.
Deleted this test - buildAncestor
no longer needs the rule, so it doesn't need to test a rule with internal tags in it.
}, | ||
]; | ||
expect(signal).toEqual(expected); | ||
}); | ||
|
||
test('it removes internal tags from a typical 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.
Next 4 tests moved to build_rule.test.ts
return { | ||
rule: rule.id != null ? rule.id : '', | ||
rule: doc._source.signal.rule.id, |
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.
Semantics change: signal.parents.rule
now contains the parent rule rather than current signal rule.
}; | ||
} else { | ||
return { | ||
rule: rule.id != null ? rule.id : '', |
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.
If the parent doc is not a signal, then there is no signal.parents.rule
return !doc._source.signal.ancestors.some((ancestor) => ancestor.rule === ruleId); | ||
return !( | ||
doc._source.signal.ancestors.some((ancestor) => ancestor.rule === ruleId) || | ||
doc._source.signal.rule.id === ruleId |
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.
Since signal.ancestors
no longer contains the rule id of the current signal we need to check signal.rule.id
as well as the ancestors.
parent: Ancestor; | ||
// parent is deprecated: new signals should populate parents instead | ||
// both are optional until all signals with parent are gone and we can safely remove it | ||
parent?: Ancestor; |
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.
SignalSource
represents the signal results coming from ES - we need to support pre-7.10 signals which may still have parent
or may have parents
.
Pinging @elastic/endpoint-response (Team:Endpoint Response) |
@elasticmachine merge upstream |
* creating an array of N+1 ancestors. | ||
* @param doc The parent signal/event for which to extend the ancestry. | ||
*/ | ||
export const buildAncestorsSignal = (doc: SignalSourceHit): Signal['ancestors'] => { |
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.
Can we rename this to buildAncestors
? For parity with buildParent
, and since this isn't actually building a signal...
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.
Let's get confirmation that the semantics changes are something we can get away with (for existing API users), but otherwise LGTM. Would also like to get that function renamed.
@elasticmachine merge upstream |
@@ -22,11 +22,33 @@ | |||
} | |||
} | |||
}, | |||
"parents": { | |||
"properties": { | |||
"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.
This is the rule.id
, not rule.rule_id
right? Curious if there's any upside to using one over the other. Like if users often import/export rules, would we lose tracing by using the id
?
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.
Right, this is rule.id
. I think for the parents/ancestry we want to know which specific instance of a rule generated the alert so id
is a good choice.
We could consider making signal.parent.rule
an object where we could have id
, rule_id
, and any other rule
fields that could be useful in signal.parent.rule.*
, but that would be a breaking change with the existing signal.parent
and signal.ancestors
so I think we'd need a migration.
depth: existingSignal.depth + 1, | ||
// We first look for signal.depth and use that if it exists. If it doesn't exist, this should be a pre-7.10 signal | ||
// and should have signal.parent.depth instead. signal.parent.depth in this case is treated as equivalent to signal.depth. | ||
depth: doc._source.signal.depth ?? doc._source.signal?.parent?.depth ?? 1, |
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.
Why is the ?
needed after doc._source.signal
- seems confusing since it was checked on line 16. Should I expect that value to exist in this block of code?
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.
Good point, it's not needed - I'll remove it.
* creating an array of N+1 ancestors. | ||
* @param doc The parent signal/event for which to extend the ancestry. | ||
*/ | ||
export const buildAncestors = (doc: SignalSourceHit): Signal['ancestors'] => { |
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: Are Signal['ancestors']
and Ancestor[]
equivalent? If they are, should we use Ancestor[]
for consistency, just so as a dev quickly looking through here it's clear buildParent
and buildAncestors
are returning the same type just one is array and the other isn't?
@elasticmachine merge upstream |
💚 Build SucceededBuild metrics
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. Created a rule (rule-1) which produced some signals on master, then checked out this branch and ran that rule + another rule (rule-2) to populate the "parents" field on signals generated by rule-2. Did not see an issue with migrations or anything on the signals table breaking. Looks good!
* master: (25 commits) [bugfix] Replace panel flyout opens 2 flyouts (elastic#76931) clean up test (elastic#76887) [Enterprise Search] Update shared API request handler (elastic#77112) [Maps] convert ESAggSource to TS (elastic#76999) Add plugin status API - take 2 (elastic#76732) Adds lens as a readable saved object for read-only dashboard users (elastic#77067) Skip checking for the reserved realm (elastic#76687) Reporting/diagnostics (elastic#74314) Reporting/Test: unskip non-screenshot tests (elastic#77088) Move metrics to setup and add cgroup metrics (elastic#76730) [Enterprise Search] Add Overview landing page/plugin (elastic#76734) First pass. Change TS type. Update OpenAPI (elastic#76434) [CI] Balance xpack ci groups a bit (elastic#77068) [Security_solution][Detections] Refactor signal ancestry to allow multiple parents (elastic#76531) [Maps] convert MetricsEditor to TS (elastic#76727) IndexMigrator: fix non blocking migration wrapper promise rejection (elastic#77018) [Enterprise Search] Update config data endpoint to v2 (elastic#76970) [ML] Add decision path charts to exploration results table (elastic#73561) Bump eventemitter3 from 4.0.0 to 4.0.7 (elastic#77016) [Ingest Pipelines] Add descriptions for ingest processors K-S (elastic#76981) ...
* master: (41 commits) [bugfix] Replace panel flyout opens 2 flyouts (elastic#76931) clean up test (elastic#76887) [Enterprise Search] Update shared API request handler (elastic#77112) [Maps] convert ESAggSource to TS (elastic#76999) Add plugin status API - take 2 (elastic#76732) Adds lens as a readable saved object for read-only dashboard users (elastic#77067) Skip checking for the reserved realm (elastic#76687) Reporting/diagnostics (elastic#74314) Reporting/Test: unskip non-screenshot tests (elastic#77088) Move metrics to setup and add cgroup metrics (elastic#76730) [Enterprise Search] Add Overview landing page/plugin (elastic#76734) First pass. Change TS type. Update OpenAPI (elastic#76434) [CI] Balance xpack ci groups a bit (elastic#77068) [Security_solution][Detections] Refactor signal ancestry to allow multiple parents (elastic#76531) [Maps] convert MetricsEditor to TS (elastic#76727) IndexMigrator: fix non blocking migration wrapper promise rejection (elastic#77018) [Enterprise Search] Update config data endpoint to v2 (elastic#76970) [ML] Add decision path charts to exploration results table (elastic#73561) Bump eventemitter3 from 4.0.0 to 4.0.7 (elastic#77016) [Ingest Pipelines] Add descriptions for ingest processors K-S (elastic#76981) ...
…rok/new-patterns-component-use-array * 'master' of github.com:elastic/kibana: (39 commits) [APM] Always load esarchives from common (elastic#77139) [Ingest Manager] Handle Legacy ES client errors (elastic#76865) [Docs] URL Drilldown (elastic#76529) [bugfix] Replace panel flyout opens 2 flyouts (elastic#76931) clean up test (elastic#76887) [Enterprise Search] Update shared API request handler (elastic#77112) [Maps] convert ESAggSource to TS (elastic#76999) Add plugin status API - take 2 (elastic#76732) Adds lens as a readable saved object for read-only dashboard users (elastic#77067) Skip checking for the reserved realm (elastic#76687) Reporting/diagnostics (elastic#74314) Reporting/Test: unskip non-screenshot tests (elastic#77088) Move metrics to setup and add cgroup metrics (elastic#76730) [Enterprise Search] Add Overview landing page/plugin (elastic#76734) First pass. Change TS type. Update OpenAPI (elastic#76434) [CI] Balance xpack ci groups a bit (elastic#77068) [Security_solution][Detections] Refactor signal ancestry to allow multiple parents (elastic#76531) [Maps] convert MetricsEditor to TS (elastic#76727) IndexMigrator: fix non blocking migration wrapper promise rejection (elastic#77018) [Enterprise Search] Update config data endpoint to v2 (elastic#76970) ... # Conflicts: # src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts
* master: (38 commits) Reporting/Test: unskip non-screenshot tests (elastic#77088) Move metrics to setup and add cgroup metrics (elastic#76730) [Enterprise Search] Add Overview landing page/plugin (elastic#76734) First pass. Change TS type. Update OpenAPI (elastic#76434) [CI] Balance xpack ci groups a bit (elastic#77068) [Security_solution][Detections] Refactor signal ancestry to allow multiple parents (elastic#76531) [Maps] convert MetricsEditor to TS (elastic#76727) IndexMigrator: fix non blocking migration wrapper promise rejection (elastic#77018) [Enterprise Search] Update config data endpoint to v2 (elastic#76970) [ML] Add decision path charts to exploration results table (elastic#73561) Bump eventemitter3 from 4.0.0 to 4.0.7 (elastic#77016) [Ingest Pipelines] Add descriptions for ingest processors K-S (elastic#76981) [Metrics UI] Replace Snapshot API with Metrics API (elastic#76253) legacy utils cleanup (elastic#76608) [ML] Account for "properties" layer in find_file_structure mappings (elastic#77035) fixed typo Upgrade to Kea 2.2 (elastic#77047) a11y tests on spaces home page including feature control (elastic#76515) [ML] Transforms list: persist pagination through refresh interval (elastic#76786) [ML] Replace all use of date_histogram interval with fixed_interval (elastic#76876) ...
Friendly reminder: Looks like this PR hasn’t been backported yet. |
…tiple parents (elastic#76531) * Refactors signal ancestry to allow multiple parents * Fix depth calculation for 7.10+ signals on pre-7.10 signals * Comment build_signal functions * Rename buildAncestorsSignal to buildAncestors * Update detection engine depth test scripts and docs * Update halting test readme * Match up rule ids in readme * Continue populating signal.parent along with signal.parents * pr comments Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…tiple parents (#76531) (#77346) * Refactors signal ancestry to allow multiple parents * Fix depth calculation for 7.10+ signals on pre-7.10 signals * Comment build_signal functions * Rename buildAncestorsSignal to buildAncestors * Update detection engine depth test scripts and docs * Update halting test readme * Match up rule ids in readme * Continue populating signal.parent along with signal.parents * pr comments Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Summary
Remaining issues:
TODO: Force mapping update so existing signal indices will add the new fields (
signal.depth
,signal.parents
,signal.ancestors.index
) to the mappingThis PR changes the way that
signal.parent.rule
andsignal.ancestors.rule
are populated, as well assignal.parent.depth
andsignal.ancestors.depth
. They will contain the rule and depth of the parent event rather than the current event as they do now. It also deprecatessignal.parent
in favor ofsignal.parents
which is expected to be an array of parent events/signals. It also refactorsbuildSignal
to make it easy to build a signal from one or multiple events.signal.parent
currently contains a mix of information from the current signal and the parent signal/event -signal.parent.rule
contains the current rule id (not the parent rule id), but the other fields such assignal.parent.id
are from the parent signal/event.Existing signal structure chart
New signal structure chart WITHOUT sequence based rule
New signal structure chart WITH sequence based rule (and using the signal above as an input)
Post 7.10 signals that are built on pre-7.10 signals will have some duplication in
signal.ancestors.rule
andsignal.ancestors.depth
. If a post-7.10 signal is built on a pre-7.10 chain of signals, thensignal.ancestors
will beThe rule de-duplication logic that prevents a rule from triggering on a signal with that same rule in its ancestry still works in this case since no data is missing.
Checklist
Delete any items that are not applicable to this PR.
For maintainers