Skip to content

Commit 7a73df9

Browse files
committed
[Security Solution] Fix DataSource payload creation during rule upgrade with MERGED pick_version (#197262)
## Summary The PR #191439 enhanced the `/upgrade/_perform` API contract and functionality to allow the users of the endpoint to upgrade rules to their `MERGED` version. However, a bug slipped in, where the two different types of `DataSource` (`type: index_patterns` or `type: data_view_id`) weren't properly handled and would cause, in some cases, a rule payload to be created having both an `index` and `data_view` field, causing upgrade to fail. This PR fixes the issue by handling these two field in a specific way, checking what the `DataSource` diffable field's type is, and setting the other field to `undefined`. ### Checklist Delete any items that are not applicable to this PR. - [ ] [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 - [ ] [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#_add_your_labels) - [ ] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) (cherry picked from commit 9656621)
1 parent 15b139e commit 7a73df9

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/diffable_rule_fields_mappings.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import { get } from 'lodash';
88
import type {
99
RuleSchedule,
10+
DataSourceIndexPatterns,
11+
DataSourceDataView,
1012
InlineKqlQuery,
1113
ThreeWayDiff,
1214
DiffableRuleTypes,
@@ -195,6 +197,10 @@ export const transformDiffableFieldValues = (
195197
} else if (fieldName === 'saved_id' && isInlineQuery(diffableFieldValue)) {
196198
// saved_id should be set only for rules with SavedKqlQuery, undefined otherwise
197199
return { type: 'TRANSFORMED_FIELD', value: undefined };
200+
} else if (fieldName === 'data_view_id' && isDataSourceIndexPatterns(diffableFieldValue)) {
201+
return { type: 'TRANSFORMED_FIELD', value: undefined };
202+
} else if (fieldName === 'index' && isDataSourceDataView(diffableFieldValue)) {
203+
return { type: 'TRANSFORMED_FIELD', value: undefined };
198204
}
199205

200206
return { type: 'NON_TRANSFORMED_FIELD' };
@@ -209,3 +215,18 @@ function isInlineQuery(value: unknown): value is InlineKqlQuery {
209215
typeof value === 'object' && value !== null && 'type' in value && value.type === 'inline_query'
210216
);
211217
}
218+
219+
function isDataSourceIndexPatterns(value: unknown): value is DataSourceIndexPatterns {
220+
return (
221+
typeof value === 'object' &&
222+
value !== null &&
223+
'type' in value &&
224+
value.type === 'index_patterns'
225+
);
226+
}
227+
228+
function isDataSourceDataView(value: unknown): value is DataSourceDataView {
229+
return (
230+
typeof value === 'object' && value !== null && 'type' in value && value.type === 'data_view'
231+
);
232+
}

x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_perform_prebuilt_rules.all_rules_mode.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import {
1717
ThreatMatchRule,
1818
FIELDS_TO_UPGRADE_TO_CURRENT_VERSION,
1919
ModeEnum,
20+
AllFieldsDiff,
21+
DataSourceIndexPatterns,
22+
QueryRule,
2023
} from '@kbn/security-solution-plugin/common/api/detection_engine';
2124
import { PrebuiltRuleAsset } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules';
2225
import { FtrProviderContext } from '../../../../../../ftr_provider_context';
@@ -246,6 +249,41 @@ export default ({ getService }: FtrProviderContext): void => {
246249
expect(installedRule.tags).toEqual(reviewRuleResponseMap.get(ruleId)?.tags);
247250
}
248251
});
252+
253+
it('correctly upgrades rules with DataSource diffs to their MERGED versions', async () => {
254+
await createHistoricalPrebuiltRuleAssetSavedObjects(es, [queryRule]);
255+
await installPrebuiltRules(es, supertest);
256+
257+
const targetObject = cloneDeep(queryRule);
258+
targetObject['security-rule'].version += 1;
259+
targetObject['security-rule'].name = TARGET_NAME;
260+
targetObject['security-rule'].tags = TARGET_TAGS;
261+
targetObject['security-rule'].index = ['auditbeat-*'];
262+
await createHistoricalPrebuiltRuleAssetSavedObjects(es, [targetObject]);
263+
264+
const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
265+
const ruleDiffFields = reviewResponse.rules[0].diff.fields as AllFieldsDiff;
266+
267+
const performUpgradeResponse = await performUpgradePrebuiltRules(es, supertest, {
268+
mode: ModeEnum.ALL_RULES,
269+
pick_version: 'MERGED',
270+
});
271+
272+
expect(performUpgradeResponse.summary.succeeded).toEqual(1);
273+
274+
const installedRules = await getInstalledRules(supertest);
275+
const installedRule = installedRules.data[0] as QueryRule;
276+
277+
expect(installedRule.name).toEqual(ruleDiffFields.name.merged_version);
278+
expect(installedRule.tags).toEqual(ruleDiffFields.tags.merged_version);
279+
280+
// Check that the updated rules has an `index` field which equals the output of the diff algorithm
281+
// for the DataSource diffable field, and that the data_view_id is correspondingly set to undefined.
282+
expect(installedRule.index).toEqual(
283+
(ruleDiffFields.data_source.merged_version as DataSourceIndexPatterns).index_patterns
284+
);
285+
expect(installedRule.data_view_id).toBe(undefined);
286+
});
249287
});
250288

251289
describe('edge cases and unhappy paths', () => {

0 commit comments

Comments
 (0)