From 7589c753a5f5fdf2220908d1244fa191ba6bf93f Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Mon, 16 Dec 2024 15:57:34 +0100 Subject: [PATCH 1/7] [Rules migration] Add Integrations column (#11387) --- .../common/siem_migrations/constants.ts | 2 + .../model/api/rules/rule_migration.gen.ts | 19 ++++ .../api/rules/rule_migration.schema.yaml | 27 ++++++ .../public/siem_migrations/rules/api/index.ts | 19 ++++ .../rules/components/rules_table/index.tsx | 44 +++++++-- .../components/rules_table_columns/author.tsx | 1 + .../rules_table_columns/integrations.tsx | 37 +++++++ .../rules_table_columns/translations.ts | 7 ++ .../rules_table_columns/updated.tsx | 2 +- .../use_migration_rule_preview_flyout.tsx | 51 +++++----- .../use_migration_rules_table_columns.tsx | 9 +- .../service/hooks/use_get_integrations.ts | 48 +++++++++ .../rules/service/rule_migrations_service.ts | 8 ++ .../rules/api/get_integrations.ts | 97 +++++++++++++++++++ .../rules/api/get_prebuilt_rules.ts | 19 +--- .../lib/siem_migrations/rules/api/index.ts | 2 + .../rules/api/util/installation.ts | 8 +- .../rules/api/util/prebuilt_rules.ts | 41 +++++++- .../rules/data/rule_migrations_data_client.ts | 7 +- ...ule_migrations_data_integrations_client.ts | 18 ++++ .../data/rule_migrations_data_rules_client.ts | 6 +- .../data/rule_migrations_data_service.ts | 7 +- .../lib/siem_migrations/rules/data/search.ts | 8 ++ .../lib/siem_migrations/rules/data/sort.ts | 18 +++- .../rules/siem_rule_migrations_service.ts | 10 +- .../siem_migrations_service.ts | 8 +- .../security_solution/server/plugin.ts | 2 + 27 files changed, 462 insertions(+), 63 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts create mode 100644 x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts index 88ed777c21d69..e94fc28041ab2 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts @@ -25,6 +25,8 @@ export const SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH = `${SIEM_RULE_MIGRATION_PATH}/install_translated` as const; export const SIEM_RULE_MIGRATIONS_PREBUILT_RULES_PATH = `${SIEM_RULE_MIGRATION_PATH}/prebuilt_rules` as const; +export const SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH = + `${SIEM_RULE_MIGRATION_PATH}/integrations` as const; export const SIEM_RULE_MIGRATION_RESOURCES_PATH = `${SIEM_RULE_MIGRATION_PATH}/resources` as const; export const SIEM_RULE_MIGRATION_RESOURCES_MISSING_PATH = diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts index 47c06e1e02c7a..f00f5cf17cd44 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts @@ -30,6 +30,7 @@ import { } from '../../rule_migration.gen'; import { NonEmptyString } from '../../../../api/model/primitives.gen'; import { ConnectorId, LangSmithOptions } from '../../common.gen'; +import { RelatedIntegration } from '../../../../api/detection_engine/model/rule_schema/common_attributes.gen'; export type CreateRuleMigrationRequestParams = z.infer; export const CreateRuleMigrationRequestParams = z.object({ @@ -79,6 +80,24 @@ export const GetRuleMigrationResponse = z.object({ data: z.array(RuleMigration), }); +export type GetRuleMigrationIntegrationsRequestParams = z.infer< + typeof GetRuleMigrationIntegrationsRequestParams +>; +export const GetRuleMigrationIntegrationsRequestParams = z.object({ + migration_id: NonEmptyString, +}); +export type GetRuleMigrationIntegrationsRequestParamsInput = z.input< + typeof GetRuleMigrationIntegrationsRequestParams +>; + +/** + * The map of related integrations, with the integration id as a key + */ +export type GetRuleMigrationIntegrationsResponse = z.infer< + typeof GetRuleMigrationIntegrationsResponse +>; +export const GetRuleMigrationIntegrationsResponse = z.object({}).catchall(RelatedIntegration); + export type GetRuleMigrationPrebuiltRulesRequestParams = z.infer< typeof GetRuleMigrationPrebuiltRulesRequestParams >; diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml index 69e43b57dabd3..f1af3290c76e1 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml @@ -396,6 +396,33 @@ paths: additionalProperties: $ref: '../../rule_migration.schema.yaml#/components/schemas/PrebuiltRuleVersion' + /internal/siem_migrations/rules/{migration_id}/integrations: + get: + summary: Retrieves all related integrations for a specific migration + operationId: GetRuleMigrationIntegrations + x-codegen-enabled: true + x-internal: true + description: Retrieves all related integrations + tags: + - SIEM Rule Migrations + parameters: + - name: migration_id + in: path + required: true + schema: + description: The migration id to retrieve related integrations for + $ref: '../../../../../common/api/model/primitives.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Indicates that related integrations have been retrieved correctly. + content: + application/json: + schema: + type: object + description: The map of related integrations, with the integration id as a key + additionalProperties: + $ref: '../../../../../common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml#/components/schemas/RelatedIntegration' + # Rule migration resources APIs /internal/siem_migrations/rules/{migration_id}/resources: diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts index 02fb423b05279..8681244a301ec 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts @@ -23,6 +23,7 @@ import { SIEM_RULE_MIGRATION_RESOURCES_MISSING_PATH, SIEM_RULE_MIGRATION_RESOURCES_PATH, SIEM_RULE_MIGRATIONS_PREBUILT_RULES_PATH, + SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH, } from '../../../../common/siem_migrations/constants'; import type { CreateRuleMigrationRequestBody, @@ -39,6 +40,7 @@ import type { UpsertRuleMigrationResourcesResponse, GetRuleMigrationPrebuiltRulesResponse, UpdateRuleMigrationResponse, + GetRuleMigrationIntegrationsResponse, } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; export interface GetRuleMigrationStatsParams { @@ -279,6 +281,23 @@ export const getRuleMigrationsPrebuiltRules = async ({ ); }; +export interface GetRelatedIntegrationsParams { + /** `id` of the migration to get related integrations for */ + migrationId: string; + /** Optional AbortSignal for cancelling request */ + signal?: AbortSignal; +} +/** Retrieves related integrations for a specific migration. */ +export const getRelatedIntegrations = async ({ + migrationId, + signal, +}: GetRelatedIntegrationsParams): Promise => { + return KibanaServices.get().http.get( + replaceParams(SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH, { migration_id: migrationId }), + { version: '1', signal } + ); +}; + export interface UpdateRulesParams { /** The list of migration rules data to update */ rulesToUpdate: UpdateRuleMigrationData[]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx index b883934a0bdcb..f54dba5ca6b82 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx @@ -18,6 +18,7 @@ import { } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; +import type { RelatedIntegration, RuleResponse } from '../../../../../common/api/detection_engine'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; import { EmptyMigration } from './empty_migration'; @@ -33,6 +34,7 @@ import { BulkActions } from './bulk_actions'; import { SearchField } from './search_field'; import { RuleTranslationResult } from '../../../../../common/siem_migrations/constants'; import * as i18n from './translations'; +import { useGetRelatedIntegrations } from '../../service/hooks/use_get_integrations'; const DEFAULT_PAGE_SIZE = 10; const DEFAULT_SORT_FIELD = 'translation_result'; @@ -64,6 +66,9 @@ export const MigrationRulesTable: React.FC = React.mem const { data: prebuiltRules = {}, isLoading: isPrebuiltRulesLoading } = useGetMigrationPrebuiltRules(migrationId); + const { integrations, isLoading: isIntegrationsLoading } = + useGetRelatedIntegrations(migrationId); + const { data: { ruleMigrations, total } = { ruleMigrations: [], total: 0 }, isLoading: isDataLoading, @@ -180,7 +185,12 @@ export const MigrationRulesTable: React.FC = React.mem [addError, installTranslatedMigrationRules] ); - const isLoading = isStatsLoading || isPrebuiltRulesLoading || isDataLoading || isTableLoading; + const isLoading = + isStatsLoading || + isPrebuiltRulesLoading || + isIntegrationsLoading || + isDataLoading || + isTableLoading; const ruleActionsFactory = useCallback( (ruleMigration: RuleMigration, closeRulePreview: () => void) => { @@ -221,13 +231,33 @@ export const MigrationRulesTable: React.FC = React.mem [installSingleRule, isLoading] ); - const getMigrationRule = useCallback( + const getMigrationRuleData = useCallback( (ruleId: string) => { - if (!isLoading && ruleMigrations.length) { - return ruleMigrations.find((item) => item.id === ruleId); + if (!isLoading && ruleMigrations.length && integrations) { + const ruleMigration = ruleMigrations.find((item) => item.id === ruleId); + let matchedPrebuiltRule: RuleResponse | undefined; + const relatedIntegrations: RelatedIntegration[] = []; + if (ruleMigration) { + // Find matched prebuilt rule if any and prioritize its installed version + const matchedPrebuiltRuleVersion = ruleMigration.elastic_rule?.prebuilt_rule_id + ? prebuiltRules[ruleMigration.elastic_rule.prebuilt_rule_id] + : undefined; + matchedPrebuiltRule = + matchedPrebuiltRuleVersion?.current ?? matchedPrebuiltRuleVersion?.target; + + if (matchedPrebuiltRule?.related_integrations) { + relatedIntegrations.push(...matchedPrebuiltRule.related_integrations); + } else if (ruleMigration.elastic_rule?.integration_id) { + const integration = integrations[ruleMigration.elastic_rule.integration_id]; + if (integration) { + relatedIntegrations.push(integration); + } + } + } + return { ruleMigration, matchedPrebuiltRule, relatedIntegrations }; } }, - [isLoading, ruleMigrations] + [integrations, isLoading, prebuiltRules, ruleMigrations] ); const { @@ -235,8 +265,7 @@ export const MigrationRulesTable: React.FC = React.mem openMigrationRuleDetails: openRulePreview, } = useMigrationRuleDetailsFlyout({ isLoading, - prebuiltRules, - getMigrationRule, + getMigrationRuleData, ruleActionsFactory, }); @@ -244,6 +273,7 @@ export const MigrationRulesTable: React.FC = React.mem disableActions: isTableLoading, openMigrationRuleDetails: openRulePreview, installMigrationRule: installSingleRule, + getMigrationRuleData, }); return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/author.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/author.tsx index 23980f5612f89..cd762db00e2c7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/author.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/author.tsx @@ -34,6 +34,7 @@ export const createAuthorColumn = (): TableColumn => { return ; }, sortable: true, + truncateText: true, width: '10%', }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx new file mode 100644 index 0000000000000..ae7a282683dae --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx @@ -0,0 +1,37 @@ +/* + * 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 from 'react'; +import type { RelatedIntegration } from '../../../../../common/api/detection_engine'; +import { IntegrationsPopover } from '../../../../detections/components/rules/related_integrations/integrations_popover'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import * as i18n from './translations'; +import type { TableColumn } from './constants'; + +export const createIntegrationsColumn = ({ + getMigrationRuleData, +}: { + getMigrationRuleData: ( + ruleId: string + ) => { relatedIntegrations?: RelatedIntegration[] } | undefined; +}): TableColumn => { + return { + field: 'elastic_rule.integration_id', + name: i18n.COLUMN_INTEGRATIONS, + render: (_, rule: RuleMigration) => { + const migrationRuleData = getMigrationRuleData(rule.id); + const relatedIntegrations = migrationRuleData?.relatedIntegrations; + if (relatedIntegrations == null || relatedIntegrations.length === 0) { + return null; + } + return ; + }, + truncateText: true, + width: '143px', + align: 'center', + }; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/translations.ts index 64e459a609143..5b4fd6d6a477e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/translations.ts @@ -97,3 +97,10 @@ export const COLUMN_UPDATED = i18n.translate( defaultMessage: 'Updated', } ); + +export const COLUMN_INTEGRATIONS = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.integrationsLabel', + { + defaultMessage: 'Integrations', + } +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/updated.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/updated.tsx index cec9f86eb7bde..aaf4e75ac4917 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/updated.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/updated.tsx @@ -19,7 +19,7 @@ export const createUpdatedColumn = (): TableColumn => { ), sortable: true, - truncateText: false, + truncateText: true, align: 'center', width: '10%', }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rule_preview_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rule_preview_flyout.tsx index 4efaa4aba7181..9dad5a30ab073 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rule_preview_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rule_preview_flyout.tsx @@ -8,16 +8,18 @@ import type { ReactNode } from 'react'; import React, { useCallback, useState, useMemo } from 'react'; import type { EuiTabbedContentTab } from '@elastic/eui'; -import type { - PrebuiltRuleVersion, - RuleMigration, -} from '../../../../common/siem_migrations/model/rule_migration.gen'; +import type { RuleResponse } from '../../../../common/api/detection_engine'; +import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; import { MigrationRuleDetailsFlyout } from '../components/rule_details_flyout'; interface UseMigrationRuleDetailsFlyoutParams { isLoading?: boolean; - prebuiltRules: Record; - getMigrationRule: (ruleId: string) => RuleMigration | undefined; + getMigrationRuleData: (ruleId: string) => + | { + ruleMigration?: RuleMigration; + matchedPrebuiltRule?: RuleResponse; + } + | undefined; ruleActionsFactory: (ruleMigration: RuleMigration, closeRulePreview: () => void) => ReactNode; extraTabsFactory?: (ruleMigration: RuleMigration) => EuiTabbedContentTab[]; } @@ -30,27 +32,17 @@ interface UseMigrationRuleDetailsFlyoutResult { export function useMigrationRuleDetailsFlyout({ isLoading, - prebuiltRules, - getMigrationRule, + getMigrationRuleData, extraTabsFactory, ruleActionsFactory, }: UseMigrationRuleDetailsFlyoutParams): UseMigrationRuleDetailsFlyoutResult { const [migrationRuleId, setMigrationRuleId] = useState(); - const ruleMigration = useMemo(() => { + const migrationRuleData = useMemo(() => { if (migrationRuleId) { - return getMigrationRule(migrationRuleId); + return getMigrationRuleData(migrationRuleId); } - }, [getMigrationRule, migrationRuleId]); - const matchedPrebuiltRule = useMemo(() => { - if (ruleMigration) { - // Find matched prebuilt rule if any and prioritize its installed version - const matchedPrebuiltRuleVersion = ruleMigration.elastic_rule?.prebuilt_rule_id - ? prebuiltRules[ruleMigration.elastic_rule.prebuilt_rule_id] - : undefined; - return matchedPrebuiltRuleVersion?.current ?? matchedPrebuiltRuleVersion?.target; - } - }, [prebuiltRules, ruleMigration]); + }, [getMigrationRuleData, migrationRuleId]); const openMigrationRuleDetails = useCallback((rule: RuleMigration) => { setMigrationRuleId(rule.id); @@ -58,19 +50,24 @@ export function useMigrationRuleDetailsFlyout({ const closeMigrationRuleDetails = useCallback(() => setMigrationRuleId(undefined), []); const ruleActions = useMemo( - () => ruleMigration && ruleActionsFactory(ruleMigration, closeMigrationRuleDetails), - [ruleMigration, ruleActionsFactory, closeMigrationRuleDetails] + () => + migrationRuleData?.ruleMigration && + ruleActionsFactory(migrationRuleData.ruleMigration, closeMigrationRuleDetails), + [migrationRuleData?.ruleMigration, ruleActionsFactory, closeMigrationRuleDetails] ); const extraTabs = useMemo( - () => (ruleMigration && extraTabsFactory ? extraTabsFactory(ruleMigration) : []), - [ruleMigration, extraTabsFactory] + () => + migrationRuleData?.ruleMigration && extraTabsFactory + ? extraTabsFactory(migrationRuleData.ruleMigration) + : [], + [extraTabsFactory, migrationRuleData?.ruleMigration] ); return { - migrationRuleDetailsFlyout: ruleMigration && ( + migrationRuleDetailsFlyout: migrationRuleData?.ruleMigration && ( void; installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void; + getMigrationRuleData: ( + ruleId: string + ) => { relatedIntegrations?: RelatedIntegration[] } | undefined; }): TableColumn[] => { return useMemo( () => [ @@ -35,12 +41,13 @@ export const useMigrationRulesTableColumns = ({ createRiskScoreColumn(), createSeverityColumn(), createAuthorColumn(), + createIntegrationsColumn({ getMigrationRuleData }), createActionsColumn({ disableActions, openMigrationRuleDetails, installMigrationRule, }), ], - [disableActions, installMigrationRule, openMigrationRuleDetails] + [disableActions, getMigrationRuleData, installMigrationRule, openMigrationRuleDetails] ); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts new file mode 100644 index 0000000000000..081ed821ed01a --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts @@ -0,0 +1,48 @@ +/* + * 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 { useCallback, useEffect, useReducer, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import type { RelatedIntegration } from '../../../../../common/api/detection_engine'; +import { useKibana } from '../../../../common/lib/kibana/kibana_react'; +import { reducer, initialState } from './common/api_request_reducer'; + +export const GET_RELATED_INTEGRATIONS_ERROR = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.service.getRelatedIntegrationsError', + { defaultMessage: 'Failed to fetch related integrations' } +); + +export const useGetRelatedIntegrations = (migrationId: string) => { + const { siemMigrations, notifications } = useKibana().services; + const [state, dispatch] = useReducer(reducer, initialState); + const [integrations, setIntegrations] = useState< + Record | undefined + >(); + + const getRelatedIntegrations = useCallback(() => { + (async () => { + try { + dispatch({ type: 'start' }); + const results = await siemMigrations.rules.getRelatedIntegrations(migrationId); + + setIntegrations(results); + dispatch({ type: 'success' }); + } catch (err) { + setIntegrations(undefined); + const apiError = err.body ?? err; + notifications.toasts.addError(apiError, { title: GET_RELATED_INTEGRATIONS_ERROR }); + dispatch({ type: 'error', error: apiError }); + } + })(); + }, [siemMigrations.rules, migrationId, notifications.toasts]); + + useEffect(() => { + getRelatedIntegrations(); + }, [getRelatedIntegrations]); + + return { isLoading: state.loading, error: state.error, integrations }; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts index 83ead556b09cc..83c2ee69e4b86 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts @@ -12,6 +12,7 @@ import { DEFAULT_ASSISTANT_NAMESPACE, TRACE_OPTIONS_SESSION_STORAGE_KEY, } from '@kbn/elastic-assistant/impl/assistant_context/constants'; +import type { RelatedIntegration } from '../../../../common/api/detection_engine'; import type { LangSmithOptions } from '../../../../common/siem_migrations/model/common.gen'; import type { RuleMigrationResourceData, @@ -35,6 +36,7 @@ import { type GetRuleMigrationsStatsAllParams, getMissingResources, upsertMigrationResources, + getRelatedIntegrations, } from '../api'; import type { RuleMigrationStats } from '../types'; import { getSuccessToast } from './success_notification'; @@ -181,6 +183,12 @@ export class SiemRulesMigrationsService { }); } + public async getRelatedIntegrations( + migrationId: string + ): Promise> { + return getRelatedIntegrations({ migrationId }); + } + private async startTaskStatsPolling(): Promise { let pendingMigrationIds: string[] = []; do { diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts new file mode 100644 index 0000000000000..01f97e2ce8caf --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts @@ -0,0 +1,97 @@ +/* + * 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 { IKibanaResponse, Logger } from '@kbn/core/server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import type { RelatedIntegration } from '../../../../../common/api/detection_engine'; +import { + GetRuleMigrationIntegrationsRequestParams, + type GetRuleMigrationIntegrationsResponse, +} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH } from '../../../../../common/siem_migrations/constants'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; +import { withLicense } from './util/with_license'; +import { getPrebuiltRulesForMigration } from './util/prebuilt_rules'; + +export const registerSiemRuleMigrationsIntegrationsRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + router.versioned + .get({ + path: SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH, + access: 'internal', + security: { authz: { requiredPrivileges: ['securitySolution'] } }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: buildRouteValidationWithZod(GetRuleMigrationIntegrationsRequestParams), + }, + }, + }, + withLicense( + async ( + context, + req, + res + ): Promise> => { + const { migration_id: migrationId } = req.params; + try { + const ctx = await context.resolve(['core', 'alerting', 'securitySolution']); + const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient(); + const savedObjectsClient = ctx.core.savedObjects.client; + const rulesClient = await ctx.alerting.getRulesClient(); + + // Retrieve related integrations for migration rules translated into Elastic custom rules + const options = { filters: { custom: true } }; + const batches = ruleMigrationsClient.data.rules.searchBatches(migrationId, options); + + const integrationIdsSet = new Set(); + let results = await batches.next(); + while (results.length) { + results.forEach((rule) => { + if (rule.elastic_rule?.integration_id) { + integrationIdsSet.add(rule.elastic_rule.integration_id); + } + }); + results = await batches.next(); + } + + const relatedIntegrations: Record = {}; + const packages = await ruleMigrationsClient.data.integrations.getIntegrationPackages(); + packages?.forEach(({ id, version, integration }) => { + if (integrationIdsSet.has(id)) { + relatedIntegrations[id] = { package: id, version, integration }; + } + }); + + // Retrieve related integrations for migration rules matched with prebuilt rules + const prebuiltRules = await getPrebuiltRulesForMigration( + migrationId, + ruleMigrationsClient, + rulesClient, + savedObjectsClient + ); + Object.values(prebuiltRules).forEach((rule) => { + const integrations = (rule.current ?? rule.target).related_integrations; + integrations.forEach( + (integration) => (relatedIntegrations[integration.package] = integration) + ); + }); + + return res.ok({ body: relatedIntegrations }); + } catch (err) { + logger.error(err); + return res.badRequest({ body: err.message }); + } + } + ) + ); +}; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_prebuilt_rules.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_prebuilt_rules.ts index 551e4a51e477e..8165b858e2a31 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_prebuilt_rules.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_prebuilt_rules.ts @@ -12,8 +12,7 @@ import { GetRuleMigrationPrebuiltRulesRequestParams } from '../../../../../commo import { SIEM_RULE_MIGRATIONS_PREBUILT_RULES_PATH } from '../../../../../common/siem_migrations/constants'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { withLicense } from './util/with_license'; -import { getPrebuiltRules, getUniquePrebuiltRuleIds } from './util/prebuilt_rules'; -import { MAX_PREBUILT_RULES_TO_FETCH } from './constants'; +import { getPrebuiltRulesForMigration } from './util/prebuilt_rules'; export const registerSiemRuleMigrationsPrebuiltRulesRoute = ( router: SecuritySolutionPluginRouter, @@ -47,19 +46,11 @@ export const registerSiemRuleMigrationsPrebuiltRulesRoute = ( const savedObjectsClient = ctx.core.savedObjects.client; const rulesClient = await ctx.alerting.getRulesClient(); - const result = await ruleMigrationsClient.data.rules.get(migrationId, { - filters: { - prebuilt: true, - }, - from: 0, - size: MAX_PREBUILT_RULES_TO_FETCH, - }); - - const prebuiltRulesIds = getUniquePrebuiltRuleIds(result.data); - const prebuiltRules = await getPrebuiltRules( + const prebuiltRules = await getPrebuiltRulesForMigration( + migrationId, + ruleMigrationsClient, rulesClient, - savedObjectsClient, - prebuiltRulesIds + savedObjectsClient ); return res.ok({ body: prebuiltRules }); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts index 241e59ac02a27..05d2c8f1a5dc4 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts @@ -22,6 +22,7 @@ import { registerSiemRuleMigrationsInstallRoute } from './install'; import { registerSiemRuleMigrationsInstallTranslatedRoute } from './install_translated'; import { registerSiemRuleMigrationsResourceGetMissingRoute } from './resources/missing'; import { registerSiemRuleMigrationsPrebuiltRulesRoute } from './get_prebuilt_rules'; +import { registerSiemRuleMigrationsIntegrationsRoute } from './get_integrations'; export const registerSiemRuleMigrationsRoutes = ( router: SecuritySolutionPluginRouter, @@ -39,6 +40,7 @@ export const registerSiemRuleMigrationsRoutes = ( registerSiemRuleMigrationsStopRoute(router, logger); registerSiemRuleMigrationsInstallRoute(router, logger); registerSiemRuleMigrationsInstallTranslatedRoute(router, logger); + registerSiemRuleMigrationsIntegrationsRoute(router, logger); registerSiemRuleMigrationsResourceUpsertRoute(router, logger); registerSiemRuleMigrationsResourceGetRoute(router, logger); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts index de95d818dd18d..aace5ed0ab356 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts @@ -15,7 +15,7 @@ import { createPrebuiltRules } from '../../../../detection_engine/prebuilt_rules import type { IDetectionRulesClient } from '../../../../detection_engine/rule_management/logic/detection_rules_client/detection_rules_client_interface'; import type { RuleResponse } from '../../../../../../common/api/detection_engine'; import type { StoredRuleMigration } from '../../types'; -import { getPrebuiltRules, getUniquePrebuiltRuleIds } from './prebuilt_rules'; +import { getPrebuiltRulesByIds, getUniquePrebuiltRuleIds } from './prebuilt_rules'; import { MAX_CUSTOM_RULES_TO_CREATE_IN_PARALLEL, MAX_TRANSLATED_RULES_TO_INSTALL, @@ -35,7 +35,11 @@ const installPrebuiltRules = async ( ): Promise => { // Get required prebuilt rules const prebuiltRulesIds = getUniquePrebuiltRuleIds(rulesToInstall); - const prebuiltRules = await getPrebuiltRules(rulesClient, savedObjectsClient, prebuiltRulesIds); + const prebuiltRules = await getPrebuiltRulesByIds( + rulesClient, + savedObjectsClient, + prebuiltRulesIds + ); const { installed: alreadyInstalledRules, installable } = Object.values(prebuiltRules).reduce( (acc, item) => { diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts index 7760612abc878..64d7aa8bb5f56 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts @@ -13,6 +13,7 @@ import { fetchRuleVersionsTriad } from '../../../../detection_engine/prebuilt_ru import { createPrebuiltRuleAssetsClient } from '../../../../detection_engine/prebuilt_rules/logic/rule_assets/prebuilt_rule_assets_client'; import { convertPrebuiltRuleAssetToRuleResponse } from '../../../../detection_engine/rule_management/logic/detection_rules_client/converters/convert_prebuilt_rule_asset_to_rule_response'; import type { RuleMigration } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; +import type { SiemRuleMigrationsClient } from '../../siem_rule_migrations_service'; export const getUniquePrebuiltRuleIds = (migrationRules: RuleMigration[]): string[] => { const rulesIds = new Set(); @@ -43,7 +44,7 @@ export interface PrebuiltRulesResults { * @param rulesIds The list of IDs to filter requested prebuilt rules. If not specified, all available prebuilt rules will be returned. * @returns */ -export const getPrebuiltRules = async ( +export const getPrebuiltRulesByIds = async ( rulesClient: RulesClient, savedObjectsClient: SavedObjectsClientContract, rulesIds?: string[] @@ -82,3 +83,41 @@ export const getPrebuiltRules = async ( return prebuiltRules; }; + +/** + * Gets Elastic prebuilt rules + * @param migrationId The `id` of the migration to get related prebuilt rules for + * @param ruleMigrationsClient The rules migration client to migration rules data + * @param rulesClient The rules client to fetch prebuilt rules + * @param savedObjectsClient The saved objects client + * @returns + */ +export const getPrebuiltRulesForMigration = async ( + migrationId: string, + ruleMigrationsClient: SiemRuleMigrationsClient, + rulesClient: RulesClient, + savedObjectsClient: SavedObjectsClientContract +): Promise> => { + const options = { filters: { prebuilt: true } }; + const batches = ruleMigrationsClient.data.rules.searchBatches(migrationId, options); + + const rulesIds = new Set(); + let results = await batches.next(); + while (results.length) { + results.forEach((rule) => { + if (rule.elastic_rule?.prebuilt_rule_id) { + rulesIds.add(rule.elastic_rule.prebuilt_rule_id); + } + }); + results = await batches.next(); + } + const prebuiltRulesIds = Array.from(rulesIds); + + const prebuiltRules = await getPrebuiltRulesByIds( + rulesClient, + savedObjectsClient, + prebuiltRulesIds + ); + + return prebuiltRules; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_client.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_client.ts index c06c889482360..e479c42cce273 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_client.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_client.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import type { PackageService } from '@kbn/fleet-plugin/server'; import { RuleMigrationsDataIntegrationsClient } from './rule_migrations_data_integrations_client'; import { RuleMigrationsDataPrebuiltRulesClient } from './rule_migrations_data_prebuilt_rules_client'; import { RuleMigrationsDataResourcesClient } from './rule_migrations_data_resources_client'; @@ -25,7 +26,8 @@ export class RuleMigrationsDataClient { indexNameProviders: IndexNameProviders, username: string, esClient: ElasticsearchClient, - logger: Logger + logger: Logger, + packageService?: PackageService ) { this.rules = new RuleMigrationsDataRulesClient( indexNameProviders.rules, @@ -43,7 +45,8 @@ export class RuleMigrationsDataClient { indexNameProviders.integrations, username, esClient, - logger + logger, + packageService ); this.prebuiltRules = new RuleMigrationsDataPrebuiltRulesClient( indexNameProviders.prebuiltrules, diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_integrations_client.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_integrations_client.ts index fdb063836f9e4..947a206cd0c7a 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_integrations_client.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_integrations_client.ts @@ -5,11 +5,15 @@ * 2.0. */ +import type { PackageService } from '@kbn/fleet-plugin/server'; +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import type { PackageList } from '@kbn/fleet-plugin/common'; import type { Integration } from '../types'; import { RuleMigrationsDataBaseClient } from './rule_migrations_data_base_client'; /* This will be removed once the package registry changes is performed */ import integrationsFile from './integrations_temp.json'; +import type { IndexNameProvider } from './rule_migrations_data_client'; /* The minimum score required for a integration to be considered correct, might need to change this later */ const MIN_SCORE = 40 as const; @@ -22,6 +26,20 @@ const INTEGRATIONS = integrationsFile as Integration[]; * The 500 number was chosen as a reasonable number to avoid large payloads. It can be adjusted if needed. */ export class RuleMigrationsDataIntegrationsClient extends RuleMigrationsDataBaseClient { + constructor( + getIndexName: IndexNameProvider, + username: string, + esClient: ElasticsearchClient, + logger: Logger, + private packageService?: PackageService + ) { + super(getIndexName, username, esClient, logger); + } + + async getIntegrationPackages(): Promise { + return this.packageService?.asInternalUser.getPackages(); + } + /** Indexes an array of integrations to be used with ELSER semantic search queries */ async create(): Promise { const index = await this.getIndexName(); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts index 47bcd56e6433e..8728929a75ba0 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts @@ -43,6 +43,7 @@ export interface RuleMigrationFilters { ids?: string[]; installable?: boolean; prebuilt?: boolean; + custom?: boolean; searchTerm?: string; } export interface RuleMigrationGetOptions { @@ -397,7 +398,7 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient private getFilterQuery( migrationId: string, - { status, ids, installable, prebuilt, searchTerm }: RuleMigrationFilters = {} + { status, ids, installable, prebuilt, custom, searchTerm }: RuleMigrationFilters = {} ): QueryDslQueryContainer { const filter: QueryDslQueryContainer[] = [{ term: { migration_id: migrationId } }]; if (status) { @@ -416,6 +417,9 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient if (prebuilt) { filter.push(searchConditions.isPrebuilt()); } + if (custom) { + filter.push(searchConditions.isCustom()); + } if (searchTerm?.length) { filter.push(searchConditions.matchTitle(searchTerm)); } diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_service.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_service.ts index 5799e5ab84c07..6681f0c3903b0 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_service.ts @@ -6,6 +6,7 @@ */ import type { AuthenticatedUser, ElasticsearchClient, Logger } from '@kbn/core/server'; import { IndexPatternAdapter, type FieldMap, type InstallParams } from '@kbn/index-adapter'; +import type { PackageService } from '@kbn/fleet-plugin/server'; import type { IndexNameProvider, IndexNameProviders } from './rule_migrations_data_client'; import { RuleMigrationsDataClient } from './rule_migrations_data_client'; import { @@ -24,6 +25,7 @@ interface CreateClientParams { spaceId: string; currentUser: AuthenticatedUser; esClient: ElasticsearchClient; + packageService?: PackageService; } export class RuleMigrationsDataService { @@ -58,7 +60,7 @@ export class RuleMigrationsDataService { ]); } - public createClient({ spaceId, currentUser, esClient }: CreateClientParams) { + public createClient({ spaceId, currentUser, esClient, packageService }: CreateClientParams) { const indexNameProviders: IndexNameProviders = { rules: this.createIndexNameProvider('rules', spaceId), resources: this.createIndexNameProvider('resources', spaceId), @@ -70,7 +72,8 @@ export class RuleMigrationsDataService { indexNameProviders, currentUser.username, esClient, - this.logger + this.logger, + packageService ); } diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/search.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/search.ts index 3bd8da066a45f..18196246da66d 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/search.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/search.ts @@ -28,6 +28,14 @@ export const conditions = { }, }; }, + isCustom(): QueryDslQueryContainer { + return { + nested: { + path: 'elastic_rule', + query: { bool: { must_not: { exists: { field: 'elastic_rule.prebuilt_rule_id' } } } }, + }, + }; + }, matchTitle(title: string): QueryDslQueryContainer { return { nested: { diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/sort.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/sort.ts index 2d0ef644b8e56..6f3fcd46612d4 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/sort.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/data/sort.ts @@ -113,9 +113,21 @@ const sortingOptionsMap: { [key: string]: (direction?: estypes.SortOrder) => estypes.SortCombinations[]; } = { 'elastic_rule.title': sortingOptions.name, - 'elastic_rule.severity': sortingOptions.severity, - 'elastic_rule.prebuilt_rule_id': sortingOptions.matchedPrebuiltRule, - translation_result: sortingOptions.status, + 'elastic_rule.severity': (direction?: estypes.SortOrder) => [ + ...sortingOptions.severity(direction), + ...sortingOptions.status('desc'), + ...sortingOptions.matchedPrebuiltRule('desc'), + ], + 'elastic_rule.prebuilt_rule_id': (direction?: estypes.SortOrder) => [ + ...sortingOptions.matchedPrebuiltRule(direction), + ...sortingOptions.status('desc'), + ...sortingOptions.severity('desc'), + ], + translation_result: (direction?: estypes.SortOrder) => [ + ...sortingOptions.status(direction), + ...sortingOptions.matchedPrebuiltRule('desc'), + ...sortingOptions.severity('desc'), + ], updated_at: sortingOptions.updated, }; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/siem_rule_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/siem_rule_migrations_service.ts index d9f4a1c5249cb..3be54a7e3d896 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/siem_rule_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/siem_rule_migrations_service.ts @@ -14,6 +14,7 @@ import type { KibanaRequest, Logger, } from '@kbn/core/server'; +import type { PackageService } from '@kbn/fleet-plugin/server'; import { RuleMigrationsDataService } from './data/rule_migrations_data_service'; import type { RuleMigrationsDataClient } from './data/rule_migrations_data_client'; import type { RuleMigrationsTaskClient } from './task/rule_migrations_task_client'; @@ -29,6 +30,7 @@ export interface SiemRuleMigrationsCreateClientParams { request: KibanaRequest; currentUser: AuthenticatedUser | null; spaceId: string; + packageService?: PackageService; } export interface SiemRuleMigrationsClient { @@ -60,13 +62,19 @@ export class SiemRuleMigrationsService { createClient({ spaceId, currentUser, + packageService, request, }: SiemRuleMigrationsCreateClientParams): SiemRuleMigrationsClient { assert(currentUser, 'Current user must be authenticated'); assert(this.esClusterClient, 'ES client not available, please call setup first'); const esClient = this.esClusterClient.asInternalUser; - const dataClient = this.dataService.createClient({ spaceId, currentUser, esClient }); + const dataClient = this.dataService.createClient({ + spaceId, + currentUser, + esClient, + packageService, + }); const taskClient = this.taskService.createClient({ currentUser, dataClient }); return { data: dataClient, task: taskClient }; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts index 948ae89a39bb0..641838ff5105b 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts @@ -7,6 +7,7 @@ import type { LoggerFactory } from '@kbn/core/server'; import { ReplaySubject, type Subject } from 'rxjs'; +import type { PackageService } from '@kbn/fleet-plugin/server'; import type { ConfigType } from '../../config'; import { SiemRuleMigrationsService, @@ -18,6 +19,7 @@ import type { SiemMigrationsSetupParams } from './types'; export class SiemMigrationsService { private pluginStop$: Subject; private rules: SiemRuleMigrationsService; + private packageService?: PackageService; constructor(private config: ConfigType, logger: LoggerFactory, kibanaVersion: string) { this.pluginStop$ = new ReplaySubject(1); @@ -31,7 +33,11 @@ export class SiemMigrationsService { } createRulesClient(params: SiemRuleMigrationsCreateClientParams): SiemRuleMigrationsClient { - return this.rules.createClient(params); + return this.rules.createClient({ ...params, packageService: this.packageService }); + } + + public start(packageService?: PackageService) { + this.packageService = packageService; } stop() { diff --git a/x-pack/solutions/security/plugins/security_solution/server/plugin.ts b/x-pack/solutions/security/plugins/security_solution/server/plugin.ts index d8fa5c61ee7f3..bf1289f959bac 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/plugin.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/plugin.ts @@ -688,6 +688,8 @@ export class Plugin implements ISecuritySolutionPlugin { this.telemetryReceiver ); + this.siemMigrationsService.start(packageService); + securityWorkflowInsightsService .start({ esClient: core.elasticsearch.client.asInternalUser, From bc2eaec6e44c98fd0f286554765efea002ae38fe Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:49:03 +0000 Subject: [PATCH 2/7] [CI] Auto-commit changed files from 'yarn openapi:generate' --- .../common/api/quickstart_client.gen.ts | 23 +++++++++++++++++ .../services/security_solution_api.gen.ts | 25 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts index fa315e3c421aa..52575bed4e8db 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts @@ -367,6 +367,8 @@ import type { GetRuleMigrationRequestQueryInput, GetRuleMigrationRequestParamsInput, GetRuleMigrationResponse, + GetRuleMigrationIntegrationsRequestParamsInput, + GetRuleMigrationIntegrationsResponse, GetRuleMigrationPrebuiltRulesRequestParamsInput, GetRuleMigrationPrebuiltRulesResponse, GetRuleMigrationResourcesRequestQueryInput, @@ -1455,6 +1457,24 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } + /** + * Retrieves all related integrations + */ + async getRuleMigrationIntegrations(props: GetRuleMigrationIntegrationsProps) { + this.log.info(`${new Date().toISOString()} Calling API GetRuleMigrationIntegrations`); + return this.kbnClient + .request({ + path: replaceParams( + '/internal/siem_migrations/rules/{migration_id}/integrations', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'GET', + }) + .catch(catchAxiosErrorFormatAndThrow); + } /** * Retrieves all available prebuilt rules (installed and installable) */ @@ -2459,6 +2479,9 @@ export interface GetRuleMigrationProps { query: GetRuleMigrationRequestQueryInput; params: GetRuleMigrationRequestParamsInput; } +export interface GetRuleMigrationIntegrationsProps { + params: GetRuleMigrationIntegrationsRequestParamsInput; +} export interface GetRuleMigrationPrebuiltRulesProps { params: GetRuleMigrationPrebuiltRulesRequestParamsInput; } diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index 9ffdc1c43a2a1..4e77adee8d36e 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -100,6 +100,7 @@ import { GetRuleMigrationRequestQueryInput, GetRuleMigrationRequestParamsInput, } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; +import { GetRuleMigrationIntegrationsRequestParamsInput } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; import { GetRuleMigrationPrebuiltRulesRequestParamsInput } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; import { GetRuleMigrationResourcesRequestQueryInput, @@ -974,6 +975,27 @@ finalize it. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .query(props.query); }, + /** + * Retrieves all related integrations + */ + getRuleMigrationIntegrations( + props: GetRuleMigrationIntegrationsProps, + kibanaSpace: string = 'default' + ) { + return supertest + .get( + routeWithNamespace( + replaceParams( + '/internal/siem_migrations/rules/{migration_id}/integrations', + props.params + ), + kibanaSpace + ) + ) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); + }, /** * Retrieves all available prebuilt rules (installed and installable) */ @@ -1793,6 +1815,9 @@ export interface GetRuleMigrationProps { query: GetRuleMigrationRequestQueryInput; params: GetRuleMigrationRequestParamsInput; } +export interface GetRuleMigrationIntegrationsProps { + params: GetRuleMigrationIntegrationsRequestParamsInput; +} export interface GetRuleMigrationPrebuiltRulesProps { params: GetRuleMigrationPrebuiltRulesRequestParamsInput; } From 13c18b1e88233ce0b2a9c5c6158af1b0d8da713e Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Wed, 18 Dec 2024 18:51:19 +0100 Subject: [PATCH 3/7] Review feedback --- .../common/siem_migrations/constants.ts | 4 +- .../model/api/rules/rule_migration.gen.ts | 10 ---- .../api/rules/rule_migration.schema.yaml | 7 --- .../public/siem_migrations/rules/api/index.ts | 13 ++--- .../rules/components/rules_table/index.tsx | 43 ++++++++-------- .../rules_table_columns/integrations.tsx | 6 ++- .../use_migration_rules_table_columns.tsx | 2 +- .../siem_migrations/rules/pages/index.tsx | 22 ++++++++- .../service/hooks/use_get_integrations.ts | 32 +++++------- .../rules/service/rule_migrations_service.ts | 8 ++- .../rules/api/get_integrations.ts | 49 ++----------------- .../siem_migrations_service.ts | 8 +-- .../security_solution/server/plugin.ts | 2 - .../server/request_context_factory.ts | 1 + 14 files changed, 77 insertions(+), 130 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts index e94fc28041ab2..019766d96e78f 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/constants.ts @@ -11,6 +11,8 @@ export const SIEM_MIGRATIONS_PATH = '/internal/siem_migrations' as const; export const SIEM_RULE_MIGRATIONS_PATH = `${SIEM_MIGRATIONS_PATH}/rules` as const; export const SIEM_RULE_MIGRATIONS_ALL_STATS_PATH = `${SIEM_RULE_MIGRATIONS_PATH}/stats` as const; +export const SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH = + `${SIEM_RULE_MIGRATIONS_PATH}/integrations` as const; export const SIEM_RULE_MIGRATION_CREATE_PATH = `${SIEM_RULE_MIGRATIONS_PATH}/{migration_id?}` as const; export const SIEM_RULE_MIGRATION_PATH = `${SIEM_RULE_MIGRATIONS_PATH}/{migration_id}` as const; @@ -25,8 +27,6 @@ export const SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH = `${SIEM_RULE_MIGRATION_PATH}/install_translated` as const; export const SIEM_RULE_MIGRATIONS_PREBUILT_RULES_PATH = `${SIEM_RULE_MIGRATION_PATH}/prebuilt_rules` as const; -export const SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH = - `${SIEM_RULE_MIGRATION_PATH}/integrations` as const; export const SIEM_RULE_MIGRATION_RESOURCES_PATH = `${SIEM_RULE_MIGRATION_PATH}/resources` as const; export const SIEM_RULE_MIGRATION_RESOURCES_MISSING_PATH = diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts index f00f5cf17cd44..e8e642a894d8a 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts @@ -80,16 +80,6 @@ export const GetRuleMigrationResponse = z.object({ data: z.array(RuleMigration), }); -export type GetRuleMigrationIntegrationsRequestParams = z.infer< - typeof GetRuleMigrationIntegrationsRequestParams ->; -export const GetRuleMigrationIntegrationsRequestParams = z.object({ - migration_id: NonEmptyString, -}); -export type GetRuleMigrationIntegrationsRequestParamsInput = z.input< - typeof GetRuleMigrationIntegrationsRequestParams ->; - /** * The map of related integrations, with the integration id as a key */ diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml index f1af3290c76e1..d29efb82a060d 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml @@ -405,13 +405,6 @@ paths: description: Retrieves all related integrations tags: - SIEM Rule Migrations - parameters: - - name: migration_id - in: path - required: true - schema: - description: The migration id to retrieve related integrations for - $ref: '../../../../../common/api/model/primitives.schema.yaml#/components/schemas/NonEmptyString' responses: 200: description: Indicates that related integrations have been retrieved correctly. diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts index 8681244a301ec..2465a465d28d7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts @@ -281,19 +281,16 @@ export const getRuleMigrationsPrebuiltRules = async ({ ); }; -export interface GetRelatedIntegrationsParams { - /** `id` of the migration to get related integrations for */ - migrationId: string; +export interface GetIntegrationsParams { /** Optional AbortSignal for cancelling request */ signal?: AbortSignal; } -/** Retrieves related integrations for a specific migration. */ -export const getRelatedIntegrations = async ({ - migrationId, +/** Retrieves existing integrations. */ +export const getIntegrations = async ({ signal, -}: GetRelatedIntegrationsParams): Promise => { +}: GetIntegrationsParams): Promise => { return KibanaServices.get().http.get( - replaceParams(SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH, { migration_id: migrationId }), + SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH, { version: '1', signal } ); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx index f54dba5ca6b82..ba86a7587b5f8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx @@ -34,7 +34,6 @@ import { BulkActions } from './bulk_actions'; import { SearchField } from './search_field'; import { RuleTranslationResult } from '../../../../../common/siem_migrations/constants'; import * as i18n from './translations'; -import { useGetRelatedIntegrations } from '../../service/hooks/use_get_integrations'; const DEFAULT_PAGE_SIZE = 10; const DEFAULT_SORT_FIELD = 'translation_result'; @@ -45,13 +44,23 @@ export interface MigrationRulesTableProps { * Selected rule migration id */ migrationId: string; + + /** + * Existing integrations. + */ + integrations?: Record; + + /** + * Indicates whether the integrations loading is in progress. + */ + isIntegrationsLoading?: boolean; } /** * Table Component for displaying SIEM rules migrations */ export const MigrationRulesTable: React.FC = React.memo( - ({ migrationId }) => { + ({ migrationId, integrations, isIntegrationsLoading }) => { const { addError } = useAppToasts(); const [pageIndex, setPageIndex] = useState(0); @@ -66,9 +75,6 @@ export const MigrationRulesTable: React.FC = React.mem const { data: prebuiltRules = {}, isLoading: isPrebuiltRulesLoading } = useGetMigrationPrebuiltRules(migrationId); - const { integrations, isLoading: isIntegrationsLoading } = - useGetRelatedIntegrations(migrationId); - const { data: { ruleMigrations, total } = { ruleMigrations: [], total: 0 }, isLoading: isDataLoading, @@ -185,12 +191,7 @@ export const MigrationRulesTable: React.FC = React.mem [addError, installTranslatedMigrationRules] ); - const isLoading = - isStatsLoading || - isPrebuiltRulesLoading || - isIntegrationsLoading || - isDataLoading || - isTableLoading; + const isLoading = isStatsLoading || isPrebuiltRulesLoading || isDataLoading || isTableLoading; const ruleActionsFactory = useCallback( (ruleMigration: RuleMigration, closeRulePreview: () => void) => { @@ -233,7 +234,7 @@ export const MigrationRulesTable: React.FC = React.mem const getMigrationRuleData = useCallback( (ruleId: string) => { - if (!isLoading && ruleMigrations.length && integrations) { + if (!isLoading && ruleMigrations.length) { const ruleMigration = ruleMigrations.find((item) => item.id === ruleId); let matchedPrebuiltRule: RuleResponse | undefined; const relatedIntegrations: RelatedIntegration[] = []; @@ -245,19 +246,21 @@ export const MigrationRulesTable: React.FC = React.mem matchedPrebuiltRule = matchedPrebuiltRuleVersion?.current ?? matchedPrebuiltRuleVersion?.target; - if (matchedPrebuiltRule?.related_integrations) { - relatedIntegrations.push(...matchedPrebuiltRule.related_integrations); - } else if (ruleMigration.elastic_rule?.integration_id) { - const integration = integrations[ruleMigration.elastic_rule.integration_id]; - if (integration) { - relatedIntegrations.push(integration); + if (integrations) { + if (matchedPrebuiltRule?.related_integrations) { + relatedIntegrations.push(...matchedPrebuiltRule.related_integrations); + } else if (ruleMigration.elastic_rule?.integration_id) { + const integration = integrations[ruleMigration.elastic_rule.integration_id]; + if (integration) { + relatedIntegrations.push(integration); + } } } } - return { ruleMigration, matchedPrebuiltRule, relatedIntegrations }; + return { ruleMigration, matchedPrebuiltRule, relatedIntegrations, isIntegrationsLoading }; } }, - [integrations, isLoading, prebuiltRules, ruleMigrations] + [integrations, isIntegrationsLoading, isLoading, prebuiltRules, ruleMigrations] ); const { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx index ae7a282683dae..43b7086c9814c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/integrations.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; import type { RelatedIntegration } from '../../../../../common/api/detection_engine'; import { IntegrationsPopover } from '../../../../detections/components/rules/related_integrations/integrations_popover'; import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; @@ -17,13 +18,16 @@ export const createIntegrationsColumn = ({ }: { getMigrationRuleData: ( ruleId: string - ) => { relatedIntegrations?: RelatedIntegration[] } | undefined; + ) => { relatedIntegrations?: RelatedIntegration[]; isIntegrationsLoading?: boolean } | undefined; }): TableColumn => { return { field: 'elastic_rule.integration_id', name: i18n.COLUMN_INTEGRATIONS, render: (_, rule: RuleMigration) => { const migrationRuleData = getMigrationRuleData(rule.id); + if (migrationRuleData?.isIntegrationsLoading) { + return ; + } const relatedIntegrations = migrationRuleData?.relatedIntegrations; if (relatedIntegrations == null || relatedIntegrations.length === 0) { return null; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rules_table_columns.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rules_table_columns.tsx index 7ae79938f7c34..3e0a69ee66004 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rules_table_columns.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rules_table_columns.tsx @@ -31,7 +31,7 @@ export const useMigrationRulesTableColumns = ({ installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void; getMigrationRuleData: ( ruleId: string - ) => { relatedIntegrations?: RelatedIntegration[] } | undefined; + ) => { relatedIntegrations?: RelatedIntegration[]; isIntegrationsLoading?: boolean } | undefined; }): TableColumn[] => { return useMemo( () => [ diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx index 3877a6f46cbe7..4fd24c709382f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx @@ -9,6 +9,7 @@ import React, { useEffect, useMemo } from 'react'; import { EuiSkeletonLoading, EuiSkeletonText, EuiSkeletonTitle } from '@elastic/eui'; import type { RouteComponentProps } from 'react-router-dom'; +import type { RelatedIntegration } from '../../../../common/api/detection_engine'; import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/constants'; import { useNavigation } from '../../../common/lib/kibana'; import { HeaderPage } from '../../../common/components/header_page'; @@ -22,6 +23,7 @@ import { MissingPrivilegesCallOut } from '../../../detections/components/callout import { HeaderButtons } from '../components/header_buttons'; import { UnknownMigration } from '../components/unknown_migration'; import { useLatestStats } from '../service/hooks/use_latest_stats'; +import { useGetIntegrations } from '../service/hooks/use_get_integrations'; type MigrationRulesPageProps = RouteComponentProps<{ migrationId?: string }>; @@ -35,6 +37,16 @@ export const MigrationRulesPage: React.FC = React.memo( const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = useLatestStats(); + const [integrations, setIntegrations] = React.useState< + Record | undefined + >(); + const { getIntegrations, isLoading: isIntegrationsLoading } = + useGetIntegrations(setIntegrations); + + useEffect(() => { + getIntegrations(); + }, [getIntegrations]); + const finishedRuleMigrationsStats = useMemo(() => { if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) { return []; @@ -72,8 +84,14 @@ export const MigrationRulesPage: React.FC = React.memo( if (!migrationId || !finishedRuleMigrationsStats.some((stats) => stats.id === migrationId)) { return ; } - return ; - }, [migrationId, finishedRuleMigrationsStats]); + return ( + + ); + }, [migrationId, finishedRuleMigrationsStats, integrations, isIntegrationsLoading]); return ( <> diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts index 081ed821ed01a..8ed94e78f31c4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_get_integrations.ts @@ -5,44 +5,38 @@ * 2.0. */ -import { useCallback, useEffect, useReducer, useState } from 'react'; +import { useCallback, useReducer } from 'react'; import { i18n } from '@kbn/i18n'; import type { RelatedIntegration } from '../../../../../common/api/detection_engine'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import { reducer, initialState } from './common/api_request_reducer'; -export const GET_RELATED_INTEGRATIONS_ERROR = i18n.translate( - 'xpack.securitySolution.siemMigrations.rules.service.getRelatedIntegrationsError', - { defaultMessage: 'Failed to fetch related integrations' } +export const GET_INTEGRATIONS_ERROR = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.service.getIntegrationsError', + { defaultMessage: 'Failed to fetch integrations' } ); -export const useGetRelatedIntegrations = (migrationId: string) => { +export type OnSuccess = (integrations: Record) => void; + +export const useGetIntegrations = (onSuccess: OnSuccess) => { const { siemMigrations, notifications } = useKibana().services; const [state, dispatch] = useReducer(reducer, initialState); - const [integrations, setIntegrations] = useState< - Record | undefined - >(); - const getRelatedIntegrations = useCallback(() => { + const getIntegrations = useCallback(() => { (async () => { try { dispatch({ type: 'start' }); - const results = await siemMigrations.rules.getRelatedIntegrations(migrationId); + const integrations = await siemMigrations.rules.getIntegrations(); - setIntegrations(results); + onSuccess(integrations); dispatch({ type: 'success' }); } catch (err) { - setIntegrations(undefined); const apiError = err.body ?? err; - notifications.toasts.addError(apiError, { title: GET_RELATED_INTEGRATIONS_ERROR }); + notifications.toasts.addError(apiError, { title: GET_INTEGRATIONS_ERROR }); dispatch({ type: 'error', error: apiError }); } })(); - }, [siemMigrations.rules, migrationId, notifications.toasts]); - - useEffect(() => { - getRelatedIntegrations(); - }, [getRelatedIntegrations]); + }, [siemMigrations.rules, notifications.toasts, onSuccess]); - return { isLoading: state.loading, error: state.error, integrations }; + return { isLoading: state.loading, error: state.error, getIntegrations }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts index 83c2ee69e4b86..69ed039e6d5ab 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts @@ -36,7 +36,7 @@ import { type GetRuleMigrationsStatsAllParams, getMissingResources, upsertMigrationResources, - getRelatedIntegrations, + getIntegrations, } from '../api'; import type { RuleMigrationStats } from '../types'; import { getSuccessToast } from './success_notification'; @@ -183,10 +183,8 @@ export class SiemRulesMigrationsService { }); } - public async getRelatedIntegrations( - migrationId: string - ): Promise> { - return getRelatedIntegrations({ migrationId }); + public async getIntegrations(): Promise> { + return getIntegrations({}); } private async startTaskStatsPolling(): Promise { diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts index 01f97e2ce8caf..afc7c7b9608d3 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/get_integrations.ts @@ -6,16 +6,11 @@ */ import type { IKibanaResponse, Logger } from '@kbn/core/server'; -import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { RelatedIntegration } from '../../../../../common/api/detection_engine'; -import { - GetRuleMigrationIntegrationsRequestParams, - type GetRuleMigrationIntegrationsResponse, -} from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { type GetRuleMigrationIntegrationsResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import { SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH } from '../../../../../common/siem_migrations/constants'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { withLicense } from './util/with_license'; -import { getPrebuiltRulesForMigration } from './util/prebuilt_rules'; export const registerSiemRuleMigrationsIntegrationsRoute = ( router: SecuritySolutionPluginRouter, @@ -30,11 +25,7 @@ export const registerSiemRuleMigrationsIntegrationsRoute = ( .addVersion( { version: '1', - validate: { - request: { - params: buildRouteValidationWithZod(GetRuleMigrationIntegrationsRequestParams), - }, - }, + validate: {}, }, withLicense( async ( @@ -42,48 +33,14 @@ export const registerSiemRuleMigrationsIntegrationsRoute = ( req, res ): Promise> => { - const { migration_id: migrationId } = req.params; try { const ctx = await context.resolve(['core', 'alerting', 'securitySolution']); const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient(); - const savedObjectsClient = ctx.core.savedObjects.client; - const rulesClient = await ctx.alerting.getRulesClient(); - - // Retrieve related integrations for migration rules translated into Elastic custom rules - const options = { filters: { custom: true } }; - const batches = ruleMigrationsClient.data.rules.searchBatches(migrationId, options); - - const integrationIdsSet = new Set(); - let results = await batches.next(); - while (results.length) { - results.forEach((rule) => { - if (rule.elastic_rule?.integration_id) { - integrationIdsSet.add(rule.elastic_rule.integration_id); - } - }); - results = await batches.next(); - } const relatedIntegrations: Record = {}; const packages = await ruleMigrationsClient.data.integrations.getIntegrationPackages(); packages?.forEach(({ id, version, integration }) => { - if (integrationIdsSet.has(id)) { - relatedIntegrations[id] = { package: id, version, integration }; - } - }); - - // Retrieve related integrations for migration rules matched with prebuilt rules - const prebuiltRules = await getPrebuiltRulesForMigration( - migrationId, - ruleMigrationsClient, - rulesClient, - savedObjectsClient - ); - Object.values(prebuiltRules).forEach((rule) => { - const integrations = (rule.current ?? rule.target).related_integrations; - integrations.forEach( - (integration) => (relatedIntegrations[integration.package] = integration) - ); + relatedIntegrations[id] = { package: id, version, integration }; }); return res.ok({ body: relatedIntegrations }); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts index 641838ff5105b..8d30ddeb1d51e 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts @@ -7,7 +7,6 @@ import type { LoggerFactory } from '@kbn/core/server'; import { ReplaySubject, type Subject } from 'rxjs'; -import type { PackageService } from '@kbn/fleet-plugin/server'; import type { ConfigType } from '../../config'; import { SiemRuleMigrationsService, @@ -19,7 +18,6 @@ import type { SiemMigrationsSetupParams } from './types'; export class SiemMigrationsService { private pluginStop$: Subject; private rules: SiemRuleMigrationsService; - private packageService?: PackageService; constructor(private config: ConfigType, logger: LoggerFactory, kibanaVersion: string) { this.pluginStop$ = new ReplaySubject(1); @@ -33,11 +31,7 @@ export class SiemMigrationsService { } createRulesClient(params: SiemRuleMigrationsCreateClientParams): SiemRuleMigrationsClient { - return this.rules.createClient({ ...params, packageService: this.packageService }); - } - - public start(packageService?: PackageService) { - this.packageService = packageService; + return this.rules.createClient({ ...params }); } stop() { diff --git a/x-pack/solutions/security/plugins/security_solution/server/plugin.ts b/x-pack/solutions/security/plugins/security_solution/server/plugin.ts index bf1289f959bac..d8fa5c61ee7f3 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/plugin.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/plugin.ts @@ -688,8 +688,6 @@ export class Plugin implements ISecuritySolutionPlugin { this.telemetryReceiver ); - this.siemMigrationsService.start(packageService); - securityWorkflowInsightsService .start({ esClient: core.elasticsearch.client.asInternalUser, diff --git a/x-pack/solutions/security/plugins/security_solution/server/request_context_factory.ts b/x-pack/solutions/security/plugins/security_solution/server/request_context_factory.ts index a6b5e1b3e650a..1c5e954dfeb79 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/request_context_factory.ts @@ -176,6 +176,7 @@ export class RequestContextFactory implements IRequestContextFactory { request, currentUser: coreContext.security.authc.getCurrentUser(), spaceId: getSpaceId(), + packageService: startPlugins.fleet?.packageService, }) ), From 41e5a44ef91cd402e36b23d7f824dfa3f67eee64 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:14:13 +0000 Subject: [PATCH 4/7] [CI] Auto-commit changed files from 'yarn openapi:generate' --- .../common/api/quickstart_client.gen.ts | 11 ++--------- .../services/security_solution_api.gen.ts | 14 ++------------ 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts index 52575bed4e8db..95ecaa8ad4c75 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts @@ -367,7 +367,6 @@ import type { GetRuleMigrationRequestQueryInput, GetRuleMigrationRequestParamsInput, GetRuleMigrationResponse, - GetRuleMigrationIntegrationsRequestParamsInput, GetRuleMigrationIntegrationsResponse, GetRuleMigrationPrebuiltRulesRequestParamsInput, GetRuleMigrationPrebuiltRulesResponse, @@ -1460,14 +1459,11 @@ finalize it. /** * Retrieves all related integrations */ - async getRuleMigrationIntegrations(props: GetRuleMigrationIntegrationsProps) { + async getRuleMigrationIntegrations() { this.log.info(`${new Date().toISOString()} Calling API GetRuleMigrationIntegrations`); return this.kbnClient .request({ - path: replaceParams( - '/internal/siem_migrations/rules/{migration_id}/integrations', - props.params - ), + path: '/internal/siem_migrations/rules/{migration_id}/integrations', headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1', }, @@ -2479,9 +2475,6 @@ export interface GetRuleMigrationProps { query: GetRuleMigrationRequestQueryInput; params: GetRuleMigrationRequestParamsInput; } -export interface GetRuleMigrationIntegrationsProps { - params: GetRuleMigrationIntegrationsRequestParamsInput; -} export interface GetRuleMigrationPrebuiltRulesProps { params: GetRuleMigrationPrebuiltRulesRequestParamsInput; } diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index 4e77adee8d36e..61c7766b8b5be 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -100,7 +100,6 @@ import { GetRuleMigrationRequestQueryInput, GetRuleMigrationRequestParamsInput, } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; -import { GetRuleMigrationIntegrationsRequestParamsInput } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; import { GetRuleMigrationPrebuiltRulesRequestParamsInput } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; import { GetRuleMigrationResourcesRequestQueryInput, @@ -978,17 +977,11 @@ finalize it. /** * Retrieves all related integrations */ - getRuleMigrationIntegrations( - props: GetRuleMigrationIntegrationsProps, - kibanaSpace: string = 'default' - ) { + getRuleMigrationIntegrations(kibanaSpace: string = 'default') { return supertest .get( routeWithNamespace( - replaceParams( - '/internal/siem_migrations/rules/{migration_id}/integrations', - props.params - ), + '/internal/siem_migrations/rules/{migration_id}/integrations', kibanaSpace ) ) @@ -1815,9 +1808,6 @@ export interface GetRuleMigrationProps { query: GetRuleMigrationRequestQueryInput; params: GetRuleMigrationRequestParamsInput; } -export interface GetRuleMigrationIntegrationsProps { - params: GetRuleMigrationIntegrationsRequestParamsInput; -} export interface GetRuleMigrationPrebuiltRulesProps { params: GetRuleMigrationPrebuiltRulesRequestParamsInput; } From ff1aa332e7e0273e2ad94c15da0e5434fd202c34 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:33:26 +0000 Subject: [PATCH 5/7] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/legacy/embeddable/visualize_embeddable.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx index e343fd535a85e..1f631f30f8eb5 100644 --- a/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx @@ -22,11 +22,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { Warnings } from '@kbn/charts-plugin/public'; import { hasUnsupportedDownsampledAggregationFailure } from '@kbn/search-response-warnings'; import { Adapters } from '@kbn/inspector-plugin/public'; -import { - Embeddable, - EmbeddableInput, - EmbeddableOutput, -} from '@kbn/embeddable-plugin/public'; +import { Embeddable, EmbeddableInput, EmbeddableOutput } from '@kbn/embeddable-plugin/public'; import { SavedObjectEmbeddableInput } from '@kbn/embeddable-plugin/common'; import { ExpressionAstExpression, From ee2cb3392fa18e1de6205a7312c18716d0c097ee Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Thu, 19 Dec 2024 17:52:14 +0100 Subject: [PATCH 6/7] Review feedback --- .../model/api/rules/rule_migration.gen.ts | 2 +- .../api/rules/rule_migration.schema.yaml | 40 +++++++++---------- .../rules/api/util/installation.ts | 8 +--- .../rules/api/util/prebuilt_rules.ts | 8 +--- .../siem_migrations_service.ts | 2 +- 5 files changed, 26 insertions(+), 34 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts index e8e642a894d8a..7a6cbec4d2d1d 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts @@ -28,9 +28,9 @@ import { RuleMigrationResourceType, RuleMigrationResource, } from '../../rule_migration.gen'; +import { RelatedIntegration } from '../../../../api/detection_engine/model/rule_schema/common_attributes.gen'; import { NonEmptyString } from '../../../../api/model/primitives.gen'; import { ConnectorId, LangSmithOptions } from '../../common.gen'; -import { RelatedIntegration } from '../../../../api/detection_engine/model/rule_schema/common_attributes.gen'; export type CreateRuleMigrationRequestParams = z.infer; export const CreateRuleMigrationRequestParams = z.object({ diff --git a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml index d29efb82a060d..39feb3a51897c 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml +++ b/x-pack/solutions/security/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml @@ -54,6 +54,26 @@ paths: items: $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationTaskStats' + /internal/siem_migrations/rules/integrations: + get: + summary: Retrieves all related integrations for a specific migration + operationId: GetRuleMigrationIntegrations + x-codegen-enabled: true + x-internal: true + description: Retrieves all related integrations + tags: + - SIEM Rule Migrations + responses: + 200: + description: Indicates that related integrations have been retrieved correctly. + content: + application/json: + schema: + type: object + description: The map of related integrations, with the integration id as a key + additionalProperties: + $ref: '../../../../../common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml#/components/schemas/RelatedIntegration' + ## Specific rule migration APIs /internal/siem_migrations/rules/{migration_id}: @@ -396,26 +416,6 @@ paths: additionalProperties: $ref: '../../rule_migration.schema.yaml#/components/schemas/PrebuiltRuleVersion' - /internal/siem_migrations/rules/{migration_id}/integrations: - get: - summary: Retrieves all related integrations for a specific migration - operationId: GetRuleMigrationIntegrations - x-codegen-enabled: true - x-internal: true - description: Retrieves all related integrations - tags: - - SIEM Rule Migrations - responses: - 200: - description: Indicates that related integrations have been retrieved correctly. - content: - application/json: - schema: - type: object - description: The map of related integrations, with the integration id as a key - additionalProperties: - $ref: '../../../../../common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml#/components/schemas/RelatedIntegration' - # Rule migration resources APIs /internal/siem_migrations/rules/{migration_id}/resources: diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts index aace5ed0ab356..de95d818dd18d 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts @@ -15,7 +15,7 @@ import { createPrebuiltRules } from '../../../../detection_engine/prebuilt_rules import type { IDetectionRulesClient } from '../../../../detection_engine/rule_management/logic/detection_rules_client/detection_rules_client_interface'; import type { RuleResponse } from '../../../../../../common/api/detection_engine'; import type { StoredRuleMigration } from '../../types'; -import { getPrebuiltRulesByIds, getUniquePrebuiltRuleIds } from './prebuilt_rules'; +import { getPrebuiltRules, getUniquePrebuiltRuleIds } from './prebuilt_rules'; import { MAX_CUSTOM_RULES_TO_CREATE_IN_PARALLEL, MAX_TRANSLATED_RULES_TO_INSTALL, @@ -35,11 +35,7 @@ const installPrebuiltRules = async ( ): Promise => { // Get required prebuilt rules const prebuiltRulesIds = getUniquePrebuiltRuleIds(rulesToInstall); - const prebuiltRules = await getPrebuiltRulesByIds( - rulesClient, - savedObjectsClient, - prebuiltRulesIds - ); + const prebuiltRules = await getPrebuiltRules(rulesClient, savedObjectsClient, prebuiltRulesIds); const { installed: alreadyInstalledRules, installable } = Object.values(prebuiltRules).reduce( (acc, item) => { diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts index 64d7aa8bb5f56..cf7317f0bfde0 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/util/prebuilt_rules.ts @@ -44,7 +44,7 @@ export interface PrebuiltRulesResults { * @param rulesIds The list of IDs to filter requested prebuilt rules. If not specified, all available prebuilt rules will be returned. * @returns */ -export const getPrebuiltRulesByIds = async ( +export const getPrebuiltRules = async ( rulesClient: RulesClient, savedObjectsClient: SavedObjectsClientContract, rulesIds?: string[] @@ -113,11 +113,7 @@ export const getPrebuiltRulesForMigration = async ( } const prebuiltRulesIds = Array.from(rulesIds); - const prebuiltRules = await getPrebuiltRulesByIds( - rulesClient, - savedObjectsClient, - prebuiltRulesIds - ); + const prebuiltRules = await getPrebuiltRules(rulesClient, savedObjectsClient, prebuiltRulesIds); return prebuiltRules; }; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts index 8d30ddeb1d51e..948ae89a39bb0 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/siem_migrations_service.ts @@ -31,7 +31,7 @@ export class SiemMigrationsService { } createRulesClient(params: SiemRuleMigrationsCreateClientParams): SiemRuleMigrationsClient { - return this.rules.createClient({ ...params }); + return this.rules.createClient(params); } stop() { From ded57e031de4c874bcd03bb9cb3d9bb2ac9f168d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:19:17 +0000 Subject: [PATCH 7/7] [CI] Auto-commit changed files from 'yarn openapi:generate' --- .../security_solution/common/api/quickstart_client.gen.ts | 2 +- .../api_integration/services/security_solution_api.gen.ts | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts index 95ecaa8ad4c75..774935bd95719 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/api/quickstart_client.gen.ts @@ -1463,7 +1463,7 @@ finalize it. this.log.info(`${new Date().toISOString()} Calling API GetRuleMigrationIntegrations`); return this.kbnClient .request({ - path: '/internal/siem_migrations/rules/{migration_id}/integrations', + path: '/internal/siem_migrations/rules/integrations', headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1', }, diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index 61c7766b8b5be..d2b44d297b276 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -979,12 +979,7 @@ finalize it. */ getRuleMigrationIntegrations(kibanaSpace: string = 'default') { return supertest - .get( - routeWithNamespace( - '/internal/siem_migrations/rules/{migration_id}/integrations', - kibanaSpace - ) - ) + .get(routeWithNamespace('/internal/siem_migrations/rules/integrations', kibanaSpace)) .set('kbn-xsrf', 'true') .set(ELASTIC_HTTP_VERSION_HEADER, '1') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana');