diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.test.ts index e5837c8184a5f..c4c2668f710f3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.test.ts @@ -303,7 +303,47 @@ describe('extractIntegrations', () => { }); describe('for packages with only one policy template', () => { - it('extracts package title', () => { + it('extracts two integrations when package and integration names DO NOT match', () => { + const packages = [ + { + name: 'package-a', + title: 'Package A', + version: '1.1.1', + policy_templates: [ + { + name: 'integration-a', + title: 'Integration A', + }, + ], + }, + ] as PackageList; + + const result = extractIntegrations(packages, []); + + expect(result.length).toBe(2); + }); + + it('extracts one integration when package and integration names match', () => { + const packages = [ + { + name: 'package-a', + title: 'Package A', + version: '1.1.1', + policy_templates: [ + { + name: 'package-a', + title: 'Package A', + }, + ], + }, + ] as PackageList; + + const result = extractIntegrations(packages, []); + + expect(result.length).toBe(1); + }); + + it('extracts package title for both integrations', () => { const packages = [ { name: 'package-a', @@ -325,6 +365,10 @@ describe('extractIntegrations', () => { package_name: 'package-a', package_title: 'Package A', }), + expect.objectContaining({ + package_name: 'package-a', + package_title: 'Package A', + }), ]); }); @@ -345,15 +389,40 @@ describe('extractIntegrations', () => { const result = extractIntegrations(packages, []); - expect(result).toEqual([ + expect(result).toContainEqual( expect.objectContaining({ integration_name: 'integration-a', integration_title: 'Package A Integration a', - }), - ]); + }) + ); + }); + + it('DOES NOT extract integration title for an extra integration', () => { + const packages = [ + { + name: 'package-a', + title: 'Package A', + version: '1.1.1', + policy_templates: [ + { + name: 'integration-a', + title: 'Integration A', + }, + ], + }, + ] as PackageList; + + const result = extractIntegrations(packages, []); + + expect(result).toEqual( + expect.not.objectContaining({ + integration_name: expect.anything(), + integration_title: expect.anything(), + }) + ); }); - it('omits integration_name and integration_title are omitted when package and integration names match', () => { + it('omits integration_name and integration_title when package and integration names match', () => { const packages = [ { name: 'integration-a', @@ -399,6 +468,9 @@ describe('extractIntegrations', () => { expect.objectContaining({ latest_package_version: '1.1.1', }), + expect.objectContaining({ + latest_package_version: '1.1.1', + }), ]); }); @@ -424,6 +496,10 @@ describe('extractIntegrations', () => { is_installed: false, is_enabled: false, }), + expect.objectContaining({ + is_installed: false, + is_enabled: false, + }), ]); }); @@ -455,6 +531,10 @@ describe('extractIntegrations', () => { is_installed: true, is_enabled: false, }), + expect.objectContaining({ + is_installed: true, + is_enabled: false, + }), ]); }); @@ -499,6 +579,10 @@ describe('extractIntegrations', () => { is_installed: true, is_enabled: true, }), + expect.objectContaining({ + is_installed: true, + is_enabled: true, + }), ]); }); @@ -542,6 +626,9 @@ describe('extractIntegrations', () => { expect.objectContaining({ installed_package_version: '1.0.0', }), + expect.objectContaining({ + installed_package_version: '1.0.0', + }), ]); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.ts index 23cd03cedbe36..065d307fe1f76 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_all_integrations/extract_integrations.ts @@ -26,29 +26,36 @@ export function extractIntegrations( const packagePolicyTemplates = fleetPackage.policy_templates ?? []; for (const policyTemplate of packagePolicyTemplates) { - const integrationId = getIntegrationId(packageName, policyTemplate.name); const integrationName = policyTemplate.name; - const integrationTitle = - packagePolicyTemplates.length === 1 && policyTemplate.name === fleetPackage.name - ? packageTitle - : `${packageTitle} ${capitalize(policyTemplate.title)}`; - const integration: Integration = { - package_name: packageName, - package_title: packageTitle, - latest_package_version: fleetPackage.version, - installed_package_version: installedPackageVersion, - integration_name: packageName !== integrationName ? integrationName : undefined, - integration_title: packageName !== integrationName ? integrationTitle : undefined, - is_installed: isPackageInstalled, // All integrations installed as a part of the package - is_enabled: enabledIntegrationsSet.has(integrationId), - }; + if (integrationName !== packageName) { + const integrationId = getIntegrationId(packageName, integrationName); + const integrationTitle = `${packageTitle} ${capitalize(policyTemplate.title)}`; + const integration: Integration = { + package_name: packageName, + package_title: packageTitle, + latest_package_version: fleetPackage.version, + installed_package_version: installedPackageVersion, + integration_name: integrationName, + integration_title: integrationTitle, + is_installed: isPackageInstalled, // All integrations installed as a part of the package + is_enabled: enabledIntegrationsSet.has(integrationId), + }; - result.push(integration); + result.push(integration); + } } - // some packages don't have policy templates at al, e.g. Lateral Movement Detection - if (packagePolicyTemplates.length === 0) { + // There are two edge cases here + // + // - (1) Some prebuilt rules don't use integration name when there is just + // one integration per package, e.g. "Web Application Suspicious Activity: + // Unauthorized Method" refers "apm" package name while apm package has + // "apmserver" integration + // + // - (2) Some packages don't have policy templates at all, + // e.g. "Lateral Movement Detection" + if (packagePolicyTemplates.length <= 1) { result.push({ package_name: packageName, package_title: packageTitle,