From 2751c1934e9505836d92372ad69f4fefc4f714d4 Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 3 Dec 2025 13:20:35 +0100 Subject: [PATCH 01/10] Add integration knowledge opt out UI setting and enable feature flag --- .../fleet/common/experimental_features.ts | 2 +- .../fleet/common/types/models/settings.ts | 1 + .../installed_integration_action_menu.tsx | 170 +++++++++------ .../integration_knowledge_flyout.tsx | 203 ++++++++++++++++++ .../plugins/shared/fleet/server/plugin.ts | 2 + .../routes/settings/settings_handler.ts | 7 +- .../fleet/server/saved_objects/index.ts | 17 +- .../get_integration_knowledge_setting.ts | 42 ++++ .../steps/step_save_knowledge_base.ts | 39 +++- .../shared/fleet/server/services/settings.ts | 24 ++- .../reindex_integration_knowledge_task.ts | 116 ++++++++++ .../fleet/server/types/rest_spec/settings.ts | 7 +- .../fleet/server/types/so_attributes.ts | 1 + 13 files changed, 547 insertions(+), 84 deletions(-) create mode 100644 x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx create mode 100644 x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts create mode 100644 x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts diff --git a/x-pack/platform/plugins/shared/fleet/common/experimental_features.ts b/x-pack/platform/plugins/shared/fleet/common/experimental_features.ts index 69dffdc5cf093..4e8351a5416f6 100644 --- a/x-pack/platform/plugins/shared/fleet/common/experimental_features.ts +++ b/x-pack/platform/plugins/shared/fleet/common/experimental_features.ts @@ -17,7 +17,7 @@ const _allowedExperimentalValues = { enableOtelIntegrations: true, enableAgentStatusAlerting: true, enableAgentPrivilegeLevelChange: false, - installIntegrationsKnowledge: false, + installIntegrationsKnowledge: true, enableFleetPolicyRevisionsCleanupTask: true, agentlessPoliciesAPI: true, // When enabled, agentless policies API will be enabled. useAgentlessAPIInUI: true, // When enabled, Fleet UI will use agentless policies API to create agentless policies. diff --git a/x-pack/platform/plugins/shared/fleet/common/types/models/settings.ts b/x-pack/platform/plugins/shared/fleet/common/types/models/settings.ts index 4887775df3e4d..29f5a95ebbad8 100644 --- a/x-pack/platform/plugins/shared/fleet/common/types/models/settings.ts +++ b/x-pack/platform/plugins/shared/fleet/common/types/models/settings.ts @@ -23,6 +23,7 @@ export interface BaseSettings { metrics?: 'success' | null; synthetics?: 'success' | null; }; + integration_knowledge_enabled?: boolean; } export interface Settings extends BaseSettings { diff --git a/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/installed_integration_action_menu.tsx b/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/installed_integration_action_menu.tsx index 0d94230e55bf5..1e84b8195ee98 100644 --- a/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/installed_integration_action_menu.tsx +++ b/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/installed_integration_action_menu.tsx @@ -20,19 +20,17 @@ import { useInstalledIntegrationsActions } from '../hooks/use_installed_integrat import { ExperimentalFeaturesService } from '../../../../../services'; import { useLicense } from '../../../../../hooks'; +import { IntegrationKnowledgeFlyout } from './integration_knowledge_flyout'; + export const InstalledIntegrationsActionMenu: React.FunctionComponent<{ selectedItems: InstalledPackageUIPackageListItem[]; }> = ({ selectedItems }) => { const [isOpen, setIsOpen] = useState(false); + const [showIntegrationKnowledgeFlyout, setShowIntegrationKnowledgeFlyout] = useState(false); const { enablePackageRollback } = ExperimentalFeaturesService.get(); const licenseService = useLicense(); const button = ( - setIsOpen((s) => !s)} - > + setIsOpen((s) => !s)}> { + setIsOpen(false); + setShowIntegrationKnowledgeFlyout(true); + }, []); + const items = useMemo(() => { const hasUpgreadableIntegrations = selectedItems.some( (item) => @@ -80,78 +83,99 @@ export const InstalledIntegrationsActionMenu: React.FunctionComponent<{ !!item.installationInfo?.previous_version && !item.installationInfo?.is_rollback_ttl_expired ); - return [ + const menuItems = [ , - - {hasUninstallableIntegrations ? ( - - } + ]; + + if (selectedItems.length > 0) { + menuItems.push( + ...[ + - - ) : ( - - )} - , - ...(enablePackageRollback - ? [ - + , + + {hasUninstallableIntegrations ? ( + + } + > + + + ) : ( - , - ] - : []), - ]; + )} + , + ...(enablePackageRollback + ? [ + + + , + ] + : []), + ] + ); + } + + return menuItems; }, [ selectedItems, openUninstallModal, @@ -159,18 +183,24 @@ export const InstalledIntegrationsActionMenu: React.FunctionComponent<{ openRollbackModal, enablePackageRollback, licenseService, + openManageIntegrationKnowledgeFlyout, ]); return ( - setIsOpen(false)} - panelPaddingSize="none" - anchorPosition="downLeft" - > - - + <> + setIsOpen(false)} + panelPaddingSize="none" + anchorPosition="downLeft" + > + + + {showIntegrationKnowledgeFlyout && ( + setShowIntegrationKnowledgeFlyout(false)} /> + )} + ); }; diff --git a/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx b/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx new file mode 100644 index 0000000000000..bda0999a3bcf5 --- /dev/null +++ b/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx @@ -0,0 +1,203 @@ +/* + * 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 React, { useCallback, useEffect } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiSwitch, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { i18n } from '@kbn/i18n'; + +import { + useAuthz, + useGetSettingsQuery, + usePutSettingsMutation, + useStartServices, +} from '../../../../../hooks'; +import { Loading } from '../../../../../components'; + +export const IntegrationKnowledgeFlyout: React.FunctionComponent<{ + onClose: () => void; +}> = ({ onClose }) => { + const [integrationKnowledgeSetting, setIntegrationKnowledgeSetting] = + React.useState(false); + + const authz = useAuthz(); + const { notifications } = useStartServices(); + + const { data: settings, isInitialLoading: isSettingsInitialLoading } = useGetSettingsQuery({ + enabled: authz.fleet.readSettings, + }); + + useEffect(() => { + const isEnabled = Boolean(settings?.item.integration_knowledge_enabled); + setIntegrationKnowledgeSetting(isEnabled); + }, [settings?.item.integration_knowledge_enabled]); + + const { mutateAsync: mutateSettingsAsync } = usePutSettingsMutation(); + + const updateSettings = useCallback( + async (integrationKnowledgeEnabled: boolean) => { + try { + setIntegrationKnowledgeSetting(integrationKnowledgeEnabled); + const res = await mutateSettingsAsync({ + integration_knowledge_enabled: integrationKnowledgeEnabled, + }); + + if (res.error) { + throw res.error; + } + } catch (error) { + setIntegrationKnowledgeSetting(!integrationKnowledgeEnabled); + notifications.toasts.addError(error, { + title: i18n.translate('xpack.fleet.integrationKnowledgeFlyout.errorUpdatingSettings', { + defaultMessage: 'Error updating intergration knowledge setting', + }), + }); + } + }, + [mutateSettingsAsync, notifications.toasts] + ); + + const saveIntegrationKnowledgeSetting = (setting: boolean) => { + updateSettings(setting); + onClose(); + }; + return ( + + + +

+ +

+
+
+ + {isSettingsInitialLoading ? ( + + ) : ( + + + +

+ +

+

+ +

+

+ +

+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+

+ +

+

+ +

+
+
+ + setIntegrationKnowledgeSetting(e.target.checked)} + label={ + + } + /> + +
+ )} +
+ + + + + + + + + saveIntegrationKnowledgeSetting(integrationKnowledgeSetting)} + aria-label="Save" + disabled={ + integrationKnowledgeSetting === + Boolean(settings?.item.integration_knowledge_enabled) + } + > + + + + + +
+ ); +}; diff --git a/x-pack/platform/plugins/shared/fleet/server/plugin.ts b/x-pack/platform/plugins/shared/fleet/server/plugin.ts index c49837171a275..6cf409cb81dfd 100644 --- a/x-pack/platform/plugins/shared/fleet/server/plugin.ts +++ b/x-pack/platform/plugins/shared/fleet/server/plugin.ts @@ -160,6 +160,7 @@ import { registerAgentlessDeploymentSyncTask, scheduleAgentlessDeploymentSyncTask, } from './tasks/agentless/deployment_sync_task'; +import { registerReindexIntegrationKnowledgeTask } from './tasks/reindex_integration_knowledge_task'; export interface FleetSetupDeps { security: SecurityPluginSetup; @@ -664,6 +665,7 @@ export class FleetPlugin registerPackagesBulkOperationTask(deps.taskManager); registerSetupTasks(deps.taskManager); registerAgentlessDeploymentSyncTask(deps.taskManager, this.configInitialValue); + registerReindexIntegrationKnowledgeTask(deps.taskManager); this.bulkActionsResolver = new BulkActionsResolver(deps.taskManager, core); this.checkDeletedFilesTask = new CheckDeletedFilesTask({ diff --git a/x-pack/platform/plugins/shared/fleet/server/routes/settings/settings_handler.ts b/x-pack/platform/plugins/shared/fleet/server/routes/settings/settings_handler.ts index 13c1a1317ebf8..eeda186a4bc4a 100644 --- a/x-pack/platform/plugins/shared/fleet/server/routes/settings/settings_handler.ts +++ b/x-pack/platform/plugins/shared/fleet/server/routes/settings/settings_handler.ts @@ -12,8 +12,9 @@ import type { PutSettingsRequestSchema, PutSpaceSettingsRequestSchema, } from '../../types'; -import { settingsService } from '../../services'; +import { appContextService, settingsService } from '../../services'; import { getSpaceSettings, saveSpaceSettings } from '../../services/spaces/space_settings'; +import { scheduleReindexIntegrationKnowledgeTask } from '../../tasks/reindex_integration_knowledge_task'; export const getSpaceSettingsHandler: FleetRequestHandler = async (context, request, response) => { const soClient = (await context.fleet).internalSoClient; @@ -73,6 +74,10 @@ export const putSettingsHandler: FleetRequestHandler< try { const settings = await settingsService.saveSettings(soClient, request.body); + if (request.body.integration_knowledge_enabled) { + await scheduleReindexIntegrationKnowledgeTask(appContextService.getTaskManagerStart()!); + } + const body = { item: settings, }; diff --git a/x-pack/platform/plugins/shared/fleet/server/saved_objects/index.ts b/x-pack/platform/plugins/shared/fleet/server/saved_objects/index.ts index 3a33a0645bb1c..13eafe8a8efa9 100644 --- a/x-pack/platform/plugins/shared/fleet/server/saved_objects/index.ts +++ b/x-pack/platform/plugins/shared/fleet/server/saved_objects/index.ts @@ -33,7 +33,7 @@ import { SPACE_SETTINGS_SAVED_OBJECT_TYPE, } from '../constants'; -import { SettingsSchemaV5 } from '../types'; +import { SettingsSchemaV5, SettingsSchemaV6 } from '../types'; import { migrateSyntheticsPackagePolicyToV8120 } from './migrations/synthetics/to_v8_12_0'; @@ -179,6 +179,7 @@ export const getSavedObjectTypes = ( dynamic: false, properties: {}, }, + integration_knowledge_enabled: { type: 'boolean' }, }, }, migrations: { @@ -241,6 +242,20 @@ export const getSavedObjectTypes = ( create: SettingsSchemaV5, }, }, + 6: { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + integration_knowledge_enabled: { type: 'boolean' }, + }, + }, + ], + schemas: { + forwardCompatibility: SettingsSchemaV6.extends({}, { unknowns: 'ignore' }), + create: SettingsSchemaV6, + }, + }, }, }, [LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE]: { diff --git a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts new file mode 100644 index 0000000000000..ec176de641b47 --- /dev/null +++ b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts @@ -0,0 +1,42 @@ +/* + * 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 { SavedObjectsClientContract } from '@kbn/core/server'; + +import { appContextService } from '../../app_context'; +import { getSettings } from '../../settings'; + +export async function getIntegrationKnowledgeSetting( + savedObjectsClient: SavedObjectsClientContract +): Promise { + const config = appContextService.getConfig(); + + const integrationKnowledgeConfig: boolean = + config?.experimentalFeatures?.integrationKnowledge || + appContextService.getExperimentalFeatures().installIntegrationsKnowledge; + try { + const { integration_knowledge_enabled: integrationKnowledgeEnabled } = await getSettings( + savedObjectsClient + ); + appContextService + .getLogger() + .debug( + `getIntegrationKnowledgeSetting returns ${ + integrationKnowledgeEnabled ?? integrationKnowledgeConfig + }` + ); + return integrationKnowledgeEnabled ?? integrationKnowledgeConfig; + } catch (err) { + appContextService + .getLogger() + .warn( + 'Error while trying to load integration knowledge flag from settings, defaulting to feature flag', + err + ); + } + return integrationKnowledgeConfig; +} diff --git a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts index 5860c266e846f..23bd7e56f28c2 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts @@ -7,6 +7,10 @@ import path from 'path'; +import type { Logger } from '@kbn/core/server'; + +import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; + import { FleetError } from '../../../../../errors'; import { saveKnowledgeBaseContentToIndex, @@ -24,7 +28,7 @@ import type { EsAssetReference } from '../../../../../types'; import { updateEsAssetReferences } from '../../es_assets_reference'; import type { KnowledgeBaseItem } from '../../../../../../common/types/models/epm'; import { licenseService } from '../../../../license'; -import { appContextService } from '../../../../app_context'; +import { getIntegrationKnowledgeSetting } from '../../get_integration_knowledge_setting'; export const KNOWLEDGE_BASE_PATH = 'docs/knowledge_base/'; export const DOCS_PATH_PATTERN = '/docs/'; export const KNOWLEDGE_BASE_FOLDER = 'knowledge_base/'; @@ -82,17 +86,18 @@ export async function stepSaveKnowledgeBase( const { packageInstallContext, esClient, savedObjectsClient, logger } = context; const { packageInfo, archiveIterator } = packageInstallContext; - let esReferences = context.esReferences ?? []; + const esReferences = context.esReferences ?? []; logger.debug( `Knowledge base step: Starting for package ${packageInfo.name}@${packageInfo.version}` ); - // Check if knowledge base installation is enabled via experimental feature flag - const experimentalFeatures = appContextService.getExperimentalFeatures(); - if (!experimentalFeatures.installIntegrationsKnowledge) { + const integrationKnowledgeEnabled = await getIntegrationKnowledgeSetting(savedObjectsClient); + + // Check if knowledge base installation is enabled via user setting + if (!integrationKnowledgeEnabled) { logger.debug( - `Knowledge base step: Skipping knowledge base save - installIntegrationsKnowledge experimental feature is disabled` + `Knowledge base step: Skipping knowledge base save - integration knowledge enabled setting is disabled` ); return { esReferences }; } @@ -104,6 +109,24 @@ export async function stepSaveKnowledgeBase( return { esReferences }; } + return await indexKnowledgeBase( + esReferences, + savedObjectsClient, + esClient, + logger, + packageInfo, + archiveIterator + ); +} + +export async function indexKnowledgeBase( + esReferences: EsAssetReference[], + savedObjectsClient: SavedObjectsClientContract, + esClient: ElasticsearchClient, + logger: Logger, + packageInfo: { name: string; version: string }, + archiveIterator: ArchiveIterator +): Promise<{ esReferences: EsAssetReference[] }> { // Extract knowledge base content directly from the archive const knowledgeBaseItems = await extractKnowledgeBaseFromArchive( archiveIterator, @@ -125,7 +148,9 @@ export async function stepSaveKnowledgeBase( knowledgeBaseContent: knowledgeBaseItems, }); - logger.debug(`Knowledge base step: Saved ${documentIds.length} documents to index`); + logger.debug( + `Knowledge base step: Saved ${documentIds.length} documents to index for package ${packageInfo.name}@${packageInfo.version}` + ); // Add knowledge base asset references using the ES-generated document IDs const knowledgeBaseAssetRefs = documentIds.map((docId) => ({ diff --git a/x-pack/platform/plugins/shared/fleet/server/services/settings.ts b/x-pack/platform/plugins/shared/fleet/server/services/settings.ts index 1560c6c9818c8..5178e4d93d951 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/settings.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/settings.ts @@ -40,6 +40,7 @@ function mapSettingsSO(settingsSo: SavedObject): Settings preconfigured_fields: getConfigFleetServerHosts() ? ['fleet_server_hosts'] : [], delete_unenrolled_agents: settingsSo.attributes.delete_unenrolled_agents, ilm_migration_status: settingsSo.attributes.ilm_migration_status, + integration_knowledge_enabled: settingsSo.attributes.integration_knowledge_enabled, }; } @@ -77,10 +78,20 @@ export async function settingsSetup(soClient: SavedObjectsClientContract) { try { const config = appContextService.getConfig(); const settings = await getSettings(soClient); + + const updatedSettings = {} as Partial; if (config?.prereleaseEnabledByDefault && !settings.prerelease_integrations_enabled) { - await saveSettings(soClient, { - prerelease_integrations_enabled: config?.prereleaseEnabledByDefault, - }); + updatedSettings.prerelease_integrations_enabled = config?.prereleaseEnabledByDefault; + } + if ( + (config?.experimentalFeatures?.integrationKnowledge || + appContextService.getExperimentalFeatures().installIntegrationsKnowledge) && + settings.integration_knowledge_enabled === undefined + ) { + updatedSettings.integration_knowledge_enabled = true; + } + if (Object.keys(updatedSettings).length > 0) { + await saveSettings(soClient, updatedSettings); } } catch (e) { if (e.isBoom && e.output.statusCode === 404) { @@ -184,5 +195,12 @@ export function createDefaultSettings(): BaseSettings { settings.use_space_awareness_migration_status = 'success'; } + if ( + config?.experimentalFeatures?.integrationKnowledge || + appContextService.getExperimentalFeatures().installIntegrationsKnowledge + ) { + settings.integration_knowledge_enabled = true; + } + return settings; } diff --git a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts new file mode 100644 index 0000000000000..89f2b2ef2c93b --- /dev/null +++ b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts @@ -0,0 +1,116 @@ +/* + * 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 { + ConcreteTaskInstance, + TaskManagerSetupContract, + TaskManagerStartContract, +} from '@kbn/task-manager-plugin/server'; +import { v4 as uuidv4 } from 'uuid'; + +import pMap from 'p-map'; + +import * as Registry from '../services/epm/registry'; +import { getInstallations } from '../services/epm/packages'; +import { appContextService, licenseService } from '../services'; +import { MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } from '../constants'; +import { indexKnowledgeBase } from '../services/epm/packages/install_state_machine/steps'; + +const TASK_TYPE = 'fleet:reindex_integration_knowledge'; + +export function registerReindexIntegrationKnowledgeTask( + taskManagerSetup: TaskManagerSetupContract +) { + taskManagerSetup.registerTaskDefinitions({ + [TASK_TYPE]: { + title: 'Fleet Reindex integration knowledge', + timeout: '5m', + maxAttempts: 3, + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { + let cancelled = false; + const isCancelled = () => cancelled; + return { + async run() { + if (isCancelled()) { + throw new Error('Task has been cancelled'); + } + + // Check if user has appropriate license for knowledge base functionality + if (!licenseService.isEnterprise()) { + appContextService + .getLogger() + .debug(`Skipping knowledge base reindexing - requires Enterprise license`); + return; + } + + await reindexIntegrationKnowledgeForInstalledPackages(); + }, + async cancel() { + cancelled = true; + }, + }; + }, + }, + }); +} + +export async function scheduleReindexIntegrationKnowledgeTask( + taskManagerStart: TaskManagerStartContract +) { + appContextService + .getLogger() + .info('Scheduling task to reindex integration knowledge for installed packages'); + await taskManagerStart.ensureScheduled({ + id: `${TASK_TYPE}:${uuidv4()}`, + scope: ['fleet'], + params: {}, + taskType: TASK_TYPE, + runAt: new Date(), + state: {}, + }); +} + +async function reindexIntegrationKnowledgeForInstalledPackages() { + const soClient = appContextService.getInternalUserSOClientWithoutSpaceExtension(); + const esClient = appContextService.getInternalUserESClient(); + const logger = appContextService.getLogger(); + const installedPackages = await getInstallations(soClient); + await pMap( + installedPackages.saved_objects, + async ({ attributes: installation }) => { + // TODO archiveIterator is different if `install_source !== 'registry'` + const { archiveIterator } = await Registry.getPackage( + installation.name, + installation.version, + { useStreaming: true } + ); + await indexKnowledgeBase( + installation.installed_es, + soClient, + esClient, + logger, + { name: installation.name, version: installation.version }, + archiveIterator + ).catch((error) => { + logger.error( + `Failed reindexing knowledge base for package ${installation.name}@${installation.version}: ${error}` + ); + }); + + // await reinstallPackageForInstallation({ + // soClient, + // esClient, + // installation, + // }).catch((err) => { + // logger.error( + // `Package needs to be manually reinstalled ${installation.name} after enabling integration knowledge: ${err.message}` + // ); + // }); + }, + { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } + ); +} diff --git a/x-pack/platform/plugins/shared/fleet/server/types/rest_spec/settings.ts b/x-pack/platform/plugins/shared/fleet/server/types/rest_spec/settings.ts index dbc4b4efcdeb7..3213cd0308675 100644 --- a/x-pack/platform/plugins/shared/fleet/server/types/rest_spec/settings.ts +++ b/x-pack/platform/plugins/shared/fleet/server/types/rest_spec/settings.ts @@ -59,6 +59,7 @@ export const PutSettingsRequestSchema = { is_preconfigured: schema.boolean(), }) ), + integration_knowledge_enabled: schema.maybe(schema.boolean()), }), }; @@ -101,8 +102,12 @@ export const SettingsSchemaV5 = schema.object({ ), }); +export const SettingsSchemaV6 = SettingsSchemaV5.extends({ + integration_knowledge_enabled: schema.maybe(schema.boolean()), +}); + export const SettingsResponseSchema = schema.object({ - item: SettingsSchemaV5, + item: SettingsSchemaV6, }); export const PutSpaceSettingsRequestSchema = { diff --git a/x-pack/platform/plugins/shared/fleet/server/types/so_attributes.ts b/x-pack/platform/plugins/shared/fleet/server/types/so_attributes.ts index 07547ee94d191..9bf9a4cc33ec3 100644 --- a/x-pack/platform/plugins/shared/fleet/server/types/so_attributes.ts +++ b/x-pack/platform/plugins/shared/fleet/server/types/so_attributes.ts @@ -274,6 +274,7 @@ export interface SettingsSOAttributes { metrics?: 'success' | null; synthetics?: 'success' | null; }; + integration_knowledge_enabled?: boolean; } export interface SpaceSettingsSOAttributes { From ff611805b25c3804028dd0c9fb15b13efa0528af Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:47:13 +0000 Subject: [PATCH 02/10] Changes from node scripts/capture_oas_snapshot --include-path /api/status --include-path /api/alerting/rule/ --include-path /api/alerting/rules --include-path /api/actions --include-path /api/security/role --include-path /api/spaces --include-path /api/streams --include-path /api/fleet --include-path /api/saved_objects/_import --include-path /api/saved_objects/_export --include-path /api/maintenance_window --include-path /api/agent_builder --update --- oas_docs/bundle.json | 9 +++++++++ oas_docs/bundle.serverless.json | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index b5c213e422f2f..b659d37148cdd 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -48863,6 +48863,9 @@ }, "type": "object" }, + "integration_knowledge_enabled": { + "type": "boolean" + }, "output_secret_storage_requirements_met": { "type": "boolean" }, @@ -49010,6 +49013,9 @@ "deprecated": true, "type": "boolean" }, + "integration_knowledge_enabled": { + "type": "boolean" + }, "kibana_ca_sha256": { "deprecated": true, "type": "string" @@ -49093,6 +49099,9 @@ }, "type": "object" }, + "integration_knowledge_enabled": { + "type": "boolean" + }, "output_secret_storage_requirements_met": { "type": "boolean" }, diff --git a/oas_docs/bundle.serverless.json b/oas_docs/bundle.serverless.json index dff8c4e331b43..a2df4c7db1e62 100644 --- a/oas_docs/bundle.serverless.json +++ b/oas_docs/bundle.serverless.json @@ -48351,6 +48351,9 @@ }, "type": "object" }, + "integration_knowledge_enabled": { + "type": "boolean" + }, "output_secret_storage_requirements_met": { "type": "boolean" }, @@ -48498,6 +48501,9 @@ "deprecated": true, "type": "boolean" }, + "integration_knowledge_enabled": { + "type": "boolean" + }, "kibana_ca_sha256": { "deprecated": true, "type": "string" @@ -48581,6 +48587,9 @@ }, "type": "object" }, + "integration_knowledge_enabled": { + "type": "boolean" + }, "output_secret_storage_requirements_met": { "type": "boolean" }, From 1fc7ff2563f32035f2fce940bdd0019abd957859 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:49:30 +0000 Subject: [PATCH 03/10] Changes from node scripts/check_mappings_update --fix --- packages/kbn-check-saved-objects-cli/current_fields.json | 1 + packages/kbn-check-saved-objects-cli/current_mappings.json | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/kbn-check-saved-objects-cli/current_fields.json b/packages/kbn-check-saved-objects-cli/current_fields.json index fd34bc7369f72..19c9a06ad72f9 100644 --- a/packages/kbn-check-saved-objects-cli/current_fields.json +++ b/packages/kbn-check-saved-objects-cli/current_fields.json @@ -805,6 +805,7 @@ "fleet_server_hosts", "has_seen_add_data_notice", "ilm_migration_status", + "integration_knowledge_enabled", "output_secret_storage_requirements_met", "prerelease_integrations_enabled", "secret_storage_requirements_met", diff --git a/packages/kbn-check-saved-objects-cli/current_mappings.json b/packages/kbn-check-saved-objects-cli/current_mappings.json index 4501675a5745b..b48d426da5f04 100644 --- a/packages/kbn-check-saved-objects-cli/current_mappings.json +++ b/packages/kbn-check-saved-objects-cli/current_mappings.json @@ -2660,6 +2660,9 @@ "dynamic": false, "properties": {} }, + "integration_knowledge_enabled": { + "type": "boolean" + }, "output_secret_storage_requirements_met": { "type": "boolean" }, From 5501cdb0c7c3aa8019dcfb8ba52e93aab22dba99 Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 3 Dec 2025 14:12:48 +0100 Subject: [PATCH 04/10] skip reindex for packages not installed from registry --- .../get_integration_knowledge_setting.ts | 7 ------- .../steps/step_save_knowledge_base.ts | 4 +++- .../tasks/reindex_integration_knowledge_task.ts | 17 ++++++----------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts index ec176de641b47..f4cc58711dea3 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/get_integration_knowledge_setting.ts @@ -22,13 +22,6 @@ export async function getIntegrationKnowledgeSetting( const { integration_knowledge_enabled: integrationKnowledgeEnabled } = await getSettings( savedObjectsClient ); - appContextService - .getLogger() - .debug( - `getIntegrationKnowledgeSetting returns ${ - integrationKnowledgeEnabled ?? integrationKnowledgeConfig - }` - ); return integrationKnowledgeEnabled ?? integrationKnowledgeConfig; } catch (err) { appContextService diff --git a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts index 23bd7e56f28c2..9f63b1da80091 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.ts @@ -134,7 +134,9 @@ export async function indexKnowledgeBase( packageInfo.version ); - logger.debug(`Knowledge base step: Found ${knowledgeBaseItems.length} items to process`); + logger.debug( + `Knowledge base step: Found ${knowledgeBaseItems.length} items to process for package ${packageInfo.name}@${packageInfo.version}` + ); // Save knowledge base content if present if (knowledgeBaseItems && knowledgeBaseItems.length > 0) { diff --git a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts index 89f2b2ef2c93b..7440bfc6ebb84 100644 --- a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts +++ b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts @@ -82,7 +82,12 @@ async function reindexIntegrationKnowledgeForInstalledPackages() { await pMap( installedPackages.saved_objects, async ({ attributes: installation }) => { - // TODO archiveIterator is different if `install_source !== 'registry'` + if (installation.install_source !== 'registry') { + logger.debug( + `Skipping reindexing knowledge base for package ${installation.name}@${installation.version} - install source ${installation.install_source}` + ); + return; + } const { archiveIterator } = await Registry.getPackage( installation.name, installation.version, @@ -100,16 +105,6 @@ async function reindexIntegrationKnowledgeForInstalledPackages() { `Failed reindexing knowledge base for package ${installation.name}@${installation.version}: ${error}` ); }); - - // await reinstallPackageForInstallation({ - // soClient, - // esClient, - // installation, - // }).catch((err) => { - // logger.error( - // `Package needs to be manually reinstalled ${installation.name} after enabling integration knowledge: ${err.message}` - // ); - // }); }, { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } ); From f8d63b6ad2c3edacc7875d76a7447e634f99066c Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:16:40 +0000 Subject: [PATCH 05/10] Changes from make api-docs --- oas_docs/output/kibana.serverless.yaml | 6 ++++++ oas_docs/output/kibana.yaml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index f957e6c600f37..a01b8e34dd81e 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -47461,6 +47461,8 @@ paths: - success nullable: true type: string + integration_knowledge_enabled: + type: boolean output_secret_storage_requirements_met: type: boolean preconfigured_fields: @@ -47568,6 +47570,8 @@ paths: has_seen_add_data_notice: deprecated: true type: boolean + integration_knowledge_enabled: + type: boolean kibana_ca_sha256: deprecated: true type: string @@ -47627,6 +47631,8 @@ paths: - success nullable: true type: string + integration_knowledge_enabled: + type: boolean output_secret_storage_requirements_met: type: boolean preconfigured_fields: diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index a21f50b0f732b..7a69699a14db3 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -50397,6 +50397,8 @@ paths: - success nullable: true type: string + integration_knowledge_enabled: + type: boolean output_secret_storage_requirements_met: type: boolean preconfigured_fields: @@ -50504,6 +50506,8 @@ paths: has_seen_add_data_notice: deprecated: true type: boolean + integration_knowledge_enabled: + type: boolean kibana_ca_sha256: deprecated: true type: string @@ -50563,6 +50567,8 @@ paths: - success nullable: true type: string + integration_knowledge_enabled: + type: boolean output_secret_storage_requirements_met: type: boolean preconfigured_fields: From 746029b5ef84cbdad39da1a76b6ab20cfe763489 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:20:04 +0000 Subject: [PATCH 06/10] Changes from node scripts/jest_integration -u src/core/server/integration_tests/ci_checks --- .../saved_objects/check_registered_types.test.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index 12e72d4178673..aadc7b7529e6c 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -133,7 +133,7 @@ describe('checking migration metadata changes on all registered SO types', () => "ingest-download-sources": "c87e062ef293585e85fccec0c865d7cef48e0ff9a919d7781d5f7627d275484b", "ingest-outputs": "4f3451469b080548fd0f2ca414a81d91bd0d5690c34378376433ab1ae960ce5c", "ingest-package-policies": "9b9a83b94a99e0574a69999310b00917ddd5bfd44a6079badf54026029fed597", - "ingest_manager_settings": "87d90ad9493e5b254e769c283344ec707673a5ca804511e94bc47dc344b0c6a0", + "ingest_manager_settings": "e0d8058819a92cc8a8d02f5ffb1976924b4c6459f0d037f0fbbc57874bb9116f", "intercept_interaction_record": "c0220185d080f25abd14c4c29f72b2e5270f3ce55a775c8c7ac9177e0f2c810d", "intercept_trigger_record": "e10a20733bbaaae951478e45c9f2cc70677299060222edd5a6f5db29591c5f96", "inventory-view": "f66434444d3576f801f112fc3584634054af081bbf6e78eb84a41462c62e53ba", @@ -827,8 +827,9 @@ describe('checking migration metadata changes on all registered SO types', () => "ingest-package-policies|warning: The SO type owner should ensure these transform functions DO NOT mutate after they are defined.", "================================================================================================================================", "ingest_manager_settings|global: aa0735c39adb396365f28cf118204854b9d5d71e", - "ingest_manager_settings|mappings: 7f317a49162e1722d6cc6fd2abebc47f88dae570", + "ingest_manager_settings|mappings: 81be5ffecd8fcea3cdd16d0398668130c3f69d9c", "ingest_manager_settings|schemas: da39a3ee5e6b4b0d3255bfef95601890afd80709", + "ingest_manager_settings|10.6.0: dffd1419f856a6dd84d56654aabfb5d7f295e31476d8bbc618b09353425331ed", "ingest_manager_settings|10.5.0: cf8c901d4394ae835fb669c4512a89a633b3d3267648b0b1afb3bc0deb7613bd", "ingest_manager_settings|10.4.0: 764f19710e944dab032c05a10694aaf8b202d61786f6910898edf5c1e21b92f9", "ingest_manager_settings|10.3.0: 02303d6a3a088d69a827b216a78f2497dab34aef786649d105d9e49607b4931a", @@ -1328,7 +1329,7 @@ describe('checking migration metadata changes on all registered SO types', () => "ingest-download-sources": "10.1.0", "ingest-outputs": "10.8.0", "ingest-package-policies": "10.21.0", - "ingest_manager_settings": "10.5.0", + "ingest_manager_settings": "10.6.0", "intercept_interaction_record": "10.1.0", "intercept_trigger_record": "10.1.0", "inventory-view": "10.2.0", @@ -1476,7 +1477,7 @@ describe('checking migration metadata changes on all registered SO types', () => "ingest-download-sources": "10.1.0", "ingest-outputs": "10.8.0", "ingest-package-policies": "10.21.0", - "ingest_manager_settings": "10.5.0", + "ingest_manager_settings": "10.6.0", "intercept_interaction_record": "10.1.0", "intercept_trigger_record": "10.1.0", "inventory-view": "10.2.0", From 0c3da93dba034f8de2e509df681f4925cfe1baa9 Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 3 Dec 2025 14:56:00 +0100 Subject: [PATCH 07/10] reinstall package for bundled packages and skip for non-registry packages --- .../tasks/reindex_integration_knowledge_task.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts index 7440bfc6ebb84..4188eec6d4755 100644 --- a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts +++ b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts @@ -15,7 +15,7 @@ import { v4 as uuidv4 } from 'uuid'; import pMap from 'p-map'; import * as Registry from '../services/epm/registry'; -import { getInstallations } from '../services/epm/packages'; +import { getInstallations, reinstallPackageForInstallation } from '../services/epm/packages'; import { appContextService, licenseService } from '../services'; import { MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } from '../constants'; import { indexKnowledgeBase } from '../services/epm/packages/install_state_machine/steps'; @@ -82,6 +82,19 @@ async function reindexIntegrationKnowledgeForInstalledPackages() { await pMap( installedPackages.saved_objects, async ({ attributes: installation }) => { + if (installation.install_source === 'bundled') { + await reinstallPackageForInstallation({ + soClient, + esClient, + installation, + }).catch((err) => { + logger.error( + `Package needs to be manually reinstalled ${installation.name} after enabling integration knowledge: ${err.message}` + ); + }); + return; + } + if (installation.install_source !== 'registry') { logger.debug( `Skipping reindexing knowledge base for package ${installation.name}@${installation.version} - install source ${installation.install_source}` From 7b5673539b10f1b1f9b231c9d3066da795c01362 Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 3 Dec 2025 15:14:58 +0100 Subject: [PATCH 08/10] handle bundled packages --- .../integration_knowledge_flyout.tsx | 5 +++ .../server/services/epm/packages/install.ts | 2 +- .../reindex_integration_knowledge_task.ts | 44 +++++++++++-------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx b/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx index bda0999a3bcf5..eed8e69d962b1 100644 --- a/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx +++ b/x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/installed_integrations/components/integration_knowledge_flyout.tsx @@ -62,6 +62,11 @@ export const IntegrationKnowledgeFlyout: React.FunctionComponent<{ if (res.error) { throw res.error; } + notifications.toasts.addSuccess({ + title: i18n.translate('xpack.fleet.integrationKnowledgeFlyout.successUpdatingSettings', { + defaultMessage: 'Integration knowledge setting updated successfully', + }), + }); } catch (error) { setIntegrationKnowledgeSetting(!integrationKnowledgeEnabled); notifications.toasts.addError(error, { diff --git a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install.ts b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install.ts index 756e79deb2d51..13d4a577836e6 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install.ts @@ -107,7 +107,7 @@ const MAX_ENSURE_INSTALL_TIME = 60 * 1000; const MAX_INSTALL_RETRIES = 5; const BASE_RETRY_DELAY_MS = 1000; // 1s -const PACKAGES_TO_INSTALL_WITH_STREAMING = [ +export const PACKAGES_TO_INSTALL_WITH_STREAMING = [ // The security_detection_engine package contains a large number of assets and // is not suitable for regular installation as it might cause OOM errors. 'security_detection_engine', diff --git a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts index 4188eec6d4755..9c24adb047971 100644 --- a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts +++ b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts @@ -15,10 +15,13 @@ import { v4 as uuidv4 } from 'uuid'; import pMap from 'p-map'; import * as Registry from '../services/epm/registry'; -import { getInstallations, reinstallPackageForInstallation } from '../services/epm/packages'; +import { getInstallations } from '../services/epm/packages'; import { appContextService, licenseService } from '../services'; import { MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } from '../constants'; import { indexKnowledgeBase } from '../services/epm/packages/install_state_machine/steps'; +import { unpackBufferToAssetsMap } from '../services/epm/archive'; +import { getBundledPackageForInstallation } from '../services/epm/packages/bundled_packages'; +import { PACKAGES_TO_INSTALL_WITH_STREAMING } from '../services/epm/packages/install'; const TASK_TYPE = 'fleet:reindex_integration_knowledge'; @@ -82,37 +85,40 @@ async function reindexIntegrationKnowledgeForInstalledPackages() { await pMap( installedPackages.saved_objects, async ({ attributes: installation }) => { + let archiveIterator; if (installation.install_source === 'bundled') { - await reinstallPackageForInstallation({ - soClient, - esClient, - installation, - }).catch((err) => { - logger.error( - `Package needs to be manually reinstalled ${installation.name} after enabling integration knowledge: ${err.message}` + const matchingBundledPackage = await getBundledPackageForInstallation(installation); + if (!matchingBundledPackage) { + logger.debug( + `Skipping reindexing knowledge base for package ${installation.name}@${installation.version} - bundled package not found` ); - }); - return; - } - - if (installation.install_source !== 'registry') { + return; + } + const useStreaming = PACKAGES_TO_INSTALL_WITH_STREAMING.includes(installation.name); + const archiveBuffer = await matchingBundledPackage.getBuffer(); + ({ archiveIterator } = await unpackBufferToAssetsMap({ + archiveBuffer, + contentType: 'application/zip', + useStreaming, + })); + } else if (installation.install_source !== 'registry') { logger.debug( `Skipping reindexing knowledge base for package ${installation.name}@${installation.version} - install source ${installation.install_source}` ); return; } - const { archiveIterator } = await Registry.getPackage( - installation.name, - installation.version, - { useStreaming: true } - ); + if (installation.install_source === 'registry') { + ({ archiveIterator } = await Registry.getPackage(installation.name, installation.version, { + useStreaming: true, + })); + } await indexKnowledgeBase( installation.installed_es, soClient, esClient, logger, { name: installation.name, version: installation.version }, - archiveIterator + archiveIterator! ).catch((error) => { logger.error( `Failed reindexing knowledge base for package ${installation.name}@${installation.version}: ${error}` From 530c600514d1d0e324c75eff14a626c98270c9db Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 3 Dec 2025 16:31:07 +0100 Subject: [PATCH 09/10] skip reindex if knowledge base exists on installed version --- .../tasks/reindex_integration_knowledge_task.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts index 9c24adb047971..0b697633239b0 100644 --- a/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts +++ b/x-pack/platform/plugins/shared/fleet/server/tasks/reindex_integration_knowledge_task.ts @@ -15,7 +15,7 @@ import { v4 as uuidv4 } from 'uuid'; import pMap from 'p-map'; import * as Registry from '../services/epm/registry'; -import { getInstallations } from '../services/epm/packages'; +import { getInstallations, getPackageKnowledgeBase } from '../services/epm/packages'; import { appContextService, licenseService } from '../services'; import { MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } from '../constants'; import { indexKnowledgeBase } from '../services/epm/packages/install_state_machine/steps'; @@ -85,6 +85,17 @@ async function reindexIntegrationKnowledgeForInstalledPackages() { await pMap( installedPackages.saved_objects, async ({ attributes: installation }) => { + const knowledgeBase = await getPackageKnowledgeBase({ esClient, pkgName: installation.name }); + const knowledgeBaseHasCurrentPackageVersion = knowledgeBase?.items.some( + (item) => item.version === installation.version + ); + if (knowledgeBaseHasCurrentPackageVersion) { + logger.debug( + `Skipping reindexing knowledge base for package ${installation.name}@${installation.version} - already indexed` + ); + return; + } + let archiveIterator; if (installation.install_source === 'bundled') { const matchingBundledPackage = await getBundledPackageForInstallation(installation); From a3011e7bef06bbee3854c3ebe7b3a42002712bf5 Mon Sep 17 00:00:00 2001 From: Julia Bardi Date: Wed, 3 Dec 2025 16:59:46 +0100 Subject: [PATCH 10/10] fix tests --- .../steps/step_save_knowledge_base.test.ts | 25 +++++-------------- .../apis/epm/install_remove_assets.ts | 4 +++ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.test.ts b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.test.ts index a9ad14f594a32..7b28fe8305c93 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.test.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/epm/packages/install_state_machine/steps/step_save_knowledge_base.test.ts @@ -13,6 +13,7 @@ import { saveKnowledgeBaseContentToIndex } from '../../knowledge_base_index'; import type { InstallContext } from '../_state_machine_package_install'; import { stepSaveKnowledgeBase, cleanupKnowledgeBaseStep } from './step_save_knowledge_base'; +import { getIntegrationKnowledgeSetting } from '../../get_integration_knowledge_setting'; // Mock the app context service jest.mock('../../../../app_context', () => ({ @@ -23,9 +24,6 @@ jest.mock('../../../../app_context', () => ({ info: jest.fn(), debug: jest.fn(), }), - getExperimentalFeatures: jest.fn().mockReturnValue({ - installIntegrationsKnowledge: true, - }), }, })); @@ -49,6 +47,10 @@ jest.mock('../../../../license', () => ({ }, })); +jest.mock('../../get_integration_knowledge_setting', () => ({ + getIntegrationKnowledgeSetting: jest.fn().mockResolvedValue(true), +})); + let esClient: jest.Mocked; let savedObjectsClient: jest.Mocked; @@ -698,11 +700,7 @@ describe('stepSaveKnowledgeBase', () => { }); it('should skip knowledge base processing when installIntegrationsKnowledge feature flag is disabled', async () => { - // Mock app context service to return experimental features with flag disabled - const { appContextService } = jest.requireMock('../../../../app_context'); - appContextService.getExperimentalFeatures.mockReturnValue({ - installIntegrationsKnowledge: false, - }); + (getIntegrationKnowledgeSetting as jest.Mock).mockResolvedValueOnce(false); const entries: ArchiveEntry[] = [ { @@ -722,20 +720,9 @@ describe('stepSaveKnowledgeBase', () => { // Verify that updateEsAssetReferences was NOT called const { updateEsAssetReferences } = jest.requireMock('../../es_assets_reference'); expect(updateEsAssetReferences).not.toHaveBeenCalled(); - - // Reset the mock back to enabled for other tests - appContextService.getExperimentalFeatures.mockReturnValue({ - installIntegrationsKnowledge: true, - }); }); it('should process knowledge base when installIntegrationsKnowledge feature flag is enabled', async () => { - // Ensure app context service returns experimental features with flag enabled - const { appContextService } = jest.requireMock('../../../../app_context'); - appContextService.getExperimentalFeatures.mockReturnValue({ - installIntegrationsKnowledge: true, - }); - const entries: ArchiveEntry[] = [ { path: 'test-package-1.0.0/docs/knowledge_base/guide.md', diff --git a/x-pack/platform/test/fleet_api_integration/apis/epm/install_remove_assets.ts b/x-pack/platform/test/fleet_api_integration/apis/epm/install_remove_assets.ts index dd9a9b7c79f0e..338c420a2a1a1 100644 --- a/x-pack/platform/test/fleet_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/platform/test/fleet_api_integration/apis/epm/install_remove_assets.ts @@ -739,6 +739,10 @@ const expectAssetsInstalled = ({ id: 'metrics-all_assets.test_metrics-0.1.0', type: 'ingest_pipeline', }, + { + id: 'all_assets-README.md', + type: 'knowledge_base', + }, { id: 'default', type: 'ml_model',