Skip to content

Commit 539409d

Browse files
authored
[EDR Workflows] Prevent Event Filter list recreation with every new Cloud Workloads Defend integration (#221358)
This PR fixes a missing check for the existence of the event filter list before attempting to create it in the `packagePolicy` creation callback. This callback is triggered when adding the Cloud Workloads Defend integration. The fix follows the same pattern used in similar list-creation logic: https://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/lists/server/handlers/create_exception_list_handler.ts#L39 https://github.com/user-attachments/assets/81495092-e682-4f2d-ba9c-c149d3c8936c
1 parent f8ad8a3 commit 539409d

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)