diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts index 5809af1b1642f..7dbc67e6125b0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts @@ -5,18 +5,25 @@ * 2.0. */ +import { Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; - +import { initPromisePool } from '../../../../../utils/promise_pool'; +import { buildSiemResponse } from '../../utils'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; + import { DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL } from '../../../../../../common/constants'; import { GetInstalledIntegrationsResponse } from '../../../../../../common/detection_engine/schemas/response/get_installed_integrations_response_schema'; -import { buildSiemResponse } from '../../utils'; import { createInstalledIntegrationSet } from './installed_integration_set'; +const MAX_CONCURRENT_REQUESTS_TO_PACKAGE_REGISTRY = 5; + /** * Returns an array of installed Fleet integrations and their packages. */ -export const getInstalledIntegrationsRoute = (router: SecuritySolutionPluginRouter) => { +export const getInstalledIntegrationsRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { router.get( { path: DETECTION_ENGINE_INSTALLED_INTEGRATIONS_URL, @@ -39,17 +46,40 @@ export const getInstalledIntegrationsRoute = (router: SecuritySolutionPluginRout set.addPackagePolicy(policy); }); - const registryPackages = await Promise.all( - set.getPackages().map((packageInfo) => { - return fleet.packages.getRegistryPackage( + const registryPackages = await initPromisePool({ + concurrency: MAX_CONCURRENT_REQUESTS_TO_PACKAGE_REGISTRY, + items: set.getPackages(), + executor: async (packageInfo) => { + const registryPackage = await fleet.packages.getRegistryPackage( packageInfo.package_name, packageInfo.package_version ); - }) - ); + return registryPackage; + }, + }); + + if (registryPackages.errors.length > 0) { + const errors = registryPackages.errors.map(({ error, item }) => { + return { + error, + packageId: `${item.package_name}@${item.package_version}`, + }; + }); + + const packages = errors.map((e) => e.packageId).join(', '); + logger.error( + `Unable to retrieve installed integrations. Error fetching packages from registry: ${packages}.` + ); + + errors.forEach(({ error, packageId }) => { + const logMessage = `Error fetching package info from registry for ${packageId}`; + const logReason = error instanceof Error ? error.message : String(error); + logger.debug(`${logMessage}. ${logReason}`); + }); + } - registryPackages.forEach((registryPackage) => { - set.addRegistryPackage(registryPackage.packageInfo); + registryPackages.results.forEach(({ result }) => { + set.addRegistryPackage(result.packageInfo); }); const installedIntegrations = set.getIntegrations(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/installed_integration_set.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/installed_integration_set.ts index 5ea546359c972..092435a07f360 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/installed_integration_set.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/installed_integration_set.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { flatten } from 'lodash'; +import { capitalize, flatten } from 'lodash'; import { PackagePolicy, RegistryPackage } from '@kbn/fleet-plugin/common'; import { InstalledIntegration, @@ -35,7 +35,7 @@ export const createInstalledIntegrationSet = (): IInstalledIntegrationSet => { const addPackagePolicy = (policy: PackagePolicy): void => { const packageInfo = getPackageInfoFromPolicy(policy); - const integrationsInfo = getIntegrationsInfoFromPolicy(policy); + const integrationsInfo = getIntegrationsInfoFromPolicy(policy, packageInfo); const packageKey = `${packageInfo.package_name}:${packageInfo.package_version}`; const existingPackageInfo = packageMap.get(packageKey); @@ -121,11 +121,16 @@ const getPackageInfoFromPolicy = (policy: PackagePolicy): InstalledPackageBasicI }; }; -const getIntegrationsInfoFromPolicy = (policy: PackagePolicy): InstalledIntegrationBasicInfo[] => { +const getIntegrationsInfoFromPolicy = ( + policy: PackagePolicy, + packageInfo: InstalledPackageBasicInfo +): InstalledIntegrationBasicInfo[] => { return policy.inputs.map((input) => { + const integrationName = normalizeString(input.policy_template); // e.g. 'cloudtrail' + const integrationTitle = `${packageInfo.package_title} ${capitalize(integrationName)}`; // e.g. 'AWS Cloudtrail' return { - integration_name: normalizeString(input.policy_template), - integration_title: '', // this gets initialized later in addRegistryPackage() + integration_name: integrationName, + integration_title: integrationTitle, // title gets re-initialized later in addRegistryPackage() is_enabled: input.enabled, }; }); diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index d64cbd397ecfa..04bc2e1e3988a 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -119,7 +119,7 @@ export const initRoutes = ( getRuleExecutionEventsRoute(router); - getInstalledIntegrationsRoute(router); + getInstalledIntegrationsRoute(router, logger); createTimelinesRoute(router, config, security); patchTimelinesRoute(router, config, security);