diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/number_diff_algorithm.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/number_diff_algorithm.test.ts new file mode 100644 index 0000000000000..43f6c9ed97e9d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/number_diff_algorithm.test.ts @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ThreeVersionsOf } from '../../../../../../../../common/api/detection_engine'; +import { + ThreeWayDiffOutcome, + ThreeWayMergeOutcome, + MissingVersion, +} from '../../../../../../../../common/api/detection_engine'; +import { numberDiffAlgorithm } from './number_diff_algorithm'; + +describe('numberDiffAlgorithm', () => { + it('returns current_version as merged output if there is no update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 1, + current_version: 1, + target_version: 1, + }; + + const result = numberDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.StockValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if current_version is different and there is no update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 1, + current_version: 2, + target_version: 1, + }; + + const result = numberDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns target_version as merged output if current_version is the same and there is an update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 1, + current_version: 1, + target_version: 2, + }; + + const result = numberDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.target_version, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if current version is different but it matches the update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 1, + current_version: 2, + target_version: 2, + }; + + const result = numberDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if all three versions are different', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 1, + current_version: 2, + target_version: 3, + }; + + const result = numberDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Conflict, + has_conflict: true, + }) + ); + }); + + describe('if base_version is missing', () => { + it('returns current_version as merged output if current_version and target_version are the same', () => { + const mockVersions: ThreeVersionsOf = { + base_version: MissingVersion, + current_version: 1, + target_version: 1, + }; + + const result = numberDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.StockValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns target_version as merged output if current_version and target_version are different', () => { + const mockVersions: ThreeVersionsOf = { + base_version: MissingVersion, + current_version: 1, + target_version: 2, + }; + + const result = numberDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.target_version, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/number_diff_algorithm.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/number_diff_algorithm.ts new file mode 100644 index 0000000000000..513d9047c7a5c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/number_diff_algorithm.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { simpleDiffAlgorithm } from './simple_diff_algorithm'; + +export const numberDiffAlgorithm = simpleDiffAlgorithm; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/simple_diff_algorithm.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/simple_diff_algorithm.ts index f598e9da451c6..51d3d8fc22d58 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/simple_diff_algorithm.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/simple_diff_algorithm.ts @@ -17,6 +17,11 @@ import { ThreeWayMergeOutcome, } from '../../../../../../../../common/api/detection_engine/prebuilt_rules'; +/** + * The default diff algorithm, diffs versions passed using a simple lodash `isEqual` comparison + * + * Meant to be used with primitive types (strings, numbers, booleans), NOT Arrays or Objects + */ export const simpleDiffAlgorithm = ( versions: ThreeVersionsOf ): ThreeWayDiff => { @@ -82,7 +87,7 @@ const mergeVersions = ({ case ThreeWayDiffOutcome.CustomizedValueCanUpdate: { return { mergeOutcome: ThreeWayMergeOutcome.Conflict, - mergedVersion: targetVersion, + mergedVersion: currentVersion, }; } default: diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/single_line_string_diff_algorithm.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/single_line_string_diff_algorithm.test.ts new file mode 100644 index 0000000000000..a4f5197979db4 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/single_line_string_diff_algorithm.test.ts @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ThreeVersionsOf } from '../../../../../../../../common/api/detection_engine'; +import { + ThreeWayDiffOutcome, + ThreeWayMergeOutcome, + MissingVersion, +} from '../../../../../../../../common/api/detection_engine'; +import { singleLineStringDiffAlgorithm } from './single_line_string_diff_algorithm'; + +describe('singleLineStringDiffAlgorithm', () => { + it('returns current_version as merged output if there is no update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'A', + current_version: 'A', + target_version: 'A', + }; + + const result = singleLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.StockValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if current_version is different and there is no update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'A', + current_version: 'B', + target_version: 'A', + }; + + const result = singleLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns target_version as merged output if current_version is the same and there is an update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'A', + current_version: 'A', + target_version: 'B', + }; + + const result = singleLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.target_version, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if current version is different but it matches the update', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'A', + current_version: 'B', + target_version: 'B', + }; + + const result = singleLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if all three versions are different', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'A', + current_version: 'B', + target_version: 'C', + }; + + const result = singleLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Conflict, + has_conflict: true, + }) + ); + }); + + describe('if base_version is missing', () => { + it('returns current_version as merged output if current_version and target_version are the same', () => { + const mockVersions: ThreeVersionsOf = { + base_version: MissingVersion, + current_version: 'A', + target_version: 'A', + }; + + const result = singleLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.StockValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns target_version as merged output if current_version and target_version are different', () => { + const mockVersions: ThreeVersionsOf = { + base_version: MissingVersion, + current_version: 'A', + target_version: 'B', + }; + + const result = singleLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.target_version, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/single_line_string_diff_algorithm.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/single_line_string_diff_algorithm.ts new file mode 100644 index 0000000000000..901bb6c050e51 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/single_line_string_diff_algorithm.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { simpleDiffAlgorithm } from './simple_diff_algorithm'; + +export const singleLineStringDiffAlgorithm = simpleDiffAlgorithm;