diff --git a/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md index e6454eb424141..e2f98296e199c 100644 --- a/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md +++ b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md @@ -893,8 +893,8 @@ And field is customized by the user (current version != base versio And field is updated by Elastic in this upgrade (target version != base version) And customized field is the same as the Elastic update in this upgrade (current version == target version) Then for field the diff algorithm should output the current version as the merged one without a conflict -And field should not be returned from the `upgrade/_review` API endpoint -And field should not be shown in the upgrade preview UI +And field should be returned from the `upgrade/_review` API endpoint +And field should be shown in the upgrade preview UI Examples: | field_name | base_version | current_version | target_version | diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts index 2270c6fea7396..204d316af8091 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts @@ -7,7 +7,10 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { pickBy } from 'lodash'; -import { REVIEW_RULE_UPGRADE_URL } from '../../../../../../common/api/detection_engine/prebuilt_rules'; +import { + REVIEW_RULE_UPGRADE_URL, + ThreeWayDiffOutcome, +} from '../../../../../../common/api/detection_engine/prebuilt_rules'; import type { ReviewRuleUpgradeResponseBody, RuleUpgradeInfoForReview, @@ -120,7 +123,12 @@ const calculateRuleInfos = (results: CalculateRuleDiffResult[]): RuleUpgradeInfo diff: { fields: pickBy>( ruleDiff.fields, - (fieldDiff) => fieldDiff.has_update || fieldDiff.has_conflict + (fieldDiff) => + fieldDiff.has_update || + fieldDiff.has_conflict || + // For full transparancy we display all user-customized fields, even if nothing changes in the field's target or merged versions + fieldDiff.diff_outcome === ThreeWayDiffOutcome.CustomizedValueNoUpdate || + fieldDiff.diff_outcome === ThreeWayDiffOutcome.CustomizedValueSameUpdate ), has_conflict: ruleDiff.has_conflict, }, diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.ts index 66cc4a3a54b8c..5c85718d7203e 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.ts @@ -64,10 +64,41 @@ export default ({ getService }: FtrProviderContext): void => { name: 'B', }); - // Call the upgrade review prebuilt rules endpoint and check that no rules are eligible for update + // Increment the version of the installed rule, do NOT update the related single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + name: 'A', + version: 2, + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that single line string diff field is returned but field does not have an update const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules).toEqual([]); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(0); + expect(reviewResponse.rules[0].diff.fields).toMatchObject({ + name: { + base_version: 'A', + current_version: 'B', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + has_conflict: false, + has_update: false, + merge_outcome: ThreeWayMergeOutcome.Current, + merged_version: 'B', + target_version: 'A', + }, + version: { + current_version: 1, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + has_conflict: false, + has_update: true, + merge_outcome: ThreeWayMergeOutcome.Target, + merged_version: 2, + target_version: 2, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); }); }); @@ -140,9 +171,18 @@ export default ({ getService }: FtrProviderContext): void => { await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // but does NOT contain single line string field const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toMatchObject({ + name: { + base_version: 'A', + current_version: 'B', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + has_conflict: false, + has_update: false, + merge_outcome: ThreeWayMergeOutcome.Current, + merged_version: 'B', + target_version: 'B', + }, version: { base_version: 1, current_version: 1, @@ -345,10 +385,41 @@ export default ({ getService }: FtrProviderContext): void => { risk_score: 2, }); - // Call the upgrade review prebuilt rules endpoint and check that no rules are eligible for update + // Increment the version of the installed rule, do NOT update the related number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + risk_score: 1, + version: 2, + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that number diff field is returned but field does not have an update const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules).toEqual([]); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(0); + expect(reviewResponse.rules[0].diff.fields).toMatchObject({ + risk_score: { + base_version: 1, + current_version: 2, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + has_conflict: false, + has_update: false, + merge_outcome: ThreeWayMergeOutcome.Current, + merged_version: 2, + target_version: 1, + }, + version: { + current_version: 1, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + has_conflict: false, + has_update: true, + merge_outcome: ThreeWayMergeOutcome.Target, + merged_version: 2, + target_version: 2, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); }); }); @@ -420,10 +491,19 @@ export default ({ getService }: FtrProviderContext): void => { ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // but does NOT contain number field + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains number field const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toMatchObject({ + risk_score: { + base_version: 1, + current_version: 2, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + has_conflict: false, + has_update: false, + merge_outcome: ThreeWayMergeOutcome.Current, + merged_version: 2, + target_version: 2, + }, version: { base_version: 1, current_version: 1,