Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
536f90d
Initial logging
nikitaindik Jul 30, 2025
5864cc5
refactor: Improve logging for prebuilt rule package installation
nikitaindik Jul 31, 2025
9b71e4e
Remove unnecessary logging
nikitaindik Jul 31, 2025
a55e749
Add remaining logging wrappers
nikitaindik Jul 31, 2025
27de66a
Make logger parameter required
nikitaindik Jul 31, 2025
6411e97
Remove "?"
nikitaindik Jul 31, 2025
d9a2278
Merge remote-tracking branch 'upstream/main' into add-integration-tes…
nikitaindik Jul 31, 2025
8bcfe1a
Make TS happy
nikitaindik Jul 31, 2025
0abdaf0
Tweak logging levels
nikitaindik Jul 31, 2025
a40d484
Fail a test on purpose
nikitaindik Jul 31, 2025
f38b08c
Break another test on purpose
nikitaindik Jul 31, 2025
d215cd6
Revert
nikitaindik Aug 1, 2025
72cdc79
Merge remote-tracking branch 'upstream/main' into add-integration-tes…
nikitaindik Aug 1, 2025
9910c03
Merge remote-tracking branch 'upstream/main' into add-integration-tes…
nikitaindik Aug 2, 2025
017ec58
Rename `utils` dir to `logic`
nikitaindik Aug 2, 2025
04d78a9
Make logged messages more searchable
nikitaindik Aug 2, 2025
f83f734
`await` for `ensureInstalledPackage` result or throw in `installSecur…
nikitaindik Aug 2, 2025
ba1a128
Fix a bug with incorrect package name passed on installation
nikitaindik Aug 2, 2025
12247a9
Merge remote-tracking branch 'upstream/main' into add-integration-tes…
nikitaindik Aug 3, 2025
f8446ad
Move logger mock creation to `createMockClients`
nikitaindik Aug 4, 2025
06b0ddb
Add explicit return types for package-installing utils
nikitaindik Aug 4, 2025
0d2f534
Merge branch 'main' into add-integration-tests-logging
banderror Aug 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { SO_SEARCH_LIMIT } from '@kbn/fleet-plugin/common/constants';
import { PREBUILT_RULES_PACKAGE_NAME } from '../../../../../../common/detection_engine/constants';
Expand All @@ -15,11 +16,13 @@ import { GET_ALL_INTEGRATIONS_URL } from '../../../../../../common/api/detection
import { extractIntegrations } from './extract_integrations';
import { sortPackagesBySecurityCategory } from './sort_packages_by_security_category';
import { sortIntegrationsByStatus } from './sort_integrations_by_status';
import { getFleetPackages } from '../../logic/get_fleet_packages';
import { getFleetPackagePolicies } from '../../logic/get_package_policies';

/**
* Returns an array of Fleet integrations and their packages
*/
export const getAllIntegrationsRoute = (router: SecuritySolutionPluginRouter) => {
export const getAllIntegrationsRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
router.versioned
.get({
access: 'internal',
Expand All @@ -43,8 +46,8 @@ export const getAllIntegrationsRoute = (router: SecuritySolutionPluginRouter) =>
const fleet = ctx.securitySolution.getInternalFleetServices();

const [packages, packagePolicies] = await Promise.all([
fleet.packages.getPackages(),
fleet.packagePolicy.list(fleet.savedObjects.createInternalScopedSoClient(), {
getFleetPackages(fleet, logger),
getFleetPackagePolicies(fleet, logger, {
perPage: SO_SEARCH_LIMIT,
}),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { buildSiemResponse } from '../../../routes/utils';
import type { SecuritySolutionPluginRouter } from '../../../../../types';

import type { GetInstalledIntegrationsResponse } from '../../../../../../common/api/detection_engine/fleet_integrations';
import { GET_INSTALLED_INTEGRATIONS_URL } from '../../../../../../common/api/detection_engine/fleet_integrations';
import { createInstalledIntegrationSet } from './installed_integration_set';
import { getFleetPackages } from '../../logic/get_fleet_packages';
import { getFleetPackagePolicies } from '../../logic/get_package_policies';

/**
* Returns an array of installed Fleet integrations and their packages.
*/
export const getInstalledIntegrationsRoute = (router: SecuritySolutionPluginRouter) => {
export const getInstalledIntegrationsRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger
) => {
router.versioned
.get({
access: 'internal',
Expand All @@ -42,15 +48,12 @@ export const getInstalledIntegrationsRoute = (router: SecuritySolutionPluginRout

// Pulls all packages into memory just like the main fleet landing page
// No pagination support currently, so cannot batch this call
const allThePackages = await fleet.packages.getPackages();
const allThePackages = await getFleetPackages(fleet, logger);
allThePackages.forEach((fleetPackage) => {
set.addPackage(fleetPackage);
});

const packagePolicies = await fleet.packagePolicy.list(
fleet.savedObjects.createInternalScopedSoClient(),
{}
);
const packagePolicies = await getFleetPackagePolicies(fleet, logger);
packagePolicies.items.forEach((policy) => {
set.addPackagePolicy(policy);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { getAllIntegrationsRoute } from './get_all_integrations/route';
import { getInstalledIntegrationsRoute } from './get_installed_integrations/route';

export const registerFleetIntegrationsRoutes = (router: SecuritySolutionPluginRouter) => {
getAllIntegrationsRoute(router);
getInstalledIntegrationsRoute(router);
export const registerFleetIntegrationsRoutes = (
router: SecuritySolutionPluginRouter,
logger: Logger
) => {
getAllIntegrationsRoute(router, logger);
getInstalledIntegrationsRoute(router, logger);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import type { EndpointInternalFleetServicesInterface } from '../../../../endpoint/services/fleet';

export async function getFleetPackages(
fleet: EndpointInternalFleetServicesInterface,
logger: Logger
) {
try {
logger.debug('getFleetPackages: Fetching Fleet packages');
const packages = await fleet.packages.getPackages();
logger.debug(`getFleetPackages: Fetched Fleet packages: ${packages.length} items`);
return packages;
} catch (error) {
logger.error(`getFleetPackages: Error fetching Fleet packages`, error);
throw error;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import type { ListWithKuery } from '@kbn/fleet-plugin/common';
import type { EndpointInternalFleetServicesInterface } from '../../../../endpoint/services/fleet';

export async function getFleetPackagePolicies(
fleet: EndpointInternalFleetServicesInterface,
logger: Logger,
options: ListWithKuery & { spaceId?: string } = {}
) {
try {
logger.debug('getFleetPackagePolicies: Fetching Fleet package policies');
const soClient = fleet.savedObjects.createInternalScopedSoClient();
const packagePolicies = await fleet.packagePolicy.list(soClient, options);
logger.debug(
`getFleetPackagePolicies: Fetched Fleet package policies: ${packagePolicies.total} items`
);
return packagePolicies;
} catch (error) {
logger.error(`getFleetPackagePolicies: Error fetching Fleet package policies`, error);
throw error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe('bootstrap_prebuilt_rules_route', () => {
({ clients, context } = requestContextMock.createTools());
clients.productFeaturesService = createProductFeaturesServiceMock([]);

bootstrapPrebuiltRulesRoute(server.router);
bootstrapPrebuiltRulesRoute(server.router, clients.logger);
});

it('returns information about installed packages', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import { BOOTSTRAP_PREBUILT_RULES_URL } from '../../../../../../common/api/detection_engine/prebuilt_rules';
import type { SecuritySolutionPluginRouter } from '../../../../../types';
import { PREBUILT_RULES_OPERATION_SOCKET_TIMEOUT_MS } from '../../constants';
import { bootstrapPrebuiltRulesHandler } from './bootstrap_prebuilt_rules_handler';
import { throttleRequests } from '../../../../../utils/throttle_requests';

export const bootstrapPrebuiltRulesRoute = (router: SecuritySolutionPluginRouter) => {
export const bootstrapPrebuiltRulesRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger
) => {
router.versioned
.post({
access: 'internal',
Expand All @@ -32,6 +36,8 @@ export const bootstrapPrebuiltRulesRoute = (router: SecuritySolutionPluginRouter
version: '1',
validate: {},
},
throttleRequests(bootstrapPrebuiltRulesHandler)
throttleRequests((context, request, response) => {
return bootstrapPrebuiltRulesHandler(context, request, response, logger);
})
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
* 2.0.
*/

import type { IKibanaResponse, KibanaRequest, KibanaResponseFactory } from '@kbn/core/server';
import type {
Logger,
IKibanaResponse,
KibanaRequest,
KibanaResponseFactory,
} from '@kbn/core/server';
import { ProductFeatureSecurityKey } from '@kbn/security-solution-features/keys';
import { transformError } from '@kbn/securitysolution-es-utils';
import { installSecurityAiPromptsPackage } from '../../logic/integrations/install_ai_prompts';
Expand All @@ -25,7 +30,8 @@ import { createPrebuiltRuleObjectsClient } from '../../logic/rule_objects/prebui
export const bootstrapPrebuiltRulesHandler = async (
context: SecuritySolutionRequestHandlerContext,
_: KibanaRequest,
response: KibanaResponseFactory
response: KibanaResponseFactory,
logger: Logger
): Promise<IKibanaResponse<BootstrapPrebuiltRulesResponse>> => {
const siemResponse = buildSiemResponse(response);

Expand All @@ -47,7 +53,7 @@ export const bootstrapPrebuiltRulesHandler = async (
const packageResults: PackageInstallStatus[] = [];

// Install packages sequentially to avoid high memory usage
const prebuiltRulesResult = await installPrebuiltRulesPackage(securityContext);
const prebuiltRulesResult = await installPrebuiltRulesPackage(securityContext, logger);
packageResults.push({
name: prebuiltRulesResult.package.name,
version: prebuiltRulesResult.package.version,
Expand All @@ -62,17 +68,18 @@ export const bootstrapPrebuiltRulesHandler = async (
ruleAssetsClient,
ruleObjectsClient,
fleetServices: securityContext.getInternalFleetServices(),
logger,
});
} else {
const endpointResult = await installEndpointPackage(securityContext);
const endpointResult = await installEndpointPackage(securityContext, logger);
packageResults.push({
name: endpointResult.package.name,
version: endpointResult.package.version,
status: endpointResult.status,
});
}

const securityAiPromptsResult = await installSecurityAiPromptsPackage(securityContext);
const securityAiPromptsResult = await installSecurityAiPromptsPackage(securityContext, logger);

if (securityAiPromptsResult !== null) {
packageResults.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('add_prepackaged_rules_route', () => {
context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue(
elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse())
);
installPrebuiltRulesAndTimelinesRoute(server.router);
installPrebuiltRulesAndTimelinesRoute(server.router, clients.logger);
});

describe('status codes', () => {
Expand Down Expand Up @@ -238,6 +238,7 @@ describe('add_prepackaged_rules_route', () => {
await legacyCreatePrepackagedRules(
context.securitySolution,
clients.rulesClient,
clients.logger,
mockExceptionsClient
);

Expand All @@ -251,6 +252,7 @@ describe('add_prepackaged_rules_route', () => {
await legacyCreatePrepackagedRules(
context.securitySolution,
clients.rulesClient,
clients.logger,
mockExceptionsClient
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import { transformError } from '@kbn/securitysolution-es-utils';
import { PREBUILT_RULES_URL } from '../../../../../../common/api/detection_engine/prebuilt_rules';
import type { SecuritySolutionPluginRouter } from '../../../../../types';
Expand All @@ -14,7 +15,10 @@ import { PREBUILT_RULES_OPERATION_SOCKET_TIMEOUT_MS } from '../../constants';
// eslint-disable-next-line no-restricted-imports
import { legacyCreatePrepackagedRules } from './legacy_create_prepackaged_rules';

export const installPrebuiltRulesAndTimelinesRoute = (router: SecuritySolutionPluginRouter) => {
export const installPrebuiltRulesAndTimelinesRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger
) => {
router.versioned
.put({
access: 'public',
Expand Down Expand Up @@ -44,6 +48,7 @@ export const installPrebuiltRulesAndTimelinesRoute = (router: SecuritySolutionPl
const validated = await legacyCreatePrepackagedRules(
await context.securitySolution,
rulesClient,
logger,
undefined
);
return response.ok({ body: validated ?? {} });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import type { RulesClient } from '@kbn/alerting-plugin/server';
import type { ExceptionListClient } from '@kbn/lists-plugin/server';
import type { InstallPrebuiltRulesAndTimelinesResponse } from '../../../../../../common/api/detection_engine/prebuilt_rules';
Expand Down Expand Up @@ -35,6 +36,7 @@ export class PrepackagedRulesError extends Error {
export const legacyCreatePrepackagedRules = async (
context: SecuritySolutionApiRequestHandlerContext,
rulesClient: RulesClient,
logger: Logger,
exceptionsClient?: ExceptionListClient
): Promise<InstallPrebuiltRulesAndTimelinesResponse> => {
const savedObjectsClient = context.core.savedObjects.client;
Expand All @@ -52,7 +54,11 @@ export const legacyCreatePrepackagedRules = async (
await exceptionsListClient.createEndpointList();
}

const latestPrebuiltRules = await ensureLatestRulesPackageInstalled(ruleAssetsClient, context);
const latestPrebuiltRules = await ensureLatestRulesPackageInstalled(
ruleAssetsClient,
context,
logger
);

const installedPrebuiltRules = rulesToMap(await getExistingPrepackagedRules({ rulesClient }));
const rulesToInstall = getRulesToInstall(latestPrebuiltRules, installedPrebuiltRules);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { transformError } from '@kbn/securitysolution-es-utils';
import type { KibanaRequest, KibanaResponseFactory } from '@kbn/core/server';
import type { Logger, KibanaRequest, KibanaResponseFactory } from '@kbn/core/server';
import { SkipRuleInstallReason } from '../../../../../../common/api/detection_engine/prebuilt_rules';
import type {
PerformRuleInstallationResponseBody,
Expand All @@ -27,7 +27,8 @@ import { excludeLicenseRestrictedRules } from '../../logic/utils';
export const performRuleInstallationHandler = async (
context: SecuritySolutionRequestHandlerContext,
request: KibanaRequest<unknown, unknown, PerformRuleInstallationRequestBody>,
response: KibanaResponseFactory
response: KibanaResponseFactory,
logger: Logger
) => {
const siemResponse = buildSiemResponse(response);

Expand All @@ -48,7 +49,7 @@ export const performRuleInstallationHandler = async (

// If this API is used directly without hitting any detection engine
// pages first, the rules package might be missing.
await ensureLatestRulesPackageInstalled(ruleAssetsClient, ctx.securitySolution);
await ensureLatestRulesPackageInstalled(ruleAssetsClient, ctx.securitySolution, logger);

const allLatestVersions = await ruleAssetsClient.fetchLatestVersions();
const currentRuleVersions = await ruleObjectsClient.fetchInstalledRuleVersions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import type { Logger } from '@kbn/core/server';
import {
PERFORM_RULE_INSTALLATION_URL,
PerformRuleInstallationRequestBody,
Expand All @@ -18,7 +19,10 @@ import {
import { routeLimitedConcurrencyTag } from '../../../../../utils/route_limited_concurrency_tag';
import { performRuleInstallationHandler } from './perform_rule_installation_handler';

export const performRuleInstallationRoute = (router: SecuritySolutionPluginRouter) => {
export const performRuleInstallationRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger
) => {
router.versioned
.post({
access: 'internal',
Expand All @@ -44,6 +48,8 @@ export const performRuleInstallationRoute = (router: SecuritySolutionPluginRoute
},
},
},
performRuleInstallationHandler
(context, request, response) => {
return performRuleInstallationHandler(context, request, response, logger);
}
);
};
Loading