Skip to content

[Security Solution] Two-way prebuilt rule diff#233045

Merged
dplumlee merged 14 commits intoelastic:mainfrom
dplumlee:rule-diff-2-way
Sep 11, 2025
Merged

[Security Solution] Two-way prebuilt rule diff#233045
dplumlee merged 14 commits intoelastic:mainfrom
dplumlee:rule-diff-2-way

Conversation

@dplumlee
Copy link
Contributor

@dplumlee dplumlee commented Aug 27, 2025

Partially addresses: https://github.com/elastic/security-team/issues/12507 (internal)

Summary

Adds a 2-way diff comparison algorithm to the codebase and shifts the existing diff code to a "three-way" naming scheme.

In order for the telemetry work described in #230856 to occur, we need to refactor our diff calculation method to return rule schema fields instead of the DiffableRule schema that we currently return. This required a lot of exploratory work to determine the best method in which to accomplish this refactor, as the core function, calculateRuleDiffFields, is used as a core piece of logic in all our prebuilt rule customization related endpoints, and most of our UI components are reliant on this DiffableRule based return structure.

I settled on an approach that adds a separate 2-way diff function that never converts the rule into the diffable rule structure, allowing us to directly compare the rule objects and return exact rule schema fields. This also involved refactoring the normalization process we did in convertToDiffable and extracting out the comparison functions we used in the diff algorithms, so that both diff algorithms would be returning identical "is_customized" calculations given a set of RuleResponse objects.

This PR adds a comprehensive set of tests that verify the synchronization of these two diff algorithms for ease of maintainability and to greatly lessen the possibility of divergence.

This PR also swaps out the is_customized rule source calculation with the new 2-way diff calculation, all tests are running (and passing) with this new diff calculation.

Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.

@dplumlee dplumlee self-assigned this Aug 27, 2025
@dplumlee dplumlee added release_note:skip Skip the PR/issue when compiling release notes Team:Detections and Resp Security Detection Response Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. Team:Detection Rule Management Security Detection Rule Management Team Feature:Prebuilt Detection Rules Security Solution Prebuilt Detection Rules area backport:version Backport to applied version labels v9.2.0 labels Sep 4, 2025
@dplumlee dplumlee marked this pull request as ready for review September 4, 2025 15:15
@dplumlee dplumlee requested review from a team as code owners September 4, 2025 15:15
@dplumlee dplumlee requested a review from maximpn September 4, 2025 15:15
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-detections-response (Team:Detections and Resp)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-detection-rule-management (Team:Detection Rule Management)

@dplumlee dplumlee changed the title [Security Solution] 2 way rule diff POC [Security Solution] 2 way rule diff Sep 4, 2025
@dplumlee dplumlee changed the title [Security Solution] 2 way rule diff [Security Solution] Two-way prebuilt rule diff Sep 4, 2025
@banderror banderror requested review from banderror and jkelas and removed request for maximpn September 4, 2025 15:35
Copy link
Contributor

@jkelas jkelas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dplumlee I reviewed the code thoroughly. Also thank you for the session with explanation of lots of the intricacies of this code, this helped me much.

The code looks very good. I only left several remarks, non-critical.

I did manual testing of the code by running Kibana and making sure the diffing and comparing functionality didn't change versus baseline.

Please also run Flaky Test Runner


const fieldsDiff: Partial<RuleDiffOutcome<TwoWayDiffRule>> = {};

