From 76cc844cf4061e257661d572cc3b69141626061b Mon Sep 17 00:00:00 2001 From: Davis Plumlee <56367316+dplumlee@users.noreply.github.com> Date: Thu, 11 Jul 2024 10:21:25 -0400 Subject: [PATCH] [Security Solution] Integration tests for scalar array diff algorithm (#187778) ## Summary Completes https://github.com/elastic/kibana/issues/180162 Switches fields to use the scalar array diff algorithms assigned to them in the [overarching ticket](https://github.com/elastic/kibana/issues/180162#issuecomment-2152936375) Adds integration tests in accordance to https://github.com/elastic/kibana/pull/186325 for the upgrade/_review API endpoint for the scalar array diff algorithm. ### Checklist Delete any items that are not applicable to this PR. - [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 ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../calculation/calculate_rule_fields_diff.ts | 11 +- .../trial_license_complete_tier/index.ts | 4 +- ...ade_review_prebuilt_rules.number_fields.ts | 376 ++++++++++++++ ...iew_prebuilt_rules.scalar_array_fields.ts} | 481 ++++++------------ ...rebuilt_rules.single_line_string_fields.ts | 376 ++++++++++++++ 5 files changed, 915 insertions(+), 333 deletions(-) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts rename 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 => upgrade_review_prebuilt_rules.scalar_array_fields.ts} (54%) create mode 100644 x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts 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 5e9bd8bd9ae64..cc27fe928b27c 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 @@ -39,6 +39,7 @@ import { MissingVersion } from '../../../../../../../common/api/detection_engine import { calculateFieldsDiffFor } from './diff_calculation_helpers'; import { numberDiffAlgorithm, + scalarArrayDiffAlgorithm, simpleDiffAlgorithm, singleLineStringDiffAlgorithm, } from './algorithms'; @@ -174,20 +175,20 @@ const commonFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor rule_id: simpleDiffAlgorithm, version: numberDiffAlgorithm, name: singleLineStringDiffAlgorithm, - tags: simpleDiffAlgorithm, + tags: scalarArrayDiffAlgorithm, description: simpleDiffAlgorithm, severity: singleLineStringDiffAlgorithm, severity_mapping: simpleDiffAlgorithm, risk_score: numberDiffAlgorithm, risk_score_mapping: simpleDiffAlgorithm, - references: simpleDiffAlgorithm, + references: scalarArrayDiffAlgorithm, false_positives: simpleDiffAlgorithm, threat: simpleDiffAlgorithm, note: simpleDiffAlgorithm, setup: simpleDiffAlgorithm, related_integrations: simpleDiffAlgorithm, required_fields: simpleDiffAlgorithm, - author: simpleDiffAlgorithm, + author: scalarArrayDiffAlgorithm, license: singleLineStringDiffAlgorithm, rule_schedule: simpleDiffAlgorithm, exceptions_list: simpleDiffAlgorithm, @@ -259,7 +260,7 @@ const threatMatchFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor { loadTestFile(require.resolve('./upgrade_prebuilt_rules')); loadTestFile(require.resolve('./upgrade_prebuilt_rules_with_historical_versions')); loadTestFile(require.resolve('./fleet_integration')); - loadTestFile(require.resolve('./upgrade_review_prebuilt_rules')); + loadTestFile(require.resolve('./upgrade_review_prebuilt_rules.number_fields')); + loadTestFile(require.resolve('./upgrade_review_prebuilt_rules.single_line_string_fields')); + loadTestFile(require.resolve('./upgrade_review_prebuilt_rules.scalar_array_fields')); }); }; 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.number_fields.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.number_fields.ts new file mode 100644 index 0000000000000..79d29a29c0cd3 --- /dev/null +++ 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.number_fields.ts @@ -0,0 +1,376 @@ +/* + * 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 expect from 'expect'; +import { + ThreeWayDiffOutcome, + ThreeWayMergeOutcome, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { + deleteAllTimelines, + deleteAllPrebuiltRuleAssets, + createRuleAssetSavedObject, + installPrebuiltRules, + createPrebuiltRuleAssetSavedObjects, + reviewPrebuiltRulesToUpgrade, + patchRule, + createHistoricalPrebuiltRuleAssetSavedObjects, +} from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI review prebuilt rules updates from package with mock rule assets', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllTimelines(es, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + describe(`number fields`, () => { + const getRuleAssetSavedObjects = () => [ + createRuleAssetSavedObject({ rule_id: 'rule-1', version: 1, risk_score: 1 }), + ]; + + describe("when rule field doesn't have an update and has no custom value - scenario AAA", () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // 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 there is 1 rule eligable for update but number field is NOT returned + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe("when rule field doesn't have an update but has a custom value - scenario ABA", () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a number field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + risk_score: 2, + }); + + // 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[0].diff.fields).toEqual({ + risk_score: { + base_version: 1, + current_version: 2, + target_version: 1, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + has_update: false, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule field has an update but does not have a custom value - scenario AAB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Increment the version of the installed rule, update a number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + risk_score: 2, + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + risk_score: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a number field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + risk_score: 2, + }); + + // Increment the version of the installed rule, update a number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + risk_score: 2, + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // 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).toEqual({ + risk_score: { + base_version: 1, + current_version: 2, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + has_update: false, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a number field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + risk_score: 2, + }); + + // Increment the version of the installed rule, update a number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + risk_score: 3, + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and number field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + risk_score: { + base_version: 1, + current_version: 2, + target_version: 3, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Conflict, + has_conflict: true, + has_update: true, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(true); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule base version does not exist', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Customize a number field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + risk_score: 2, + }); + + // Increment the version of the installed rule, update a number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + risk_score: 2, + }), + ]; + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // but does NOT contain number field + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + version: { + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Customize a number field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + risk_score: 2, + }); + + // Increment the version of the installed rule, update a number field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + risk_score: 3, + }), + ]; + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and number field update does not have a conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + risk_score: { + current_version: 2, + target_version: 3, + merged_version: 3, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + version: { + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + }); + }); + }); + }); +}; 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.scalar_array_fields.ts similarity index 54% rename from 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 rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts index 9ad266e20740d..ecbd1711dc52d 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.scalar_array_fields.ts @@ -34,28 +34,32 @@ export default ({ getService }: FtrProviderContext): void => { await deleteAllPrebuiltRuleAssets(es, log); }); - describe(`single line string fields`, () => { + describe(`scalar array fields`, () => { const getRuleAssetSavedObjects = () => [ - createRuleAssetSavedObject({ rule_id: 'rule-1', version: 1, name: 'A' }), + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 1, + tags: ['one', 'two', 'three'], + }), ]; - describe("when rule field doesn't have an update and has no custom value", () => { + describe("when rule field doesn't have an update and has no custom value - scenario AAA", () => { it('should not show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); - // Increment the version of the installed rule, do NOT update the related single line string field, and create the new rule assets + // Increment the version of the installed rule, do NOT update the related scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', - name: 'A', + tags: ['one', 'three', 'two'], version: 2, }), ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Call the upgrade review prebuilt rules endpoint and check that there is 1 rule eligable for update but single line string field is NOT returned + // Call the upgrade review prebuilt rules endpoint and check that there is 1 rule eligable for update but scalar array field is NOT returned const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ version: { @@ -74,36 +78,36 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe("when rule field doesn't have an update but has a custom value", () => { - it('should not show in the upgrade/_review API response', async () => { + describe("when rule field doesn't have an update but has a custom value - scenario ABA", () => { + it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); - // Customize a single line string field on the installed rule + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - name: 'B', + tags: ['one', 'two', 'four'], }); - // Increment the version of the installed rule, do NOT update the related single line string field, and create the new rule assets + // Increment the version of the installed rule, do NOT update the related scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', - name: 'A', + tags: ['one', 'two', 'three'], 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 + // Call the upgrade review prebuilt rules endpoint and check that scalar array diff field is returned but field does not have an update const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ - name: { - base_version: 'A', - current_version: 'B', - target_version: 'A', - merged_version: 'B', + tags: { + base_version: ['one', 'two', 'three'], + current_version: ['one', 'two', 'four'], + target_version: ['one', 'two', 'three'], + merged_version: ['one', 'two', 'four'], diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, merge_outcome: ThreeWayMergeOutcome.Current, has_conflict: false, @@ -125,18 +129,18 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe('when rule field has an update but does not have a custom value', () => { + describe('when rule field has an update but does not have a custom value - scenario AAB', () => { it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); - // Increment the version of the installed rule, update a single line string field, and create the new rule assets + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - name: 'B', + tags: ['one', 'two', 'four'], }), ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); @@ -144,11 +148,11 @@ export default ({ getService }: FtrProviderContext): void => { // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ - name: { - base_version: 'A', - current_version: 'A', - target_version: 'B', - merged_version: 'B', + tags: { + base_version: ['one', 'two', 'three'], + current_version: ['one', 'two', 'three'], + target_version: ['one', 'two', 'four'], + merged_version: ['one', 'two', 'four'], diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, merge_outcome: ThreeWayMergeOutcome.Target, has_conflict: false, @@ -169,36 +173,36 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); }); - describe('when rule field has an update and a custom value that are the same', () => { + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); - // Customize a single line string field on the installed rule + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - name: 'B', + tags: ['one', 'two', 'four'], }); - // Increment the version of the installed rule, update a single line string field, and create the new rule assets + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - name: 'B', + tags: ['one', 'two', 'four'], }), ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains scalar array field const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ - name: { - base_version: 'A', - current_version: 'B', - target_version: 'B', - merged_version: 'B', + tags: { + base_version: ['one', 'two', 'three'], + current_version: ['one', 'two', 'four'], + target_version: ['one', 'two', 'four'], + merged_version: ['one', 'two', 'four'], diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, merge_outcome: ThreeWayMergeOutcome.Current, has_conflict: false, @@ -220,40 +224,40 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe('when rule field has an update and a custom value that are different', () => { + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); - // Customize a single line string field on the installed rule + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - name: 'B', + tags: ['one', 'two', 'four'], }); - // Increment the version of the installed rule, update a single line string field, and create the new rule assets + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - name: 'C', + tags: ['one', 'two', 'five'], }), ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and single line string field update has conflict + // and scalar array field update has conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ - name: { - base_version: 'A', - current_version: 'B', - target_version: 'C', - merged_version: 'B', + tags: { + base_version: ['one', 'two', 'three'], + current_version: ['one', 'two', 'four'], + target_version: ['one', 'two', 'five'], + merged_version: ['one', 'two', 'four', 'five'], diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Conflict, - has_conflict: true, + merge_outcome: ThreeWayMergeOutcome.Merged, + has_conflict: false, has_update: true, }, version: { @@ -267,281 +271,106 @@ export default ({ getService }: FtrProviderContext): void => { has_update: true, }, }); - expect(reviewResponse.rules[0].diff.has_conflict).toBe(true); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); }); - }); - - describe('when rule base version does not exist', () => { - describe('when rule field has an update and a custom value that are the same', () => { - it('should not show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Customize a single line string field on the installed rule - await patchRule(supertest, log, { + it('should compare values after deduplication', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, [ + createRuleAssetSavedObject({ rule_id: 'rule-1', - name: 'B', - }); - - // Increment the version of the installed rule, update a single line string field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - name: 'B', - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + version: 1, + tags: ['one', 'two', 'two'], + }), + ]); + await installPrebuiltRules(es, supertest); - // 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).toEqual({ - version: { - current_version: 1, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - has_conflict: false, - has_update: true, - }, - }); - expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + // Customize a scalar array field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + tags: ['two', 'one', 'three'], }); - }); - describe('when rule field has an update and a custom value that are different', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Clear previous rule assets - await deleteAllPrebuiltRuleAssets(es, log); - - // Customize a single line string field on the installed rule - await patchRule(supertest, log, { + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ rule_id: 'rule-1', - name: 'B', - }); - - // Increment the version of the installed rule, update a single line string field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - name: 'C', - }), - ]; - await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + version: 2, + tags: ['three', 'three', 'one'], + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and single line string field update does not have a conflict - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields).toEqual({ - name: { - current_version: 'B', - target_version: 'C', - merged_version: 'C', - diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - has_conflict: false, - has_update: true, - }, - version: { - current_version: 1, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - has_conflict: false, - has_update: true, - }, - }); - expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and scalar array field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + tags: { + base_version: ['one', 'two', 'two'], + current_version: ['two', 'one', 'three'], + target_version: ['three', 'three', 'one'], + merged_version: ['one', 'three'], + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + has_conflict: false, + has_update: true, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); }); - }); - }); - }); - - describe(`number fields`, () => { - const getRuleAssetSavedObjects = () => [ - createRuleAssetSavedObject({ rule_id: 'rule-1', version: 1, risk_score: 1 }), - ]; - - describe("when rule field doesn't have an update and has no custom value", () => { - it('should not show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // 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 there is 1 rule eligable for update but number field is NOT returned - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields).toEqual({ - version: { - base_version: 1, - current_version: 1, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - has_conflict: false, - has_update: true, - }, - }); - expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - }); - }); - - describe("when rule field doesn't have an update but has a custom value", () => { - it('should not show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Customize a number field on the installed rule - await patchRule(supertest, log, { - rule_id: 'rule-1', - risk_score: 2, - }); - - // 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[0].diff.fields).toEqual({ - risk_score: { - base_version: 1, - current_version: 2, - target_version: 1, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, - has_conflict: false, - has_update: false, - }, - version: { - base_version: 1, - current_version: 1, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - has_conflict: false, - has_update: true, - }, - }); - expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - }); - }); - - describe('when rule field has an update but does not have a custom value', () => { - it('should show in the upgrade/_review API response', async () => { - // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); - await installPrebuiltRules(es, supertest); - - // Increment the version of the installed rule, update a number field, and create the new rule assets - const updatedRuleAssetSavedObjects = [ - createRuleAssetSavedObject({ - rule_id: 'rule-1', - version: 2, - risk_score: 2, - }), - ]; - await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); - expect(reviewResponse.rules[0].diff.fields).toEqual({ - risk_score: { - base_version: 1, - current_version: 1, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - has_conflict: false, - has_update: true, - }, - version: { - base_version: 1, - current_version: 1, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Target, - has_conflict: false, - has_update: true, - }, - }); - expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); - expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - }); - describe('when rule field has an update and a custom value that are the same', () => { - it('should show in the upgrade/_review API response', async () => { + it('should compare values sensitive of case', async () => { // Install base prebuilt detection rule - await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await createHistoricalPrebuiltRuleAssetSavedObjects(es, [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 1, + tags: ['ONE', 'TWO'], + }), + ]); await installPrebuiltRules(es, supertest); - // Customize a number field on the installed rule + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - risk_score: 2, + tags: ['one', 'ONE'], }); - // Increment the version of the installed rule, update a number field, and create the new rule assets + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - risk_score: 2, + tags: ['ONE', 'THREE'], }), ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); - // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains number field + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and scalar array field update has conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ - risk_score: { - base_version: 1, - current_version: 2, - target_version: 2, - merged_version: 2, - diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, - merge_outcome: ThreeWayMergeOutcome.Current, + tags: { + base_version: ['ONE', 'TWO'], + current_version: ['one', 'ONE'], + target_version: ['ONE', 'THREE'], + merged_version: ['ONE', 'one', 'THREE'], + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, has_conflict: false, - has_update: false, + has_update: true, }, version: { base_version: 1, @@ -557,42 +386,40 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); }); - }); - describe('when rule field has an update and a custom value that are different', () => { - it('should show in the upgrade/_review API response', async () => { + it('should handle empty arrays', async () => { // Install base prebuilt detection rule await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); await installPrebuiltRules(es, supertest); - // Customize a number field on the installed rule + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - risk_score: 2, + tags: [], }); - // Increment the version of the installed rule, update a number field, and create the new rule assets + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - risk_score: 3, + tags: ['one', 'two', 'five'], }), ]; await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and number field update has conflict + // and scalar array field update has conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ - risk_score: { - base_version: 1, - current_version: 2, - target_version: 3, - merged_version: 2, + tags: { + base_version: ['one', 'two', 'three'], + current_version: [], + target_version: ['one', 'two', 'five'], + merged_version: ['five'], diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, - merge_outcome: ThreeWayMergeOutcome.Conflict, - has_conflict: true, + merge_outcome: ThreeWayMergeOutcome.Merged, + has_conflict: false, has_update: true, }, version: { @@ -606,13 +433,13 @@ export default ({ getService }: FtrProviderContext): void => { has_update: true, }, }); - expect(reviewResponse.rules[0].diff.has_conflict).toBe(true); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); }); }); describe('when rule base version does not exist', () => { - describe('when rule field has an update and a custom value that are the same', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { it('should not show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); @@ -621,24 +448,24 @@ export default ({ getService }: FtrProviderContext): void => { // Clear previous rule assets await deleteAllPrebuiltRuleAssets(es, log); - // Customize a number field on the installed rule + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - risk_score: 2, + tags: ['one', 'three', 'two'], }); - // Increment the version of the installed rule, update a number field, and create the new rule assets + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - risk_score: 2, + tags: ['one', 'three', 'two'], }), ]; await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // but does NOT contain number field + // but does NOT contain scalar array field const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ version: { @@ -656,7 +483,7 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe('when rule field has an update and a custom value that are different', () => { + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { it('should show in the upgrade/_review API response', async () => { // Install base prebuilt detection rule await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); @@ -665,30 +492,30 @@ export default ({ getService }: FtrProviderContext): void => { // Clear previous rule assets await deleteAllPrebuiltRuleAssets(es, log); - // Customize a number field on the installed rule + // Customize a scalar array field on the installed rule await patchRule(supertest, log, { rule_id: 'rule-1', - risk_score: 2, + tags: ['one', 'two', 'four'], }); - // Increment the version of the installed rule, update a number field, and create the new rule assets + // Increment the version of the installed rule, update a scalar array field, and create the new rule assets const updatedRuleAssetSavedObjects = [ createRuleAssetSavedObject({ rule_id: 'rule-1', version: 2, - risk_score: 3, + tags: ['one', 'two', 'five'], }), ]; await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update - // and number field update does not have a conflict + // and scalar array field update does not have a conflict const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); expect(reviewResponse.rules[0].diff.fields).toEqual({ - risk_score: { - current_version: 2, - target_version: 3, - merged_version: 3, + tags: { + current_version: ['one', 'two', 'four'], + target_version: ['one', 'two', 'five'], + merged_version: ['one', 'two', 'five'], diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, merge_outcome: ThreeWayMergeOutcome.Target, has_conflict: false, 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.single_line_string_fields.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.single_line_string_fields.ts new file mode 100644 index 0000000000000..f814d6725885a --- /dev/null +++ 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.single_line_string_fields.ts @@ -0,0 +1,376 @@ +/* + * 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 expect from 'expect'; +import { + ThreeWayDiffOutcome, + ThreeWayMergeOutcome, +} from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { FtrProviderContext } from '../../../../../../ftr_provider_context'; +import { + deleteAllTimelines, + deleteAllPrebuiltRuleAssets, + createRuleAssetSavedObject, + installPrebuiltRules, + createPrebuiltRuleAssetSavedObjects, + reviewPrebuiltRulesToUpgrade, + patchRule, + createHistoricalPrebuiltRuleAssetSavedObjects, +} from '../../../../utils'; +import { deleteAllRules } from '../../../../../../../common/utils/security_solution'; + +export default ({ getService }: FtrProviderContext): void => { + const es = getService('es'); + const supertest = getService('supertest'); + const log = getService('log'); + + describe('@ess @serverless @skipInServerlessMKI review prebuilt rules updates from package with mock rule assets', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + await deleteAllTimelines(es, log); + await deleteAllPrebuiltRuleAssets(es, log); + }); + + describe(`single line string fields`, () => { + const getRuleAssetSavedObjects = () => [ + createRuleAssetSavedObject({ rule_id: 'rule-1', version: 1, name: 'A' }), + ]; + + describe("when rule field doesn't have an update and has no custom value - scenario AAA", () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // 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 there is 1 rule eligable for update but single line string field is NOT returned + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe("when rule field doesn't have an update but has a custom value - scenario ABA", () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a single line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + name: 'B', + }); + + // 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[0].diff.fields).toEqual({ + name: { + base_version: 'A', + current_version: 'B', + target_version: 'A', + merged_version: 'B', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + has_update: false, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule field has an update but does not have a custom value - scenario AAB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Increment the version of the installed rule, update a single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + name: 'B', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + name: { + base_version: 'A', + current_version: 'A', + target_version: 'B', + merged_version: 'B', + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + + describe('when rule field has an update and a custom value that are the same - scenario ABB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a single line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + name: 'B', + }); + + // Increment the version of the installed rule, update a single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + name: 'B', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + name: { + base_version: 'A', + current_version: 'B', + target_version: 'B', + merged_version: 'B', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + has_update: false, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario ABC', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Customize a single line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + name: 'B', + }); + + // Increment the version of the installed rule, update a single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + name: 'C', + }), + ]; + await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and single line string field update has conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + name: { + base_version: 'A', + current_version: 'B', + target_version: 'C', + merged_version: 'B', + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Conflict, + has_conflict: true, + has_update: true, + }, + version: { + base_version: 1, + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(true); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule base version does not exist', () => { + describe('when rule field has an update and a custom value that are the same - scenario -AA', () => { + it('should not show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Customize a single line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + name: 'B', + }); + + // Increment the version of the installed rule, update a single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + name: 'B', + }), + ]; + await createPrebuiltRuleAssetSavedObjects(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).toEqual({ + version: { + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + + describe('when rule field has an update and a custom value that are different - scenario -AB', () => { + it('should show in the upgrade/_review API response', async () => { + // Install base prebuilt detection rule + await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects()); + await installPrebuiltRules(es, supertest); + + // Clear previous rule assets + await deleteAllPrebuiltRuleAssets(es, log); + + // Customize a single line string field on the installed rule + await patchRule(supertest, log, { + rule_id: 'rule-1', + name: 'B', + }); + + // Increment the version of the installed rule, update a single line string field, and create the new rule assets + const updatedRuleAssetSavedObjects = [ + createRuleAssetSavedObject({ + rule_id: 'rule-1', + version: 2, + name: 'C', + }), + ]; + await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects); + + // Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update + // and single line string field update does not have a conflict + const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest); + expect(reviewResponse.rules[0].diff.fields).toEqual({ + name: { + current_version: 'B', + target_version: 'C', + merged_version: 'C', + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + version: { + current_version: 1, + target_version: 2, + merged_version: 2, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + has_update: true, + }, + }); + expect(reviewResponse.rules[0].diff.has_conflict).toBe(false); + expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); + }); + }); + }); + }); + }); + }); +};