Skip to content

Commit 47cea44

Browse files
[8.19] [EDR Workflows] Prevent Event Filter list recreation with every new Cloud Workloads Defend integration (#221358) (#222328)
# Backport This will backport the following commits from `main` to `8.19`: - [[EDR Workflows] Prevent Event Filter list recreation with every new Cloud Workloads Defend integration (#221358)](#221358) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Konrad Szwarc","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-06-03T10:35:12Z","message":"[EDR Workflows] Prevent Event Filter list recreation with every new Cloud Workloads Defend integration (#221358)\n\nThis PR fixes a missing check for the existence of the event filter list\nbefore attempting to create it in the `packagePolicy` creation callback.\nThis callback is triggered when adding the Cloud Workloads Defend\nintegration.\n\nThe fix follows the same pattern used in similar list-creation logic:\n\nhttps://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/lists/server/handlers/create_exception_list_handler.ts#L39\n\n\n\nhttps://github.com/user-attachments/assets/81495092-e682-4f2d-ba9c-c149d3c8936c","sha":"539409d082f5c1416e650c452ac1474ba4d26fb8","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Defend Workflows","backport:version","v9.1.0","v8.19.0"],"title":"[EDR Workflows] Prevent Event Filter list recreation with every new Cloud Workloads Defend integration","number":221358,"url":"https://github.com/elastic/kibana/pull/221358","mergeCommit":{"message":"[EDR Workflows] Prevent Event Filter list recreation with every new Cloud Workloads Defend integration (#221358)\n\nThis PR fixes a missing check for the existence of the event filter list\nbefore attempting to create it in the `packagePolicy` creation callback.\nThis callback is triggered when adding the Cloud Workloads Defend\nintegration.\n\nThe fix follows the same pattern used in similar list-creation logic:\n\nhttps://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/lists/server/handlers/create_exception_list_handler.ts#L39\n\n\n\nhttps://github.com/user-attachments/assets/81495092-e682-4f2d-ba9c-c149d3c8936c","sha":"539409d082f5c1416e650c452ac1474ba4d26fb8"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.19"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/221358","number":221358,"mergeCommit":{"message":"[EDR Workflows] Prevent Event Filter list recreation with every new Cloud Workloads Defend integration (#221358)\n\nThis PR fixes a missing check for the existence of the event filter list\nbefore attempting to create it in the `packagePolicy` creation callback.\nThis callback is triggered when adding the Cloud Workloads Defend\nintegration.\n\nThe fix follows the same pattern used in similar list-creation logic:\n\nhttps://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/lists/server/handlers/create_exception_list_handler.ts#L39\n\n\n\nhttps://github.com/user-attachments/assets/81495092-e682-4f2d-ba9c-c149d3c8936c","sha":"539409d082f5c1416e650c452ac1474ba4d26fb8"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Konrad Szwarc <[email protected]>
1 parent e6a0656 commit 47cea44

File tree

2 files changed

+92
-14
lines changed

2 files changed

+92
-14
lines changed

x-pack/solutions/security/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,14 @@ describe('Fleet integrations', () => {
395395
soClient = savedObjectsClientMock.create();
396396
esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
397397
endpointAppContextServiceMock = createMockEndpointAppContextService();
398+
jest.clearAllMocks();
398399
endpointAppContextServiceMock.getExceptionListsClient.mockReturnValue(exceptionListClient);
399400
callback = getPackagePolicyPostCreateCallback(endpointAppContextServiceMock);
400401
policyConfig = generator.generatePolicyPackagePolicy() as PackagePolicy;
402+
// By default, simulate that the event filter list does not exist
403+
(exceptionListClient.getExceptionList as jest.Mock).mockResolvedValue(null);
404+
(exceptionListClient.createExceptionList as jest.Mock).mockResolvedValue({});
405+
(exceptionListClient.createExceptionListItem as jest.Mock).mockResolvedValue({});
401406
});
402407

403408
it('should create the Endpoint Event Filters List and add the correct Event Filters List Item attached to the policy given nonInteractiveSession parameter on integration config eventFilters', async () => {
@@ -419,6 +424,9 @@ describe('Fleet integrations', () => {
419424
req
420425
);
421426

427+
// Wait for all async code in createEventFilters to complete
428+
await new Promise(process.nextTick);
429+
422430
expect(exceptionListClient.createExceptionList).toHaveBeenCalledWith(
423431
expect.objectContaining({
424432
listId: ENDPOINT_ARTIFACT_LISTS.eventFilters.id,
@@ -446,6 +454,55 @@ describe('Fleet integrations', () => {
446454
);
447455
});
448456

457+
it('should NOT create the Event Filters List if it already exists, but should add the Event Filters List Item', async () => {
458+
const integrationConfig = {
459+
type: 'cloud',
460+
eventFilters: {
461+
nonInteractiveSession: true,
462+
},
463+
};
464+
465+
policyConfig.inputs[0]!.config!.integration_config = {
466+
value: integrationConfig,
467+
};
468+
469+
// Mock getExceptionList to return a non-null value (list already exists)
470+
(exceptionListClient.getExceptionList as jest.Mock).mockResolvedValue({
471+
id: 'existing-list-id',
472+
listId: ENDPOINT_ARTIFACT_LISTS.eventFilters.id,
473+
});
474+
475+
const postCreatedPolicyConfig = await callback(
476+
policyConfig,
477+
soClient,
478+
esClient,
479+
requestContextMock.convertContext(ctx),
480+
req
481+
);
482+
483+
// Should NOT attempt to create the list
484+
expect(exceptionListClient.createExceptionList).not.toHaveBeenCalled();
485+
// Should still create the event filter item
486+
expect(exceptionListClient.createExceptionListItem).toHaveBeenCalledWith(
487+
expect.objectContaining({
488+
listId: ENDPOINT_ARTIFACT_LISTS.eventFilters.id,
489+
tags: [`policy:${postCreatedPolicyConfig.id}`],
490+
osTypes: ['linux'],
491+
entries: [
492+
{
493+
field: 'process.entry_leader.interactive',
494+
operator: 'included',
495+
type: 'match',
496+
value: 'false',
497+
},
498+
],
499+
itemId: 'NEW_UUID',
500+
namespaceType: 'agnostic',
501+
meta: undefined,
502+
})
503+
);
504+
});
505+
449506
it('should not call Event Filters List and Event Filters List Item if nonInteractiveSession parameter is not present on integration config eventFilters', async () => {
450507
const integrationConfig = {
451508
type: 'cloud',

x-pack/solutions/security/plugins/security_solution/server/fleet_integration/handlers/create_event_filters.ts

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,45 @@ export const createEventFilters = async (
2929
if (!eventFilters?.nonInteractiveSession) {
3030
return;
3131
}
32+
3233
try {
33-
// Attempt to Create the Event Filter List. It won't create the list if it already exists.
34-
// So we can skip the validation and ignore the conflict error
35-
await exceptionsClient.createExceptionList({
36-
name: ENDPOINT_ARTIFACT_LISTS.eventFilters.name,
37-
namespaceType: 'agnostic',
38-
description: ENDPOINT_ARTIFACT_LISTS.eventFilters.description,
34+
const existingList = await exceptionsClient.getExceptionList({
3935
listId: ENDPOINT_ARTIFACT_LISTS.eventFilters.id,
40-
type: ExceptionListTypeEnum.ENDPOINT_EVENTS,
41-
immutable: false,
42-
meta: undefined,
43-
tags: [],
44-
version: 1,
36+
namespaceType: 'agnostic',
37+
id: undefined,
4538
});
39+
40+
if (existingList) {
41+
logger.debug(
42+
`Event Filter List with id "${ENDPOINT_ARTIFACT_LISTS.eventFilters.id}" already exists. Skipping creation.`
43+
);
44+
} else {
45+
logger.debug(
46+
`Event Filter List with id "${ENDPOINT_ARTIFACT_LISTS.eventFilters.id}" not found. Attempting creation.`
47+
);
48+
await exceptionsClient.createExceptionList({
49+
name: ENDPOINT_ARTIFACT_LISTS.eventFilters.name,
50+
namespaceType: 'agnostic',
51+
description: ENDPOINT_ARTIFACT_LISTS.eventFilters.description,
52+
listId: ENDPOINT_ARTIFACT_LISTS.eventFilters.id,
53+
type: ExceptionListTypeEnum.ENDPOINT_EVENTS,
54+
immutable: false,
55+
meta: undefined,
56+
tags: [],
57+
version: 1,
58+
});
59+
logger.debug(
60+
`Successfully created Event Filter List with id "${ENDPOINT_ARTIFACT_LISTS.eventFilters.id}".`
61+
);
62+
}
4663
} catch (err) {
47-
// Ignoring error 409 (Conflict)
48-
if (!SavedObjectsErrorHelpers.isConflictError(err)) {
49-
logger.error(`Error creating Event Filter List: ${wrapErrorIfNeeded(err)}`);
64+
if (SavedObjectsErrorHelpers.isConflictError(err)) {
65+
logger.debug(
66+
`Event Filter List with id "${ENDPOINT_ARTIFACT_LISTS.eventFilters.id}" already exists. Skipping creation.`
67+
);
68+
} else {
69+
logger.error(`Error during Event Filter List handling: ${wrapErrorIfNeeded(err)}`);
70+
5071
return;
5172
}
5273
}

0 commit comments

Comments
 (0)