Skip to content

Commit 4b04007

Browse files
author
Jacek Kolezynski
authored
[8.19] [Security Solution] Add event-based telemetry for prebuilt rule upgrade API (#234571) (#235318)
# Backport This will backport the following commits from `main` to `8.19`: - [[Security Solution] Add event-based telemetry for prebuilt rule upgrade API (#234571)](#234571) <!--- Backport version: 10.0.2 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Jacek Kolezynski","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-09-17T07:45:06Z","message":"[Security Solution] Add event-based telemetry for prebuilt rule upgrade API (#234571)\n\n**Partially resolves: #140369**\n\n## Summary\n\nThis is another PR from of a series of PRs I am planning to create to\ncover the requirements in the #140369 ticket.\n\nThe requirement covered in this ticket is req. #6: \"Events for\nperforming update (EBT backend)\" and req. #7 \"Missing base versions\".\n\nI am adding sending telemetry events in handling of rule update request.\nEach rule updated will send its own event with information about:\n- ruleId\n- ruleName\n- if missing base version\n- final result of the update\n- updated fields (with breakdown per conflict type). \n\nI tried to make the changes as little invasive as possible, and decided\nto create a separate file, `update_rule_telemetry.ts`, where the logic\nof building the events and sending them is encapsulated.\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n- [ ] Review the [backport\nguidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)\nand apply applicable `backport:*` labels.","sha":"a2b7329e26fe9031d387138cf0f019aa4c53cd93","branchLabelMapping":{"^v9.2.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Detections and Resp","Team: SecuritySolution","Team:Detection Rule Management","Feature:Prebuilt Detection Rules","backport:version","v9.2.0","v8.18.8","v8.19.5","v9.0.8","v9.1.5"],"title":"[Security Solution] Add event-based telemetry for prebuilt rule upgrade API","number":234571,"url":"https://github.com/elastic/kibana/pull/234571","mergeCommit":{"message":"[Security Solution] Add event-based telemetry for prebuilt rule upgrade API (#234571)\n\n**Partially resolves: #140369**\n\n## Summary\n\nThis is another PR from of a series of PRs I am planning to create to\ncover the requirements in the #140369 ticket.\n\nThe requirement covered in this ticket is req. #6: \"Events for\nperforming update (EBT backend)\" and req. #7 \"Missing base versions\".\n\nI am adding sending telemetry events in handling of rule update request.\nEach rule updated will send its own event with information about:\n- ruleId\n- ruleName\n- if missing base version\n- final result of the update\n- updated fields (with breakdown per conflict type). \n\nI tried to make the changes as little invasive as possible, and decided\nto create a separate file, `update_rule_telemetry.ts`, where the logic\nof building the events and sending them is encapsulated.\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n- [ ] Review the [backport\nguidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)\nand apply applicable `backport:*` labels.","sha":"a2b7329e26fe9031d387138cf0f019aa4c53cd93"}},"sourceBranch":"main","suggestedTargetBranches":["8.18","8.19","9.0","9.1"],"targetPullRequestStates":[{"branch":"main","label":"v9.2.0","branchLabelMappingKey":"^v9.2.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/234571","number":234571,"mergeCommit":{"message":"[Security Solution] Add event-based telemetry for prebuilt rule upgrade API (#234571)\n\n**Partially resolves: #140369**\n\n## Summary\n\nThis is another PR from of a series of PRs I am planning to create to\ncover the requirements in the #140369 ticket.\n\nThe requirement covered in this ticket is req. #6: \"Events for\nperforming update (EBT backend)\" and req. #7 \"Missing base versions\".\n\nI am adding sending telemetry events in handling of rule update request.\nEach rule updated will send its own event with information about:\n- ruleId\n- ruleName\n- if missing base version\n- final result of the update\n- updated fields (with breakdown per conflict type). \n\nI tried to make the changes as little invasive as possible, and decided\nto create a separate file, `update_rule_telemetry.ts`, where the logic\nof building the events and sending them is encapsulated.\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n- [ ] Review the [backport\nguidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)\nand apply applicable `backport:*` labels.","sha":"a2b7329e26fe9031d387138cf0f019aa4c53cd93"}},{"branch":"8.18","label":"v8.18.8","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.19","label":"v8.19.5","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.0","label":"v9.0.8","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"9.1","label":"v9.1.5","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
1 parent 56641a0 commit 4b04007

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 { calculateRuleFieldsDiff } from '../../logic/diff/calculation/calculate_
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+
FullRuleDiff,
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: FullRuleDiff,
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)