From 4e5ad09b3ae34ac0f140bacc30e5ebae0b7411a5 Mon Sep 17 00:00:00 2001 From: Dmitrii Shevchenko Date: Wed, 19 Apr 2023 13:16:24 +0200 Subject: [PATCH] [Security Solution] Handle missing base versions during rule upgrade (#154571) **Resolves: https://github.com/elastic/kibana/issues/152836** **Resolves: https://github.com/elastic/kibana/issues/148183** **Resolves partially: https://github.com/elastic/kibana/issues/148189** --- .../response_schema.ts | 3 - .../review_rule_upgrade/response_schema.ts | 9 --- .../diff/three_way_diff/three_way_diff.ts | 14 +++- .../three_way_diff/three_way_diff_outcome.ts | 14 +++- .../api/get_prebuilt_rules_status/route.ts | 4 +- .../api/review_rule_installation/route.ts | 2 +- .../api/review_rule_upgrade/route.ts | 28 +++---- .../logic/diff/calculate_rule_diff.ts | 11 +-- .../algorithms/simple_diff_algorithm.ts | 24 +++--- .../calculation/calculate_rule_fields_diff.ts | 74 ++++++++++--------- .../calculation/diff_calculation_helpers.ts | 8 +- 11 files changed, 106 insertions(+), 85 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/response_schema.ts index ea131df38375d..a60311f40b0a2 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/response_schema.ts @@ -15,9 +15,6 @@ export interface GetPrebuiltRulesStatusResponseBody { } export interface PrebuiltRulesStatusStats { - /** Total number of existing (known) prebuilt rules */ - num_prebuilt_rules_total: number; - /** Number of installed prebuilt rules */ num_prebuilt_rules_installed: number; diff --git a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/review_rule_upgrade/response_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/review_rule_upgrade/response_schema.ts index 97a4cee4c993f..35994a7963956 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/review_rule_upgrade/response_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/api/review_rule_upgrade/response_schema.ts @@ -25,17 +25,8 @@ export interface RuleUpgradeStatsForReview { /** Number of installed prebuilt rules available for upgrade (stock + customized) */ num_rules_to_upgrade_total: number; - /** Number of installed prebuilt rules available for upgrade which are stock (non-customized) */ - num_rules_to_upgrade_not_customized: number; - - /** Number of installed prebuilt rules available for upgrade which are customized by the user */ - num_rules_to_upgrade_customized: number; - /** A union of all tags of all rules available for upgrade */ tags: RuleTagArray; - - /** A union of all fields "to be upgraded" across all the rules available for upgrade. An array of field names. */ - fields: string[]; } export interface RuleUpgradeInfoForReview { diff --git a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff.ts index 521b31dc4ea15..3b6831709ced9 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff.ts @@ -8,14 +8,26 @@ import type { ThreeWayDiffOutcome } from './three_way_diff_outcome'; import type { ThreeWayMergeOutcome } from './three_way_merge_outcome'; +/** + * A symbol that represents a missing value and used when a base version of a + * rule is not available. We need a mechanism that helps us distinguish two + * situations: + * - the base version is found, and its value is `undefined` or `null` + * - the base version is not found + * + */ +export const MissingVersion = Symbol('MissingVersion'); +export type MissingVersion = typeof MissingVersion; + /** * Three versions of a value to pass to a diff algorithm. */ export interface ThreeVersionsOf { /** * Corresponds to the stock version of the currently installed prebuilt rule. + * This field is optional because the base version is not always available in the package. */ - base_version: TValue; + base_version: TValue | MissingVersion; /** * Corresponds exactly to the currently installed prebuilt rule: diff --git a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff_outcome.ts b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff_outcome.ts index 07d3fb526c209..fd36a69dbde3c 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff_outcome.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff_outcome.ts @@ -6,6 +6,7 @@ */ import { isEqual } from 'lodash'; +import { MissingVersion } from './three_way_diff'; /** * Result of comparing three versions of a value against each other. @@ -29,7 +30,7 @@ export enum ThreeWayDiffOutcome { } export const determineDiffOutcome = ( - baseVersion: TValue, + baseVersion: TValue | MissingVersion, currentVersion: TValue, targetVersion: TValue ): ThreeWayDiffOutcome => { @@ -37,6 +38,17 @@ export const determineDiffOutcome = ( const baseEqlTarget = isEqual(baseVersion, targetVersion); const currentEqlTarget = isEqual(currentVersion, targetVersion); + if (baseVersion === MissingVersion) { + /** + * We couldn't find the base version of the rule in the package so further + * version comparison is not possible. We assume that the rule is not + * customized and the value can be updated if there's an update. + */ + return currentEqlTarget + ? ThreeWayDiffOutcome.StockValueNoUpdate + : ThreeWayDiffOutcome.StockValueCanUpdate; + } + if (baseEqlCurrent) { return currentEqlTarget ? ThreeWayDiffOutcome.StockValueNoUpdate diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/route.ts index 1926320114a17..d1bdcfc80e757 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/route.ts @@ -73,11 +73,9 @@ export const getPrebuiltRulesStatusRoute = (router: SecuritySolutionPluginRouter }; const calculateRuleStats = (buckets: VersionBuckets): PrebuiltRulesStatusStats => { - const { latestVersions, installedVersions, latestVersionsToInstall, installedVersionsToUpgrade } = - buckets; + const { installedVersions, latestVersionsToInstall, installedVersionsToUpgrade } = buckets; return { - num_prebuilt_rules_total: latestVersions.length, num_prebuilt_rules_installed: installedVersions.length, num_prebuilt_rules_to_install: latestVersionsToInstall.length, num_prebuilt_rules_to_upgrade: installedVersionsToUpgrade.length, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/route.ts index 74d9c6ee80030..8eb8b91af8fbb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/route.ts @@ -79,7 +79,7 @@ export const reviewRuleInstallationRoute = (router: SecuritySolutionPluginRouter const getAggregatedTags = (rules: PrebuiltRuleAsset[]): string[] => { const set = new Set(rules.flatMap((rule) => rule.tags || [])); - return Array.from(set.values()); + return Array.from(set.values()).sort((a, b) => a.localeCompare(b)); }; const calculateRuleStats = ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/route.ts index 3b52cc102110e..626ee8f0bbf7a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/route.ts @@ -30,6 +30,7 @@ import { buildSiemResponse } from '../../../routes/utils'; import { createPrebuiltRuleAssetsClient } from '../../logic/rule_assets/prebuilt_rule_assets_client'; import { createPrebuiltRuleObjectsClient } from '../../logic/rule_objects/prebuilt_rule_objects_client'; import { getVersionBuckets } from '../../model/rule_versions/get_version_buckets'; +import { invariant } from '../../../../../../common/utils/invariant'; export const reviewRuleUpgradeRoute = (router: SecuritySolutionPluginRouter) => { router.post( @@ -114,28 +115,27 @@ const getRuleDiffCalculationArgs = ( const baseRule = baseRulesMap.get(ruleId); const latestRule = latestRulesMap.get(ruleId); - // TODO: https://github.com/elastic/kibana/issues/148189 - // Make base versions optional for diff calculation. We need to support this in order to be able - // to still show diffs for rule assets coming from packages without historical versions. - if (installedRule != null && baseRule != null && latestRule != null) { - result.push({ - currentVersion: installedRule, - baseVersion: baseRule, - targetVersion: latestRule, - }); - } + // baseRule can be undefined if the rule has no historical versions, but other versions should always be present + invariant(installedRule != null, `installedRule is not found for rule_id: ${ruleId}`); + invariant(latestRule != null, `latestRule is not found for rule_id: ${ruleId}`); + + result.push({ + currentVersion: installedRule, + baseVersion: baseRule, + targetVersion: latestRule, + }); }); return result; }; const calculateRuleStats = (results: CalculateRuleDiffResult[]): RuleUpgradeStatsForReview => { + const allTags = new Set( + results.flatMap((result) => result.ruleVersions.input.current.tags) + ); return { num_rules_to_upgrade_total: results.length, - num_rules_to_upgrade_not_customized: results.length, - num_rules_to_upgrade_customized: 0, - tags: [], - fields: [], + tags: [...allTags].sort((a, b) => a.localeCompare(b)), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculate_rule_diff.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculate_rule_diff.ts index 026589ad0ca0d..061c1d1082bdd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculate_rule_diff.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculate_rule_diff.ts @@ -8,6 +8,7 @@ import type { DiffableRule } from '../../../../../../common/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_rule'; import type { FullRuleDiff } from '../../../../../../common/detection_engine/prebuilt_rules/model/diff/rule_diff/rule_diff'; import type { ThreeWayDiff } from '../../../../../../common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff'; +import { MissingVersion } from '../../../../../../common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff'; import type { RuleResponse } from '../../../../../../common/detection_engine/rule_schema'; import type { PrebuiltRuleAsset } from '../../model/rule_assets/prebuilt_rule_asset'; @@ -16,7 +17,7 @@ import { convertRuleToDiffable } from './normalization/convert_rule_to_diffable' export interface CalculateRuleDiffArgs { currentVersion: RuleResponse; - baseVersion: PrebuiltRuleAsset; + baseVersion?: PrebuiltRuleAsset; targetVersion: PrebuiltRuleAsset; } @@ -25,12 +26,12 @@ export interface CalculateRuleDiffResult { ruleVersions: { input: { current: RuleResponse; - base: PrebuiltRuleAsset; + base?: PrebuiltRuleAsset; target: PrebuiltRuleAsset; }; output: { current: DiffableRule; - base: DiffableRule; + base?: DiffableRule; target: DiffableRule; }; }; @@ -60,12 +61,12 @@ export const calculateRuleDiff = (args: CalculateRuleDiffArgs): CalculateRuleDif const { baseVersion, currentVersion, targetVersion } = args; - const diffableBaseVersion = convertRuleToDiffable(baseVersion); + const diffableBaseVersion = baseVersion ? convertRuleToDiffable(baseVersion) : undefined; const diffableCurrentVersion = convertRuleToDiffable(currentVersion); const diffableTargetVersion = convertRuleToDiffable(targetVersion); const fieldsDiff = calculateRuleFieldsDiff({ - base_version: diffableBaseVersion, + base_version: diffableBaseVersion || MissingVersion, current_version: diffableCurrentVersion, target_version: diffableTargetVersion, }); 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 699f8f20bcf1f..90a55ee3d6eff 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 @@ -29,12 +29,11 @@ export const simpleDiffAlgorithm = ( const diffOutcome = determineDiffOutcome(baseVersion, currentVersion, targetVersion); const valueCanUpdate = determineIfValueCanUpdate(diffOutcome); - const { mergeOutcome, mergedVersion } = mergeVersions( - baseVersion, + const { mergeOutcome, mergedVersion } = mergeVersions({ currentVersion, targetVersion, - diffOutcome - ); + diffOutcome, + }); return { base_version: baseVersion, @@ -54,12 +53,17 @@ interface MergeResult { mergedVersion: TValue; } -const mergeVersions = ( - baseVersion: TValue, - currentVersion: TValue, - targetVersion: TValue, - diffOutcome: ThreeWayDiffOutcome -): MergeResult => { +interface MergeArgs { + currentVersion: TValue; + targetVersion: TValue; + diffOutcome: ThreeWayDiffOutcome; +} + +const mergeVersions = ({ + currentVersion, + targetVersion, + diffOutcome, +}: MergeArgs): MergeResult => { switch (diffOutcome) { case ThreeWayDiffOutcome.StockValueNoUpdate: case ThreeWayDiffOutcome.CustomizedValueNoUpdate: diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts index bb7a83ff20b23..abd084c1789e4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts @@ -33,6 +33,7 @@ import type { import type { FieldsDiffAlgorithmsFor } from '../../../../../../../common/detection_engine/prebuilt_rules/model/diff/rule_diff/fields_diff'; import type { ThreeVersionsOf } from '../../../../../../../common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff'; +import { MissingVersion } from '../../../../../../../common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff'; import { calculateFieldsDiffFor } from './diff_calculation_helpers'; import { simpleDiffAlgorithm } from './algorithms/simple_diff_algorithm'; @@ -47,15 +48,16 @@ const TARGET_TYPE_ERROR = `Target version can't be of different rule type`; export const calculateRuleFieldsDiff = ( ruleVersions: ThreeVersionsOf ): RuleFieldsDiff => { - validateRuleVersions(ruleVersions); - const commonFieldsDiff = calculateCommonFieldsDiff(ruleVersions); // eslint-disable-next-line @typescript-eslint/naming-convention const { base_version, current_version, target_version } = ruleVersions; + const hasBaseVersion = base_version !== MissingVersion; switch (current_version.type) { case 'query': { - invariant(base_version.type === 'query', BASE_TYPE_ERROR); + if (hasBaseVersion) { + invariant(base_version.type === 'query', BASE_TYPE_ERROR); + } invariant(target_version.type === 'query', TARGET_TYPE_ERROR); return { ...commonFieldsDiff, @@ -63,7 +65,9 @@ export const calculateRuleFieldsDiff = ( }; } case 'saved_query': { - invariant(base_version.type === 'saved_query', BASE_TYPE_ERROR); + if (hasBaseVersion) { + invariant(base_version.type === 'saved_query', BASE_TYPE_ERROR); + } invariant(target_version.type === 'saved_query', TARGET_TYPE_ERROR); return { ...commonFieldsDiff, @@ -71,7 +75,9 @@ export const calculateRuleFieldsDiff = ( }; } case 'eql': { - invariant(base_version.type === 'eql', BASE_TYPE_ERROR); + if (hasBaseVersion) { + invariant(base_version.type === 'eql', BASE_TYPE_ERROR); + } invariant(target_version.type === 'eql', TARGET_TYPE_ERROR); return { ...commonFieldsDiff, @@ -79,7 +85,9 @@ export const calculateRuleFieldsDiff = ( }; } case 'threat_match': { - invariant(base_version.type === 'threat_match', BASE_TYPE_ERROR); + if (hasBaseVersion) { + invariant(base_version.type === 'threat_match', BASE_TYPE_ERROR); + } invariant(target_version.type === 'threat_match', TARGET_TYPE_ERROR); return { ...commonFieldsDiff, @@ -87,7 +95,9 @@ export const calculateRuleFieldsDiff = ( }; } case 'threshold': { - invariant(base_version.type === 'threshold', BASE_TYPE_ERROR); + if (hasBaseVersion) { + invariant(base_version.type === 'threshold', BASE_TYPE_ERROR); + } invariant(target_version.type === 'threshold', TARGET_TYPE_ERROR); return { ...commonFieldsDiff, @@ -95,7 +105,9 @@ export const calculateRuleFieldsDiff = ( }; } case 'machine_learning': { - invariant(base_version.type === 'machine_learning', BASE_TYPE_ERROR); + if (hasBaseVersion) { + invariant(base_version.type === 'machine_learning', BASE_TYPE_ERROR); + } invariant(target_version.type === 'machine_learning', TARGET_TYPE_ERROR); return { ...commonFieldsDiff, @@ -103,7 +115,9 @@ export const calculateRuleFieldsDiff = ( }; } case 'new_terms': { - invariant(base_version.type === 'new_terms', BASE_TYPE_ERROR); + if (hasBaseVersion) { + invariant(base_version.type === 'new_terms', BASE_TYPE_ERROR); + } invariant(target_version.type === 'new_terms', TARGET_TYPE_ERROR); return { ...commonFieldsDiff, @@ -116,20 +130,10 @@ export const calculateRuleFieldsDiff = ( } }; -const validateRuleVersions = (ruleVersions: ThreeVersionsOf): void => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { base_version, current_version, target_version } = ruleVersions; - const types = new Set([base_version.type, current_version.type, target_version.type]); - - if (types.size > 1) { - throw new Error('Cannot change rule type during rule upgrade'); - } -}; - const calculateCommonFieldsDiff = ( - fieldsVersions: ThreeVersionsOf + ruleVersions: ThreeVersionsOf ): CommonFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, commonFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, commonFieldsDiffAlgorithms); }; const commonFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { @@ -164,9 +168,9 @@ const commonFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor }; const calculateCustomQueryFieldsDiff = ( - fieldsVersions: ThreeVersionsOf + ruleVersions: ThreeVersionsOf ): CustomQueryFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, customQueryFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, customQueryFieldsDiffAlgorithms); }; const customQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { @@ -177,9 +181,9 @@ const customQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor + ruleVersions: ThreeVersionsOf ): SavedQueryFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, savedQueryFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, savedQueryFieldsDiffAlgorithms); }; const savedQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { @@ -190,9 +194,9 @@ const savedQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor + ruleVersions: ThreeVersionsOf ): EqlFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, eqlFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, eqlFieldsDiffAlgorithms); }; const eqlFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { @@ -205,9 +209,9 @@ const eqlFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { }; const calculateThreatMatchFieldsDiff = ( - fieldsVersions: ThreeVersionsOf + ruleVersions: ThreeVersionsOf ): ThreatMatchFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, threatMatchFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, threatMatchFieldsDiffAlgorithms); }; const threatMatchFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { @@ -223,9 +227,9 @@ const threatMatchFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor + ruleVersions: ThreeVersionsOf ): ThresholdFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, thresholdFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, thresholdFieldsDiffAlgorithms); }; const thresholdFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { @@ -236,9 +240,9 @@ const thresholdFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor + ruleVersions: ThreeVersionsOf ): MachineLearningFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, machineLearningFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, machineLearningFieldsDiffAlgorithms); }; const machineLearningFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = @@ -249,9 +253,9 @@ const machineLearningFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor + ruleVersions: ThreeVersionsOf ): NewTermsFieldsDiff => { - return calculateFieldsDiffFor(fieldsVersions, newTermsFieldsDiffAlgorithms); + return calculateFieldsDiffFor(ruleVersions, newTermsFieldsDiffAlgorithms); }; const newTermsFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor = { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/diff_calculation_helpers.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/diff_calculation_helpers.ts index eb1b6e2d38aca..d36c33cf5d890 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/diff_calculation_helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/diff_calculation_helpers.ts @@ -11,13 +11,14 @@ import type { FieldsDiffAlgorithmsFor, } from '../../../../../../../common/detection_engine/prebuilt_rules/model/diff/rule_diff/fields_diff'; import type { ThreeVersionsOf } from '../../../../../../../common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff'; +import { MissingVersion } from '../../../../../../../common/detection_engine/prebuilt_rules/model/diff/three_way_diff/three_way_diff'; export const calculateFieldsDiffFor = ( - objectVersions: ThreeVersionsOf, + ruleVersions: ThreeVersionsOf, fieldsDiffAlgorithms: FieldsDiffAlgorithmsFor ): FieldsDiff => { const result = mapValues(fieldsDiffAlgorithms, (calculateFieldDiff, fieldName) => { - const fieldVersions = pickField(fieldName as keyof TObject, objectVersions); + const fieldVersions = pickField(fieldName as keyof TObject, ruleVersions); const fieldDiff = calculateFieldDiff(fieldVersions); return fieldDiff; }); @@ -31,7 +32,8 @@ const pickField = ( versions: ThreeVersionsOf ): ThreeVersionsOf => { return { - base_version: versions.base_version[fieldName], + base_version: + versions.base_version !== MissingVersion ? versions.base_version[fieldName] : MissingVersion, current_version: versions.current_version[fieldName], target_version: versions.target_version[fieldName], };