Skip to content

Commit 1fce4e7

Browse files
author
Jacek Kolezynski
authored
[Security Solution] Add event-based telemetry for prebuilt rule upgrade API (elastic#234571)
**Partially resolves: elastic#140369** ## Summary This is another PR from of a series of PRs I am planning to create to cover the requirements in the elastic#140369 ticket. The requirement covered in this ticket is req. #6: "Events for performing update (EBT backend)" and req. #7 "Missing base versions". I am adding sending telemetry events in handling of rule update request. Each rule updated will send its own event with information about: - ruleId - ruleName - if missing base version - final result of the update - updated fields (with breakdown per conflict type). I tried to make the changes as little invasive as possible, and decided to create a separate file, `update_rule_telemetry.ts`, where the logic of building the events and sending them is encapsulated. ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [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 - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [ ] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels.
1 parent 9d6cea7 commit 1fce4e7

File tree

8 files changed

+623
-13
lines changed

8 files changed

+623
-13
lines changed

x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/create_upgradeable_rules_payload.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { calculateThreeWayRuleFieldsDiff } from '../../logic/diff/calculation/ca
2424
import { convertPrebuiltRuleAssetToRuleResponse } from '../../../rule_management/logic/detection_rules_client/converters/convert_prebuilt_rule_asset_to_rule_response';
2525
import type { RuleTriad } from '../../model/rule_groups/get_rule_groups';
2626
import { getValueForField } from './get_value_for_field';
27+
import type { RuleUpgradeContext } from './update_rule_telemetry';
2728

2829
interface CreateModifiedPrebuiltRuleAssetsProps {
2930
upgradeableRules: RuleTriad[];
@@ -34,6 +35,7 @@ interface CreateModifiedPrebuiltRuleAssetsProps {
3435
interface ProcessedRules {
3536
modifiedPrebuiltRuleAssets: PrebuiltRuleAsset[];
3637
processingErrors: Array<PromisePoolError<{ rule_id: string }>>;
38+
ruleUpgradeContexts: RuleUpgradeContext[];
3739
}
3840

3941
export const createModifiedPrebuiltRuleAssets = ({
@@ -48,7 +50,7 @@ export const createModifiedPrebuiltRuleAssets = ({
4850
on_conflict: onConflict,
4951
} = requestBody;
5052

51-
const { modifiedPrebuiltRuleAssets, processingErrors } =
53+
const { modifiedPrebuiltRuleAssets, processingErrors, ruleUpgradeContexts } =
5254
upgradeableRules.reduce<ProcessedRules>(
5355
(processedRules, upgradeableRule) => {
5456
const targetRuleType = upgradeableRule.target.type;
@@ -107,25 +109,33 @@ export const createModifiedPrebuiltRuleAssets = ({
107109

108110
processedRules.modifiedPrebuiltRuleAssets.push(modifiedPrebuiltRuleAsset);
109111

112+
processedRules.ruleUpgradeContexts.push({
113+
ruleId,
114+
ruleName: upgradeableRule.target.name,
115+
hasBaseVersion: !!upgradeableRule.base,
116+
fieldsDiff: calculatedRuleDiff,
117+
});
118+
110119
return processedRules;
111120
} catch (err) {
112121
processedRules.processingErrors.push({
113122
error: err,
114123
item: { rule_id: ruleId },
115124
});
116-
117125
return processedRules;
118126
}
119127
},
120128
{
121129
modifiedPrebuiltRuleAssets: [],
122130
processingErrors: [],
131+
ruleUpgradeContexts: [],
123132
}
124133
);
125134

126135
return {
127136
modifiedPrebuiltRuleAssets,
128137
processingErrors,
138+
ruleUpgradeContexts,
129139
};
130140
});
131141
};

x-pack/solutions/security/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_handler.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import type { Logger, KibanaRequest, KibanaResponseFactory } from '@kbn/core/server';
99
import { transformError } from '@kbn/securitysolution-es-utils';
1010
import type {
11+
FullThreeWayRuleDiff,
1112
PerformRuleUpgradeRequestBody,
1213
PerformRuleUpgradeResponseBody,
1314
RuleUpgradeSpecifier,
@@ -38,10 +39,11 @@ import type {
3839
} from '../../../../../../common/api/detection_engine';
3940
import type { PromisePoolError } from '../../../../../utils/promise_pool';
4041
import { zipRuleVersions } from '../../logic/rule_versions/zip_rule_versions';
41-
import type { RuleVersions } from '../../logic/diff/calculate_rule_diff';
4242
import { calculateRuleDiff } from '../../logic/diff/calculate_rule_diff';
4343
import type { RuleTriad } from '../../model/rule_groups/get_rule_groups';
4444
import { getPossibleUpgrades } from '../../logic/utils';
45+
import type { RuleUpgradeContext } from './update_rule_telemetry';
46+
import { sendRuleUpdateTelemetryEvents } from './update_rule_telemetry';
4547

4648
export const performRuleUpgradeHandler = async (
4749
context: SecuritySolutionRequestHandlerContext,
@@ -59,6 +61,7 @@ export const performRuleUpgradeHandler = async (
5961
const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient);
6062
const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient);
6163
const mlAuthz = ctx.securitySolution.getMlAuthz();
64+
const analytics = ctx.securitySolution.getAnalytics();
6265

6366
const { isRulesCustomizationEnabled } = detectionRulesClient.getRuleCustomizationStatus();
6467
const defaultPickVersion = isRulesCustomizationEnabled
@@ -79,6 +82,7 @@ export const performRuleUpgradeHandler = async (
7982
const updatedRules: RuleResponse[] = [];
8083
const ruleErrors: Array<PromisePoolError<{ rule_id: string }>> = [];
8184
const allErrors: PerformRuleUpgradeResponseBody['errors'] = [];
85+
const ruleUpgradeContextsMap = new Map<string, RuleUpgradeContext>();
8286

8387
const ruleUpgradeQueue: Array<{
8488
rule_id: RuleSignatureId;
@@ -165,14 +169,22 @@ export const performRuleUpgradeHandler = async (
165169
? request.body.rules.find((x) => x.rule_id === targetRule.rule_id)
166170
: undefined;
167171

168-
const conflict = getRuleUpgradeConflictState(ruleVersions, ruleUpgradeSpecifier);
172+
const { ruleDiff } = calculateRuleDiff(ruleVersions);
173+
const conflict = getRuleUpgradeConflictState(ruleDiff, ruleUpgradeSpecifier);
169174

170175
if (conflict !== ThreeWayDiffConflict.NONE) {
171176
skippedRules.push({
172177
rule_id: targetRule.rule_id,
173178
reason: SkipRuleUpgradeReasonEnum.CONFLICT,
174179
conflict,
175180
});
181+
182+
ruleUpgradeContextsMap.set(targetRule.rule_id, {
183+
ruleId: targetRule.rule_id,
184+
ruleName: currentVersion.name,
185+
hasBaseVersion: !!baseVersion,
186+
fieldsDiff: ruleDiff.fields,
187+
});
176188
return;
177189
}
178190
}
@@ -185,13 +197,18 @@ export const performRuleUpgradeHandler = async (
185197
});
186198
});
187199

188-
const { modifiedPrebuiltRuleAssets, processingErrors } = createModifiedPrebuiltRuleAssets({
189-
upgradeableRules,
190-
requestBody: request.body,
191-
defaultPickVersion,
192-
});
200+
const { modifiedPrebuiltRuleAssets, processingErrors, ruleUpgradeContexts } =
201+
createModifiedPrebuiltRuleAssets({
202+
upgradeableRules,
203+
requestBody: request.body,
204+
defaultPickVersion,
205+
});
193206
ruleErrors.push(...processingErrors);
194207

208+
ruleUpgradeContexts.forEach((ruleUpgradeContext) => {
209+
ruleUpgradeContextsMap.set(ruleUpgradeContext.ruleId, ruleUpgradeContext);
210+
});
211+
195212
if (isDryRun) {
196213
updatedRules.push(
197214
...modifiedPrebuiltRuleAssets.map((rule) => convertPrebuiltRuleAssetToRuleResponse(rule))
@@ -220,6 +237,14 @@ export const performRuleUpgradeHandler = async (
220237
rules: [],
221238
});
222239
}
240+
241+
sendRuleUpdateTelemetryEvents(
242+
analytics,
243+
ruleUpgradeContextsMap,
244+
updatedRules,
245+
ruleErrors,
246+
skippedRules
247+
);
223248
}
224249

225250
const body: PerformRuleUpgradeResponseBody = {
@@ -247,11 +272,9 @@ export const performRuleUpgradeHandler = async (
247272
};
248273

249274
function getRuleUpgradeConflictState(
250-
ruleVersions: RuleVersions,
275+
ruleDiff: FullThreeWayRuleDiff,
251276
ruleUpgradeSpecifier?: RuleUpgradeSpecifier
252277
): ThreeWayDiffConflict {
253-
const { ruleDiff } = calculateRuleDiff(ruleVersions);
254-
255278
if (ruleDiff.num_fields_with_conflicts === 0) {
256279
return ThreeWayDiffConflict.NONE;
257280
}

0 commit comments

Comments
 (0)