[Security_solution][Detections] Refactor signal ancestry to allow multiple parents#76531
Conversation
| "rule": { | ||
| "type": "keyword" | ||
| }, | ||
| "index": { |
There was a problem hiding this comment.
index was in parent but not here
| }); | ||
| const signal = buildSignal(doc, rule); | ||
| const signal: Signal = { | ||
| ...buildSignal([doc], rule), |
There was a problem hiding this comment.
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.
| expect(rule).toEqual(expected); | ||
| }); | ||
|
|
||
| test('it builds a rule and removes internal tags', () => { |
There was a problem hiding this comment.
removeInternalTagsFromRule now happens inside buildRule so 1 additional test here.
| }; | ||
| expect(rule).toEqual(expected); | ||
| }); | ||
|
|
There was a problem hiding this comment.
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.
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.
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.
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.
Next 4 tests moved to build_rule.test.ts
| if (doc._source.signal != null) { | ||
| return { | ||
| rule: rule.id != null ? rule.id : '', | ||
| rule: doc._source.signal.rule.id, |
There was a problem hiding this comment.
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.
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.
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.
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.
Can we rename this to buildAncestors? For parity with buildParent, and since this isn't actually building a signal...
madirey
left a comment
There was a problem hiding this comment.
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 |
| }, | ||
| "parents": { | ||
| "properties": { | ||
| "rule": { |
There was a problem hiding this comment.
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.
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.
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.
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.
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: |
dhurley14
left a comment
There was a problem hiding this comment.
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.ruleandsignal.ancestors.ruleare populated, as well assignal.parent.depthandsignal.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.parentin favor ofsignal.parentswhich is expected to be an array of parent events/signals. It also refactorsbuildSignalto make it easy to build a signal from one or multiple events.signal.parentcurrently contains a mix of information from the current signal and the parent signal/event -signal.parent.rulecontains the current rule id (not the parent rule id), but the other fields such assignal.parent.idare 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.ruleandsignal.ancestors.depth. If a post-7.10 signal is built on a pre-7.10 chain of signals, thensignal.ancestorswill 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