[Security Solution] Integration tests for rule type field diff algorithms (#193375)

## Summary

Completes https://github.com/elastic/kibana/issues/190482


Switches rule `type` field to use the implemented diff algorithms
assigned to them in https://github.com/elastic/kibana/pull/193369


Adds integration tests in accordance to
https://github.com/elastic/kibana/pull/193372 for the `upgrade/_review`
API endpoint for the rule `type` field diff algorithm.

Also fixes some nested bracket misalignment that occurred in earlier PRs
with some test files

### 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)
This commit is contained in:
Davis Plumlee 2024-10-08 18:46:33 -04:00 committed by GitHub
parent 1053493c9c
commit e119d83c26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 1068 additions and 704 deletions

View file

@ -47,6 +47,7 @@ import {
kqlQueryDiffAlgorithm,
eqlQueryDiffAlgorithm,
esqlQueryDiffAlgorithm,
ruleTypeDiffAlgorithm,
} from './algorithms';
const BASE_TYPE_ERROR = `Base version can't be of different rule type`;
@ -212,7 +213,7 @@ const calculateCustomQueryFieldsDiff = (
};
const customQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableCustomQueryFields> = {
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
kql_query: kqlQueryDiffAlgorithm,
data_source: dataSourceDiffAlgorithm,
alert_suppression: simpleDiffAlgorithm,
@ -225,7 +226,7 @@ const calculateSavedQueryFieldsDiff = (
};
const savedQueryFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableSavedQueryFields> = {
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
kql_query: kqlQueryDiffAlgorithm,
data_source: dataSourceDiffAlgorithm,
alert_suppression: simpleDiffAlgorithm,
@ -238,7 +239,7 @@ const calculateEqlFieldsDiff = (
};
const eqlFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableEqlFields> = {
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
eql_query: eqlQueryDiffAlgorithm,
data_source: dataSourceDiffAlgorithm,
event_category_override: singleLineStringDiffAlgorithm,
@ -254,7 +255,7 @@ const calculateEsqlFieldsDiff = (
};
const esqlFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableEsqlFields> = {
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
esql_query: esqlQueryDiffAlgorithm,
alert_suppression: simpleDiffAlgorithm,
};
@ -266,7 +267,7 @@ const calculateThreatMatchFieldsDiff = (
};
const threatMatchFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableThreatMatchFields> = {
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
kql_query: kqlQueryDiffAlgorithm,
data_source: dataSourceDiffAlgorithm,
threat_query: kqlQueryDiffAlgorithm,
@ -284,7 +285,7 @@ const calculateThresholdFieldsDiff = (
};
const thresholdFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableThresholdFields> = {
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
kql_query: kqlQueryDiffAlgorithm,
data_source: dataSourceDiffAlgorithm,
threshold: simpleDiffAlgorithm,
@ -299,7 +300,7 @@ const calculateMachineLearningFieldsDiff = (
const machineLearningFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableMachineLearningFields> =
{
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
machine_learning_job_id: simpleDiffAlgorithm,
anomaly_threshold: numberDiffAlgorithm,
alert_suppression: simpleDiffAlgorithm,
@ -312,7 +313,7 @@ const calculateNewTermsFieldsDiff = (
};
const newTermsFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableNewTermsFields> = {
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
kql_query: kqlQueryDiffAlgorithm,
data_source: dataSourceDiffAlgorithm,
new_terms_fields: scalarArrayDiffAlgorithm,
@ -336,5 +337,5 @@ const allFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableAllFields> = {
...thresholdFieldsDiffAlgorithms,
...machineLearningFieldsDiffAlgorithms,
...newTermsFieldsDiffAlgorithms,
type: simpleDiffAlgorithm,
type: ruleTypeDiffAlgorithm,
};

View file

@ -17,6 +17,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
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.rule_type_fields'));
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'));

View file

@ -199,12 +199,12 @@ export default ({ getService }: FtrProviderContext): void => {
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // `version` is considered an updated field
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // `type` is considered to be a conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1);
});
});
@ -273,12 +273,12 @@ export default ({ getService }: FtrProviderContext): void => {
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // `version` is considered an updated field
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // `type` is considered to be a conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1);
});
});
});
@ -611,9 +611,9 @@ export default ({ getService }: FtrProviderContext): void => {
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); // `version` is considered an updated field
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); // `version` is also considered an updated field
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // `type` is also considered to be a conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(2);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);

View file

@ -157,9 +157,56 @@ export default ({ getService }: FtrProviderContext): void => {
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 () => {
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 multi line string field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
description: 'My GREAT description.\nThis is a second line.',
});
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My GREAT description.\nThis is a second line.',
}),
];
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.description).toEqual({
base_version: 'My description.\nThis is a second line.',
current_version: 'My GREAT description.\nThis is a second line.',
target_version: 'My GREAT description.\nThis is a second line.',
merged_version: 'My GREAT description.\nThis is a second line.',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
describe('when rule field has an update and a custom value that are different - scenario ABC', () => {
describe('when all versions are mergable', () => {
it('should show in the upgrade/_review API response with a solvable conflict', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
@ -175,211 +222,164 @@ export default ({ getService }: FtrProviderContext): void => {
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My GREAT description.\nThis is a second line.',
description: 'My description.\nThis is a second line, now longer.',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and multi line string field update has no conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toEqual({
base_version: 'My description.\nThis is a second line.',
current_version: 'My GREAT description.\nThis is a second line.',
target_version: 'My GREAT description.\nThis is a second line.',
merged_version: 'My GREAT description.\nThis is a second line.',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
target_version: 'My description.\nThis is a second line, now longer.',
merged_version: 'My GREAT description.\nThis is a second line, now longer.',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Merged,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
describe('when rule field has an update and a custom value that are different - scenario ABC', () => {
describe('when all versions are mergable', () => {
it('should show in the upgrade/_review API response with a solvable conflict', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
describe('when all versions are not mergable', () => {
it('should show in the upgrade/_review API response with a non-solvable conflict', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
// Customize a multi line string field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
description: 'My GREAT description.\nThis is a second line.',
});
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My description.\nThis is a second line, now longer.',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and multi line string field update has no conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toEqual({
base_version: 'My description.\nThis is a second line.',
current_version: 'My GREAT description.\nThis is a second line.',
target_version: 'My description.\nThis is a second line, now longer.',
merged_version: 'My GREAT description.\nThis is a second line, now longer.',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Merged,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
// Customize a multi line string field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
description: 'My GREAT description.\nThis is a third line.',
});
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My EXCELLENT description.\nThis is a fourth.',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and multi line string field update has conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toEqual({
base_version: 'My description.\nThis is a second line.',
current_version: 'My GREAT description.\nThis is a third line.',
target_version: 'My EXCELLENT description.\nThis is a fourth.',
merged_version: 'My GREAT description.\nThis is a third line.',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1);
});
});
});
describe('when all versions are not mergable', () => {
it('should show in the upgrade/_review API response with a non-solvable conflict', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
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);
// Customize a multi line string field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
description: 'My GREAT description.\nThis is a third line.',
});
// Clear previous rule assets
await deleteAllPrebuiltRuleAssets(es, log);
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My EXCELLENT description.\nThis is a fourth.',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and multi line string field update has conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toEqual({
base_version: 'My description.\nThis is a second line.',
current_version: 'My GREAT description.\nThis is a third line.',
target_version: 'My EXCELLENT description.\nThis is a fourth.',
merged_version: 'My GREAT description.\nThis is a third line.',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1);
// Customize a multi line string field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
description: 'My description.\nThis is a second line.',
});
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My description.\nThis is a second line.',
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// but does NOT contain multi line string field, since -AA is treated as AAA
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
});
});
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);
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);
// Clear previous rule assets
await deleteAllPrebuiltRuleAssets(es, log);
// Customize a multi line string field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
description: 'My description.\nThis is a second line.',
});
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My description.\nThis is a second line.',
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// but does NOT contain multi line string field, since -AA is treated as AAA
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
// Customize a multi line string field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
description: 'My description.\nThis is a second line.',
});
});
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 multi line string field on the installed rule
await patchRule(supertest, log, {
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
description: 'My description.\nThis is a second line.',
});
version: 2,
description: 'My GREAT description.\nThis is a second line.',
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Increment the version of the installed rule, update a multi line string field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
description: 'My GREAT description.\nThis is a second line.',
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and multi line string field update does not have a conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toEqual({
current_version: 'My description.\nThis is a second line.',
target_version: 'My GREAT description.\nThis is a second line.',
merged_version: 'My GREAT description.\nThis is a second line.',
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and multi line string field update does not have a conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.description).toEqual({
current_version: 'My description.\nThis is a second line.',
target_version: 'My GREAT description.\nThis is a second line.',
merged_version: 'My GREAT description.\nThis is a second line.',
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
});

View file

@ -154,58 +154,144 @@ export default ({ getService }: FtrProviderContext): void => {
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 () => {
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.risk_score).toEqual({
base_version: 1,
current_version: 2,
target_version: 2,
merged_version: 2,
diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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.risk_score).toEqual({
base_version: 1,
current_version: 2,
target_version: 3,
merged_version: 2,
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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 createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await createPrebuiltRuleAssetSavedObjects(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,
});
// Clear previous rule assets
await deleteAllPrebuiltRuleAssets(es, log);
// Increment the version of the installed rule, update a number field, and create the new rule assets
// Increment the version of the installed rule with the number field maintained
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
risk_score: 2,
risk_score: 1,
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
await createPrebuiltRuleAssetSavedObjects(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
// but does NOT contain the risk_score number field, since -AA is treated as AAA
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.risk_score).toEqual({
base_version: 1,
current_version: 2,
target_version: 2,
merged_version: 2,
diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.fields.risk_score).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
describe('when rule field has an update and a custom value that are different - scenario ABC', () => {
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 createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
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',
@ -220,114 +306,28 @@ export default ({ getService }: FtrProviderContext): void => {
risk_score: 3,
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
await createPrebuiltRuleAssetSavedObjects(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 number field update does not have a conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.risk_score).toEqual({
base_version: 1,
current_version: 2,
target_version: 3,
merged_version: 2,
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
merged_version: 3,
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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);
// Increment the version of the installed rule with the number field maintained
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
risk_score: 1,
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// but does NOT contain the risk_score number field, since -AA is treated as AAA
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.risk_score).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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.risk_score).toEqual({
current_version: 2,
target_version: 3,
merged_version: 3,
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
});

View file

@ -0,0 +1,362 @@
/*
* 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 {
RuleUpdateProps,
ThreeWayDiffConflict,
ThreeWayDiffOutcome,
ThreeWayMergeOutcome,
} from '@kbn/security-solution-plugin/common/api/detection_engine';
import { getPrebuiltRuleMock } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules/mocks';
import { FtrProviderContext } from '../../../../../../ftr_provider_context';
import {
deleteAllTimelines,
deleteAllPrebuiltRuleAssets,
createRuleAssetSavedObject,
installPrebuiltRules,
createPrebuiltRuleAssetSavedObjects,
reviewPrebuiltRulesToUpgrade,
patchRule,
createHistoricalPrebuiltRuleAssetSavedObjects,
updateRule,
} 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(`rule type fields`, () => {
const getRuleAssetSavedObjects = () => [
createRuleAssetSavedObject({ rule_id: 'rule-1', version: 1, type: 'query' }),
];
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 type field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
type: 'query',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that there is 1 rule eligible for update
// but type field is NOT returned
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.type).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 type field on the installed rule
await updateRule(supertest, {
...getPrebuiltRuleMock(),
rule_id: 'rule-1',
type: 'saved_query',
query: undefined,
language: undefined,
filters: undefined,
saved_id: 'saved-query-id',
} as RuleUpdateProps);
// Increment the version of the installed rule, do NOT update the related type field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
type: 'query',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that type diff field
// is returned but field does not have an update, and the merge outcome is "Target"
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.type).toEqual({
base_version: 'query',
current_version: 'saved_query',
target_version: 'query',
merged_version: 'query',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // version field counts as upgraded
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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 type field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
type: 'saved_query',
saved_id: 'even-newer-saved-query-id',
}),
];
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.type).toEqual({
base_version: 'query',
current_version: 'query',
target_version: 'saved_query',
merged_version: 'saved_query',
diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(3); // version and query fields also have updates
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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 type field on the installed rule
await updateRule(supertest, {
...getPrebuiltRuleMock(),
rule_id: 'rule-1',
type: 'saved_query',
query: undefined,
language: undefined,
filters: undefined,
saved_id: 'saved-query-id',
} as RuleUpdateProps);
// Increment the version of the installed rule, update a type field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
type: 'saved_query',
saved_id: 'saved-query-id',
}),
];
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.type).toEqual({
base_version: 'query',
current_version: 'saved_query',
target_version: 'saved_query',
merged_version: 'saved_query',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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 type field on the installed rule
await updateRule(supertest, {
...getPrebuiltRuleMock(),
rule_id: 'rule-1',
type: 'saved_query',
query: undefined,
language: undefined,
filters: undefined,
saved_id: 'saved-query-id',
} as RuleUpdateProps);
// Increment the version of the installed rule, update a type field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
type: 'esql',
language: 'esql',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and type field update has NON_SOLVABLE conflict, and merged version is TARGET
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.type).toEqual({
base_version: 'query',
current_version: 'saved_query',
target_version: 'esql',
merged_version: 'esql',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(4); // version + type + kql_query all considered updates
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // type + kql_query both considered conflicts
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(2);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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);
// Increment the version of the installed rule, but keep type field unchanged
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
type: 'query', // unchanged
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// but does NOT contain type field
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.type).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 type field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
type: 'query',
});
// Increment the version of the installed rule, update a type field, and create the new rule assets
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
type: 'saved_query',
saved_id: 'saved-query-id',
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and type field update does have a non-solvable conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.type).toEqual({
current_version: 'query',
target_version: 'saved_query',
merged_version: 'saved_query',
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(3);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(3); // type + version + query are all considered conflicts
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(1);
});
});
});
});
});
};

View file

@ -156,58 +156,291 @@ export default ({ getService }: FtrProviderContext): void => {
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 () => {
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 scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['one', 'two', 'four'],
});
// 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,
tags: ['one', 'two', 'four'],
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// 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.tags).toEqual({
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,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['one', 'two', 'four'],
});
// 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,
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 scalar array field update has conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
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.Merged,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
it('should compare values after deduplication', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 1,
tags: ['one', 'two', 'two'],
}),
]);
await installPrebuiltRules(es, supertest);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['two', 'one', 'three'],
});
// 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,
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 scalar array field update has conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
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,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
it('should compare values sensitive of case', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 1,
tags: ['ONE', 'TWO'],
}),
]);
await installPrebuiltRules(es, supertest);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['one', 'ONE'],
});
// 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,
tags: ['ONE', 'THREE'],
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// 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.tags).toEqual({
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,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
it('should handle empty arrays', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: [],
});
// 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,
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 scalar array field update has conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
base_version: ['one', 'two', 'three'],
current_version: [],
target_version: ['one', 'two', 'five'],
merged_version: ['five'],
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Merged,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['one', 'two', 'four'],
});
// Clear previous rule assets
await deleteAllPrebuiltRuleAssets(es, log);
// Increment the version of the installed rule, update a scalar array field, and create the new rule assets
// Increment the version of the installed rule, but keep scalar array field unchanged
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
tags: ['one', 'two', 'four'],
tags: ['one', 'two', 'three'], // unchanged
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update and contains scalar array field
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// but does NOT contain scalar array field (tags is not present, since scenario -AA is not included in response)
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
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,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.fields.tags).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
describe('when rule field has an update and a custom value that are different - scenario ABC', () => {
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 createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await createPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
// Clear previous rule assets
await deleteAllPrebuiltRuleAssets(es, log);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
@ -222,263 +455,30 @@ export default ({ getService }: FtrProviderContext): void => {
tags: ['one', 'two', 'five'],
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// and scalar array field update has conflict
// and scalar array field update does not have a conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
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.Merged,
merged_version: ['one', 'two', 'five'],
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + tags
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
it('should compare values after deduplication', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 1,
tags: ['one', 'two', 'two'],
}),
]);
await installPrebuiltRules(es, supertest);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['two', 'one', 'three'],
});
// 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,
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 scalar array field update has conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
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,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
it('should compare values sensitive of case', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 1,
tags: ['ONE', 'TWO'],
}),
]);
await installPrebuiltRules(es, supertest);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['one', 'ONE'],
});
// 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,
tags: ['ONE', 'THREE'],
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// 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.tags).toEqual({
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,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
it('should handle empty arrays', async () => {
// Install base prebuilt detection rule
await createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await installPrebuiltRules(es, supertest);
// Customize a scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: [],
});
// 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,
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 scalar array field update has conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
base_version: ['one', 'two', 'three'],
current_version: [],
target_version: ['one', 'two', 'five'],
merged_version: ['five'],
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Merged,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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);
// Increment the version of the installed rule, but keep scalar array field unchanged
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
tags: ['one', 'two', 'three'], // unchanged
}),
];
await createPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
// Call the upgrade review prebuilt rules endpoint and check that one rule is eligible for update
// but does NOT contain scalar array field (tags is not present, since scenario -AA is not included in response)
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 scalar array field on the installed rule
await patchRule(supertest, log, {
rule_id: 'rule-1',
tags: ['one', 'two', 'four'],
});
// 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,
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 scalar array field update does not have a conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.tags).toEqual({
current_version: ['one', 'two', 'four'],
target_version: ['one', 'two', 'five'],
merged_version: ['one', 'two', 'five'],
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + tags
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
});
});
});

View file

@ -156,59 +156,145 @@ export default ({ getService }: FtrProviderContext): void => {
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 () => {
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.name).toEqual({
base_version: 'A',
current_version: 'B',
target_version: 'B',
merged_version: 'B',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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 NON_SOLVABLE conflict, and merged version is CURRENT
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.name).toEqual({
base_version: 'A',
current_version: 'B',
target_version: 'C',
merged_version: 'B',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
has_update: true,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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 createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
await createPrebuiltRuleAssetSavedObjects(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',
});
// Clear previous rule assets
await deleteAllPrebuiltRuleAssets(es, log);
// 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, but keep single line string field unchanged
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
name: 'B',
name: 'A', // unchanged
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
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.name).toEqual({
base_version: 'A',
current_version: 'B',
target_version: 'B',
merged_version: 'B',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NONE,
has_update: false,
has_base_version: true,
});
expect(reviewResponse.rules[0].diff.fields.name).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
describe('when rule field has an update and a custom value that are different - scenario ABC', () => {
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 createHistoricalPrebuiltRuleAssetSavedObjects(es, getRuleAssetSavedObjects());
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',
@ -223,115 +309,29 @@ export default ({ getService }: FtrProviderContext): void => {
name: 'C',
}),
];
await createHistoricalPrebuiltRuleAssetSavedObjects(es, updatedRuleAssetSavedObjects);
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 has NON_SOLVABLE conflict, and merged version is CURRENT
// and single line string field update does not have a conflict
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
expect(reviewResponse.rules[0].diff.fields.name).toEqual({
base_version: 'A',
current_version: 'B',
target_version: 'C',
merged_version: 'B',
diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Current,
conflict: ThreeWayDiffConflict.NON_SOLVABLE,
merged_version: 'C',
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // name + version are both considered conflicts
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).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);
// Increment the version of the installed rule, but keep single line string field unchanged
const updatedRuleAssetSavedObjects = [
createRuleAssetSavedObject({
rule_id: 'rule-1',
version: 2,
name: 'A', // unchanged
}),
];
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.name).toBeUndefined();
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
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.name).toEqual({
current_version: 'B',
target_version: 'C',
merged_version: 'C',
diff_outcome: ThreeWayDiffOutcome.MissingBaseCanUpdate,
merge_outcome: ThreeWayMergeOutcome.Target,
conflict: ThreeWayDiffConflict.SOLVABLE,
has_update: true,
has_base_version: false,
});
expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2);
expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // name + version are both considered conflicts
expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0);
expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1);
expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1);
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0);
});
});
});