const keys = new Set([...Object.keys(normalizedBaseRule), ...Object.keys(normalizedCurrentRule)]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if we should not rather take keys from allFieldsComparators and not from the compared rules.
That way the source of the truth for this comparison logic would be our comparators definition here, not the RuleResponse. If we some day add a field to a rule, and forget adding a comparator for it here, it would silently be ignored. We should rather detect it, and be forced to add also a comparator (thus I would also suggest removing the if (comparator) ).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought through this some more but am leaning more toward leaving it as is with the added comment descriptions. I think keeping the source of truth as the RuleResponse schema should be the preferred method. The types are already set up to throw an error if a RuleResponse field is missing from the list of comparators if not already omitted on purpose (like what we do with actions, exceptions_list, etc.) and would do so if another field were added to RuleResponse, ensuring a field wouldn't be ignored unless explicitly defined to be ignored.

This way, we also return only the fields in the rules given instead of having a superset of all rule type fields in the outcome object. Currently, we only use this object to sort through for fields not equal between two rules, but it might be useful down the line to have a list of fields present instead of that superset. Not to mention we wouldn't have to compare a bunch of non-existent fields every time we do this diff calculation


import { normalizeQueryField } from './normalize_query_field';

describe('normalizeQueryField', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a few more tests to cover for spaces, \t, null, undefined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in cb3638b

@dplumlee dplumlee requested a review from jkelas September 8, 2025 19:33
@dplumlee
Copy link
Contributor Author

dplumlee commented Sep 8, 2025

@jkelas thanks for reviewing, I addressed all your comments and added further test coverage and documentation in the code, please take another look!

@kibanamachine
Copy link
Contributor

Flaky Test Runner Stats

🎉 All tests passed! - kibana-flaky-test-suite-runner#9302

[✅] Security Solution Rule Management - Prebuilt Rules Customization - Cypress: 100/100 tests passed.
[✅] [Serverless] Security Solution Rule Management - Prebuilt Rules Customization - Cypress: 100/100 tests passed.

see run history

@kibanamachine
Copy link
Contributor

Flaky Test Runner Stats

🎉 All tests passed! - kibana-flaky-test-suite-runner#9301

[✅] x-pack/solutions/security/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/customization_enabled/configs/ess.config.ts: 100/100 tests passed.
[✅] x-pack/solutions/security/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/customization_enabled/configs/serverless.config.ts: 100/100 tests passed.

see run history

Copy link
Contributor

@jkelas jkelas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dplumlee for addressing my comments. I reviewed and I think the code looks very good. I am approving.

@dplumlee dplumlee added the v9.1.4 label Sep 9, 2025
Copy link
Contributor

@banderror banderror left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, this looks like the right direction to move forward. Overall changes LGTM.

I ended up posting a lot of comments, all of them are pretty minor. I'm suggesting to do a bit more polishing and improve the structure of the code and naming to make it easier to read, navigate, maintain, and make it consistent with the three-way diff model.

I didn't review the synchronization tests and didn't test the PR for any potential regressions. Please review and consider addressing my comments, so hopefully we can wrap up this review and merge the PR tomorrow.

I really liked the refactoring that separated concerns properly and introduced these new extractors and normalizers 👍

Thanks @dplumlee!

Comment on lines +52 to +54
const comparator = allFieldsComparators[fieldKey] as
| ((a: unknown, b: unknown) => boolean)
| undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's too many as type castings in this function which is a code smell. There's probably something we can do to make the code type safe.

@banderror
Copy link
Contributor

banderror commented Sep 10, 2025

@elasticmachine merge upstream

Copy link
Contributor

@banderror banderror left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dplumlee The resulting PR looks perfect. Thanks for the great work!

chefs-kiss

@dplumlee dplumlee enabled auto-merge (squash) September 10, 2025 17:25
@dplumlee dplumlee merged commit b08abf7 into elastic:main Sep 11, 2025
12 checks passed
@kibanamachine
Copy link
Contributor

Starting backport for target branches: 9.1

https://github.com/elastic/kibana/actions/runs/17635485268

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
securitySolution 7973 7977 +4

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 10.5MB 10.5MB +3.0KB

Saved Objects .kibana field count

Every field in each saved object type adds overhead to Elasticsearch. Kibana needs to keep the total field count below Elasticsearch's default limit of 1000 fields. Only specify field mappings for the fields you wish to search on or query. See https://www.elastic.co/guide/en/kibana/master/saved-objects-service.html#_mappings

id before after diff
_data_stream_timestamp 1 - -1
_doc_count 1 - -1
_ignored_source 1 - -1
_index_mode 1 - -1
_inference_fields 1 - -1
_tier 1 - -1
apm-custom-dashboards 5 - -5
apm-server-schema 2 - -2
apm-service-group 5 - -5
application_usage_daily 2 - -2
config 2 - -2
config-global 2 - -2
coreMigrationVersion 1 - -1
created_at 1 - -1
created_by 1 - -1
entity-definition 9 - -9
entity-discovery-api-key 2 - -2
event_loop_delays_daily 2 - -2
favorites 4 - -4
file 11 - -11
file-upload-usage-collection-telemetry 3 - -3
fileShare 5 - -5
infra-custom-dashboards 4 - -4
infrastructure-monitoring-log-view 2 - -2
intercept_trigger_record 5 - -5
legacy-url-alias 7 - -7
managed 1 - -1
ml-job 6 - -6
ml-module 13 - -13
ml-trained-model 7 - -7
monitoring-telemetry 2 - -2
namespace 1 - -1
namespaces 1 - -1
observability-onboarding-state 2 - -2
originId 1 - -1
product-doc-install-status 7 - -7
references 4 - -4
sample-data-telemetry 3 - -3
security-ai-prompt 8 - -8
slo 11 - -11
space 5 - -5
synthetics-monitor 34 - -34
synthetics-monitor-multi-space 34 - -34
tag 4 - -4
type 1 - -1
typeMigrationVersion 1 - -1
ui-metric 2 - -2
updated_at 1 - -1
updated_by 1 - -1
upgrade-assistant-ml-upgrade-operation 3 - -3
upgrade-assistant-reindex-operation 3 - -3
uptime-synthetics-api-key 2 - -2
url 5 - -5
usage-counters 2 - -2
total -246

History

cc @dplumlee

kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Sep 11, 2025
**Partially addresses:**
elastic/security-team#12507 (internal)

## Summary

Adds a 2-way diff comparison algorithm to the codebase and shifts the
existing diff code to a "three-way" naming scheme.

In order for the telemetry work described in
elastic#230856 to occur, we need to
refactor our diff calculation method to return rule schema fields
instead of the `DiffableRule` schema that we currently return. This
required a lot of exploratory work to determine the best method in which
to accomplish this refactor, as the core function,
`calculateRuleDiffFields`, is used as a core piece of logic in all our
prebuilt rule customization related endpoints, and most of our UI
components are reliant on this `DiffableRule` based return structure.

I settled on an approach that adds a separate 2-way diff function that
never converts the rule into the diffable rule structure, allowing us to
directly compare the rule objects and return exact rule schema fields.
This also involved refactoring the normalization process we did in
`convertToDiffable` and extracting out the comparison functions we used
in the diff algorithms, so that both diff algorithms would be returning
identical "is_customized" calculations given a set of `RuleResponse`
objects.

This PR adds a comprehensive set of tests that verify the
synchronization of these two diff algorithms for ease of maintainability
and to greatly lessen the possibility of divergence.

This PR also swaps out the `is_customized` rule source calculation with
the new 2-way diff calculation, all tests are running (and passing) with
this new diff calculation.

### Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.

- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] [FTR tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9301)
- [x] [Cypress tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9302)

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
(cherry picked from commit b08abf7)
@kibanamachine
Copy link
Contributor

💚 All backports created successfully

Status Branch Result
9.1

Note: Successful backport PRs will be merged automatically after passing CI.

Questions ?

Please refer to the Backport tool documentation

kibanamachine added a commit that referenced this pull request Sep 11, 2025
# Backport

This will backport the following commits from `main` to `9.1`:
- [[Security Solution] Two-way prebuilt rule diff
(#233045)](#233045)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Davis
Plumlee","email":"56367316+dplumlee@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-09-11T06:00:54Z","message":"[Security
Solution] Two-way prebuilt rule diff (#233045)\n\n**Partially
addresses:**\nhttps://github.com/elastic/security-team/issues/12507
(internal)\n\n## Summary\n\nAdds a 2-way diff comparison algorithm to
the codebase and shifts the\nexisting diff code to a \"three-way\"
naming scheme.\n\nIn order for the telemetry work described
in\nhttps://github.com//pull/230856 to occur, we need
to\nrefactor our diff calculation method to return rule schema
fields\ninstead of the `DiffableRule` schema that we currently return.
This\nrequired a lot of exploratory work to determine the best method in
which\nto accomplish this refactor, as the core
function,\n`calculateRuleDiffFields`, is used as a core piece of logic
in all our\nprebuilt rule customization related endpoints, and most of
our UI\ncomponents are reliant on this `DiffableRule` based return
structure.\n\nI settled on an approach that adds a separate 2-way diff
function that\nnever converts the rule into the diffable rule structure,
allowing us to\ndirectly compare the rule objects and return exact rule
schema fields.\nThis also involved refactoring the normalization process
we did in\n`convertToDiffable` and extracting out the comparison
functions we used\nin the diff algorithms, so that both diff algorithms
would be returning\nidentical \"is_customized\" calculations given a set
of `RuleResponse`\nobjects.\n\nThis PR adds a comprehensive set of tests
that verify the\nsynchronization of these two diff algorithms for ease
of maintainability\nand to greatly lessen the possibility of
divergence.\n\nThis PR also swaps out the `is_customized` rule source
calculation with\nthe new 2-way diff calculation, all tests are running
(and passing) with\nthis new diff calculation.\n\n### Checklist\n\nCheck
the PR satisfies following conditions. \n\nReviewers should verify this
PR satisfies this list as well.\n\n-
[x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas
added for features that require explanation or tutorials\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] [FTR
tests\nrun](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9301)\n-
[x] [Cypress
tests\nrun](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9302)\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"b08abf72b878f5001096796d51cefbdebff5a171","branchLabelMapping":{"^v9.2.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["refactoring","release_note:skip","Team:Detections
and Resp","Team: SecuritySolution","Team:Detection Rule
Management","Feature:Prebuilt Detection
Rules","backport:version","v9.2.0","v9.1.4"],"title":"[Security
Solution] Two-way prebuilt rule
diff","number":233045,"url":"https://github.com/elastic/kibana/pull/233045","mergeCommit":{"message":"[Security
Solution] Two-way prebuilt rule diff (#233045)\n\n**Partially
addresses:**\nhttps://github.com/elastic/security-team/issues/12507
(internal)\n\n## Summary\n\nAdds a 2-way diff comparison algorithm to
the codebase and shifts the\nexisting diff code to a \"three-way\"
naming scheme.\n\nIn order for the telemetry work described
in\nhttps://github.com//pull/230856 to occur, we need
to\nrefactor our diff calculation method to return rule schema
fields\ninstead of the `DiffableRule` schema that we currently return.
This\nrequired a lot of exploratory work to determine the best method in
which\nto accomplish this refactor, as the core
function,\n`calculateRuleDiffFields`, is used as a core piece of logic
in all our\nprebuilt rule customization related endpoints, and most of
our UI\ncomponents are reliant on this `DiffableRule` based return
structure.\n\nI settled on an approach that adds a separate 2-way diff
function that\nnever converts the rule into the diffable rule structure,
allowing us to\ndirectly compare the rule objects and return exact rule
schema fields.\nThis also involved refactoring the normalization process
we did in\n`convertToDiffable` and extracting out the comparison
functions we used\nin the diff algorithms, so that both diff algorithms
would be returning\nidentical \"is_customized\" calculations given a set
of `RuleResponse`\nobjects.\n\nThis PR adds a comprehensive set of tests
that verify the\nsynchronization of these two diff algorithms for ease
of maintainability\nand to greatly lessen the possibility of
divergence.\n\nThis PR also swaps out the `is_customized` rule source
calculation with\nthe new 2-way diff calculation, all tests are running
(and passing) with\nthis new diff calculation.\n\n### Checklist\n\nCheck
the PR satisfies following conditions. \n\nReviewers should verify this
PR satisfies this list as well.\n\n-
[x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas
added for features that require explanation or tutorials\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] [FTR
tests\nrun](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9301)\n-
[x] [Cypress
tests\nrun](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9302)\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"b08abf72b878f5001096796d51cefbdebff5a171"}},"sourceBranch":"main","suggestedTargetBranches":["9.1"],"targetPullRequestStates":[{"branch":"main","label":"v9.2.0","branchLabelMappingKey":"^v9.2.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/233045","number":233045,"mergeCommit":{"message":"[Security
Solution] Two-way prebuilt rule diff (#233045)\n\n**Partially
addresses:**\nhttps://github.com/elastic/security-team/issues/12507
(internal)\n\n## Summary\n\nAdds a 2-way diff comparison algorithm to
the codebase and shifts the\nexisting diff code to a \"three-way\"
naming scheme.\n\nIn order for the telemetry work described
in\nhttps://github.com//pull/230856 to occur, we need
to\nrefactor our diff calculation method to return rule schema
fields\ninstead of the `DiffableRule` schema that we currently return.
This\nrequired a lot of exploratory work to determine the best method in
which\nto accomplish this refactor, as the core
function,\n`calculateRuleDiffFields`, is used as a core piece of logic
in all our\nprebuilt rule customization related endpoints, and most of
our UI\ncomponents are reliant on this `DiffableRule` based return
structure.\n\nI settled on an approach that adds a separate 2-way diff
function that\nnever converts the rule into the diffable rule structure,
allowing us to\ndirectly compare the rule objects and return exact rule
schema fields.\nThis also involved refactoring the normalization process
we did in\n`convertToDiffable` and extracting out the comparison
functions we used\nin the diff algorithms, so that both diff algorithms
would be returning\nidentical \"is_customized\" calculations given a set
of `RuleResponse`\nobjects.\n\nThis PR adds a comprehensive set of tests
that verify the\nsynchronization of these two diff algorithms for ease
of maintainability\nand to greatly lessen the possibility of
divergence.\n\nThis PR also swaps out the `is_customized` rule source
calculation with\nthe new 2-way diff calculation, all tests are running
(and passing) with\nthis new diff calculation.\n\n### Checklist\n\nCheck
the PR satisfies following conditions. \n\nReviewers should verify this
PR satisfies this list as well.\n\n-
[x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas
added for features that require explanation or tutorials\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [x] [FTR
tests\nrun](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9301)\n-
[x] [Cypress
tests\nrun](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9302)\n\n---------\n\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"b08abf72b878f5001096796d51cefbdebff5a171"}},{"branch":"9.1","label":"v9.1.4","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Davis Plumlee <56367316+dplumlee@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
@dplumlee dplumlee deleted the rule-diff-2-way branch September 11, 2025 13:07
KodeRad pushed a commit to KodeRad/kibana that referenced this pull request Sep 15, 2025
**Partially addresses:**
elastic/security-team#12507 (internal)

## Summary

Adds a 2-way diff comparison algorithm to the codebase and shifts the
existing diff code to a "three-way" naming scheme.

In order for the telemetry work described in
elastic#230856 to occur, we need to
refactor our diff calculation method to return rule schema fields
instead of the `DiffableRule` schema that we currently return. This
required a lot of exploratory work to determine the best method in which
to accomplish this refactor, as the core function,
`calculateRuleDiffFields`, is used as a core piece of logic in all our
prebuilt rule customization related endpoints, and most of our UI
components are reliant on this `DiffableRule` based return structure.

I settled on an approach that adds a separate 2-way diff function that
never converts the rule into the diffable rule structure, allowing us to
directly compare the rule objects and return exact rule schema fields.
This also involved refactoring the normalization process we did in
`convertToDiffable` and extracting out the comparison functions we used
in the diff algorithms, so that both diff algorithms would be returning
identical "is_customized" calculations given a set of `RuleResponse`
objects.

This PR adds a comprehensive set of tests that verify the
synchronization of these two diff algorithms for ease of maintainability
and to greatly lessen the possibility of divergence.

This PR also swaps out the `is_customized` rule source calculation with
the new 2-way diff calculation, all tests are running (and passing) with
this new diff calculation.

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] [FTR tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9301)
- [x] [Cypress tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9302)

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
CAWilson94 pushed a commit to CAWilson94/kibana that referenced this pull request Sep 24, 2025
**Partially addresses:**
elastic/security-team#12507 (internal)

## Summary

Adds a 2-way diff comparison algorithm to the codebase and shifts the
existing diff code to a "three-way" naming scheme.

In order for the telemetry work described in
elastic#230856 to occur, we need to
refactor our diff calculation method to return rule schema fields
instead of the `DiffableRule` schema that we currently return. This
required a lot of exploratory work to determine the best method in which
to accomplish this refactor, as the core function,
`calculateRuleDiffFields`, is used as a core piece of logic in all our
prebuilt rule customization related endpoints, and most of our UI
components are reliant on this `DiffableRule` based return structure.

I settled on an approach that adds a separate 2-way diff function that
never converts the rule into the diffable rule structure, allowing us to
directly compare the rule objects and return exact rule schema fields.
This also involved refactoring the normalization process we did in
`convertToDiffable` and extracting out the comparison functions we used
in the diff algorithms, so that both diff algorithms would be returning
identical "is_customized" calculations given a set of `RuleResponse`
objects.

This PR adds a comprehensive set of tests that verify the
synchronization of these two diff algorithms for ease of maintainability
and to greatly lessen the possibility of divergence.

This PR also swaps out the `is_customized` rule source calculation with
the new 2-way diff calculation, all tests are running (and passing) with
this new diff calculation.

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] [FTR tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9301)
- [x] [Cypress tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9302)

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
niros1 pushed a commit that referenced this pull request Sep 30, 2025
**Partially addresses:**
elastic/security-team#12507 (internal)

## Summary

Adds a 2-way diff comparison algorithm to the codebase and shifts the
existing diff code to a "three-way" naming scheme.

In order for the telemetry work described in
#230856 to occur, we need to
refactor our diff calculation method to return rule schema fields
instead of the `DiffableRule` schema that we currently return. This
required a lot of exploratory work to determine the best method in which
to accomplish this refactor, as the core function,
`calculateRuleDiffFields`, is used as a core piece of logic in all our
prebuilt rule customization related endpoints, and most of our UI
components are reliant on this `DiffableRule` based return structure.

I settled on an approach that adds a separate 2-way diff function that
never converts the rule into the diffable rule structure, allowing us to
directly compare the rule objects and return exact rule schema fields.
This also involved refactoring the normalization process we did in
`convertToDiffable` and extracting out the comparison functions we used
in the diff algorithms, so that both diff algorithms would be returning
identical "is_customized" calculations given a set of `RuleResponse`
objects.

This PR adds a comprehensive set of tests that verify the
synchronization of these two diff algorithms for ease of maintainability
and to greatly lessen the possibility of divergence.

This PR also swaps out the `is_customized` rule source calculation with
the new 2-way diff calculation, all tests are running (and passing) with
this new diff calculation.

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] [FTR tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9301)
- [x] [Cypress tests
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/9302)

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:version Backport to applied version labels Feature:Prebuilt Detection Rules Security Solution Prebuilt Detection Rules area refactoring release_note:skip Skip the PR/issue when compiling release notes Team:Detection Rule Management Security Detection Rule Management Team Team:Detections and Resp Security Detection Response Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v9.1.4 v9.2.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants