diff --git a/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result.tsx b/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result.tsx index d89f878bf014..d7c16cdbc401 100644 --- a/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result.tsx +++ b/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result.tsx @@ -37,7 +37,7 @@ export const OsqueryResult = React.memo( } event={ATTACHED_QUERY} data-test-subj={'osquery-results-comment'} diff --git a/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result_wrapper.tsx b/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result_wrapper.tsx index 0da0a01c0128..084c1f778cbd 100644 --- a/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result_wrapper.tsx +++ b/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_result_wrapper.tsx @@ -40,7 +40,7 @@ const OsqueryResultComponent = React.memo( return ( } event={ATTACHED_QUERY} data-test-subj={'osquery-results-comment'} diff --git a/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_results.test.tsx b/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_results.test.tsx index 263245d4cd5b..4e02daabcc00 100644 --- a/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_results.test.tsx +++ b/x-pack/plugins/osquery/public/shared_components/osquery_results/osquery_results.test.tsx @@ -32,7 +32,7 @@ const enablePrivileges = () => { }; const defaultProps: OsqueryActionResultsProps = { - ruleName: ['Test-rule'], + ruleName: 'Test-rule', actionItems: [ { _id: 'test', diff --git a/x-pack/plugins/osquery/public/shared_components/osquery_results/types.ts b/x-pack/plugins/osquery/public/shared_components/osquery_results/types.ts index 03815b991915..41f6fbb0e6e2 100644 --- a/x-pack/plugins/osquery/public/shared_components/osquery_results/types.ts +++ b/x-pack/plugins/osquery/public/shared_components/osquery_results/types.ts @@ -9,13 +9,13 @@ import type { Ecs } from '@kbn/cases-plugin/common'; import type { ActionEdges } from '../../../common/search_strategy'; export interface OsqueryActionResultsProps { - ruleName?: string[]; + ruleName?: string; ecsData?: Ecs | null; actionItems?: ActionEdges; } export interface OsqueryActionResultProps { - ruleName?: string[]; + ruleName?: string; ecsData?: Ecs | null; actionId: string; startDate: string; diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index 32e043298309..fdcf95a5cab4 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -102,3 +102,4 @@ export const ENDPOINT_ERROR_CODES: Record = { }; export const ENDPOINT_FIELDS_SEARCH_STRATEGY = 'endpointFields'; +export const ENDPOINT_SEARCH_STRATEGY = 'endpointSearchStrategy'; diff --git a/x-pack/plugins/security_solution/common/search_strategy/endpoint/index.ts b/x-pack/plugins/security_solution/common/search_strategy/endpoint/index.ts new file mode 100644 index 000000000000..24ac653780a7 --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/endpoint/index.ts @@ -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 type { IEsSearchResponse } from '@kbn/data-plugin/common'; +import type { ActionResponsesRequestStrategyParseResponse } from './response_actions/response'; +import type { + ResponseActionsQueries, + ActionRequestOptions, + ActionRequestStrategyResponse, + ActionResponsesRequestOptions, + ActionResponsesRequestStrategyResponse, +} from './response_actions'; + +export type EndpointFactoryQueryTypes = ResponseActionsQueries; + +export type EndpointStrategyParseResponseType = + T extends ResponseActionsQueries.results + ? ActionResponsesRequestStrategyParseResponse + : IEsSearchResponse; + +export type EndpointStrategyResponseType = + T extends ResponseActionsQueries.actions + ? ActionRequestStrategyResponse + : T extends ResponseActionsQueries.results + ? ActionResponsesRequestStrategyResponse + : never; + +export type EndpointStrategyRequestType = + T extends ResponseActionsQueries.actions + ? ActionRequestOptions + : T extends ResponseActionsQueries.results + ? ActionResponsesRequestOptions + : never; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/action.ts b/x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/action.ts similarity index 100% rename from x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/action.ts rename to x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/action.ts diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/index.ts b/x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/index.ts similarity index 100% rename from x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/index.ts rename to x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/index.ts diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/response.ts b/x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/response.ts similarity index 100% rename from x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/response.ts rename to x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/response.ts diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/types.ts b/x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/types.ts similarity index 100% rename from x-pack/plugins/security_solution/common/search_strategy/security_solution/response_actions/types.ts rename to x-pack/plugins/security_solution/common/search_strategy/endpoint/response_actions/types.ts diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts index f15a5e38af5f..c9220132f9a5 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts @@ -4,8 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { IEsSearchRequest, IEsSearchResponse } from '@kbn/data-plugin/common'; -import type { ActionResponsesRequestStrategyParseResponse } from './response_actions/response'; +import type { IEsSearchRequest } from '@kbn/data-plugin/common'; import type { ESQuery } from '../../typed_json'; import type { HostDetailsStrategyResponse, @@ -100,13 +99,6 @@ import type { FirstLastSeenRequestOptions, FirstLastSeenStrategyResponse, } from './first_last_seen'; -import type { - ActionRequestOptions, - ActionRequestStrategyResponse, - ActionResponsesRequestOptions, - ActionResponsesRequestStrategyResponse, - ResponseActionsQueries, -} from './response_actions'; import type { ManagedUserDetailsRequestOptions, ManagedUserDetailsStrategyResponse, @@ -140,8 +132,7 @@ export type FactoryQueryTypes = | CtiQueries | typeof MatrixHistogramQuery | typeof FirstLastSeenQuery - | RelatedEntitiesQueries - | ResponseActionsQueries; + | RelatedEntitiesQueries; export interface RequestBasicOptions extends IEsSearchRequest { timerange: TimerangeInput; @@ -157,11 +148,6 @@ export interface RequestOptionsPaginated extends RequestBasicOpt sort: SortField; } -export type StrategyParseResponseType = - T extends ResponseActionsQueries.results - ? ActionResponsesRequestStrategyParseResponse - : IEsSearchResponse; - export type StrategyResponseType = T extends HostsQueries.hosts ? HostsStrategyResponse : T extends HostsQueries.details @@ -230,10 +216,6 @@ export type StrategyResponseType = T extends HostsQ ? HostsRelatedUsersStrategyResponse : T extends RelatedEntitiesQueries.relatedHosts ? UsersRelatedHostsStrategyResponse - : T extends ResponseActionsQueries.actions - ? ActionRequestStrategyResponse - : T extends ResponseActionsQueries.results - ? ActionResponsesRequestStrategyResponse : never; export type StrategyRequestType = T extends HostsQueries.hosts @@ -304,10 +286,6 @@ export type StrategyRequestType = T extends HostsQu ? UsersRelatedHostsRequestOptions : T extends RelatedEntitiesQueries.relatedUsers ? HostsRelatedUsersRequestOptions - : T extends ResponseActionsQueries.actions - ? ActionRequestOptions - : T extends ResponseActionsQueries.results - ? ActionResponsesRequestOptions : never; export interface CommonFields { diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx index 8ad20bb0fdf6..67957f2a3813 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx @@ -80,7 +80,7 @@ export const useOsqueryTab = ({ const actionItems = actionsData?.data.items || []; - const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name; + const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name?.[0]; const content = ( diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx index c97b9b1417c9..c5680d943ba2 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/response_actions_view.tsx @@ -36,7 +36,6 @@ export const useResponseActionsView = ({ rawEventData: SearchHit | undefined; }): EuiTabbedContentTab | undefined => { const responseActionsEnabled = useIsExperimentalFeatureEnabled('endpointResponseActionsEnabled'); - const expandedEventFieldsObject = rawEventData ? (expandDottedObject((rawEventData as RawEventData).fields) as ExpandedEventFieldsObject) : undefined; @@ -58,7 +57,7 @@ export const useResponseActionsView = ({ return; } - const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name; + const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name?.[0]; const totalItemCount = automatedList?.items?.length ?? 0; diff --git a/x-pack/plugins/security_solution/public/common/components/response_actions/endpoint_action_results.tsx b/x-pack/plugins/security_solution/public/common/components/response_actions/endpoint_action_results.tsx index fd1ee3cec75b..b32834544cf5 100644 --- a/x-pack/plugins/security_solution/public/common/components/response_actions/endpoint_action_results.tsx +++ b/x-pack/plugins/security_solution/public/common/components/response_actions/endpoint_action_results.tsx @@ -18,10 +18,14 @@ import { ResponseActionsEmptyPrompt } from './response_actions_empty_prompt'; interface EndpointResponseActionResultsProps { action: LogsEndpointActionWithHosts; + ruleName?: string; } -export const EndpointResponseActionResults = ({ action }: EndpointResponseActionResultsProps) => { - const { rule, agent } = action; +export const EndpointResponseActionResults = ({ + action, + ruleName, +}: EndpointResponseActionResultsProps) => { + const { agent } = action; const { action_id: actionId, expiration } = action.EndpointActions; const { endpointPrivileges: { canAccessEndpointActionsLogManagement }, @@ -52,7 +56,7 @@ export const EndpointResponseActionResults = ({ action }: EndpointResponseAction return ( } event={eventText} data-test-subj={'endpoint-results-comment'} diff --git a/x-pack/plugins/security_solution/public/common/components/response_actions/response_actions_results.tsx b/x-pack/plugins/security_solution/public/common/components/response_actions/response_actions_results.tsx index feb347a08ee2..3c7be79a56f5 100644 --- a/x-pack/plugins/security_solution/public/common/components/response_actions/response_actions_results.tsx +++ b/x-pack/plugins/security_solution/public/common/components/response_actions/response_actions_results.tsx @@ -18,7 +18,7 @@ import { useKibana } from '../../lib/kibana'; interface ResponseActionsResultsProps { actions: Array; - ruleName?: string[]; + ruleName?: string; ecsData?: Ecs | null; } @@ -47,7 +47,11 @@ export const ResponseActionsResults = React.memo( } if (isEndpoint(action)) { return ( - + ); } return null; diff --git a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts index 2f7f3cd45838..2601c8eea15a 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_automated_action_list.ts @@ -8,19 +8,20 @@ import type { UseQueryResult } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; import { lastValueFrom } from 'rxjs'; - import { compact, filter, map } from 'lodash'; + +import { ENDPOINT_SEARCH_STRATEGY } from '../../../../common/endpoint/constants'; import { expandDottedObject } from '../../../../common/utils/expand_dotted'; import type { ActionDetails, LogsEndpointActionWithHosts } from '../../../../common/endpoint/types'; -import type { ResponseActionsSearchHit } from '../../../../common/search_strategy/security_solution/response_actions/types'; -import { SortOrder } from '../../../../common/search_strategy/security_solution/response_actions/types'; +import type { ResponseActionsSearchHit } from '../../../../common/search_strategy/endpoint/response_actions/types'; +import { SortOrder } from '../../../../common/search_strategy/endpoint/response_actions/types'; +import { ResponseActionsQueries } from '../../../../common/search_strategy/endpoint/response_actions'; import type { ActionResponsesRequestOptions, ActionRequestOptions, ActionRequestStrategyResponse, ActionResponsesRequestStrategyResponse, -} from '../../../../common/search_strategy/security_solution/response_actions'; -import { ResponseActionsQueries } from '../../../../common/search_strategy/security_solution/response_actions'; +} from '../../../../common/search_strategy/endpoint/response_actions'; import { useKibana } from '../../../common/lib/kibana'; import type { EndpointAutomatedActionListRequestQuery, @@ -52,7 +53,7 @@ export const useGetAutomatedActionList = ( factoryQueryType: ResponseActionsQueries.actions, }, { - strategy: 'securitySolutionSearchStrategy', + strategy: ENDPOINT_SEARCH_STRATEGY, } ) ); @@ -115,7 +116,7 @@ export const useGetAutomatedActionResponseList = ( factoryQueryType: ResponseActionsQueries.results, }, { - strategy: 'securitySolutionSearchStrategy', + strategy: ENDPOINT_SEARCH_STRATEGY, } ) ); diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index d8e51380fdf2..12603232a34a 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -17,6 +17,7 @@ import { Dataset } from '@kbn/rule-registry-plugin/server'; import type { ListPluginSetup } from '@kbn/lists-plugin/server'; import type { ILicense } from '@kbn/licensing-plugin/server'; +import { endpointSearchStrategyProvider } from './search_strategy/endpoint'; import { getScheduleNotificationResponseActionsService } from './lib/detection_engine/rule_response_actions/schedule_notification_response_actions'; import { siemGuideId, siemGuideConfig } from '../common/guided_onboarding/siem_guide_config'; import { @@ -88,7 +89,10 @@ import { actionCreateService } from './endpoint/services/actions'; import { setIsElasticCloudDeployment } from './lib/telemetry/helpers'; import { artifactService } from './lib/telemetry/artifact'; import { endpointFieldsProvider } from './search_strategy/endpoint_fields'; -import { ENDPOINT_FIELDS_SEARCH_STRATEGY } from '../common/endpoint/constants'; +import { + ENDPOINT_FIELDS_SEARCH_STRATEGY, + ENDPOINT_SEARCH_STRATEGY, +} from '../common/endpoint/constants'; import { AppFeatures } from './lib/app_features'; export type { SetupPlugins, StartPlugins, PluginSetup, PluginStart } from './plugin_contract'; @@ -351,6 +355,12 @@ export class Plugin implements ISecuritySolutionPlugin { 'securitySolutionSearchStrategy', securitySolutionSearchStrategy ); + const endpointSearchStrategy = endpointSearchStrategyProvider( + depsStart.data, + this.endpointContext + ); + + plugins.data.search.registerSearchStrategy(ENDPOINT_SEARCH_STRATEGY, endpointSearchStrategy); }); setIsElasticCloudDeployment(plugins.cloud.isCloudEnabled ?? false); diff --git a/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/index.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/index.ts new file mode 100644 index 000000000000..13387507f015 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/index.ts @@ -0,0 +1,18 @@ +/* + * 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 { EndpointFactoryQueryTypes } from '../../../../common/search_strategy/endpoint'; + +import { responseActionsFactory } from './response_actions'; +import type { EndpointFactory } from './types'; + +export const endpointFactory: Record< + EndpointFactoryQueryTypes, + EndpointFactory +> = { + ...responseActionsFactory, +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/actions/index.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/actions/index.ts similarity index 62% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/actions/index.ts rename to x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/actions/index.ts index 66790b731ea9..fbb57a0d22e1 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/actions/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/actions/index.ts @@ -6,26 +6,27 @@ */ import type { IEsSearchResponse } from '@kbn/data-plugin/common'; -import { inspectStringifyObject } from '../../../../../utils/build_query'; +import { inspectStringifyObject } from '@kbn/osquery-plugin/common/utils/build_query'; import { buildResponseActionsQuery } from './query.all_actions.dsl'; -import type { SecuritySolutionFactory } from '../../types'; +import type { EndpointFactory } from '../../types'; import type { ActionRequestOptions, ActionRequestStrategyResponse, ResponseActionsQueries, -} from '../../../../../../common/search_strategy/security_solution/response_actions'; +} from '../../../../../../common/search_strategy/endpoint/response_actions'; -export const allActions: SecuritySolutionFactory = { - buildDsl: (options: ActionRequestOptions) => { - return buildResponseActionsQuery(options); +export const allActions: EndpointFactory = { + buildDsl: (options: ActionRequestOptions, { authz }) => { + return buildResponseActionsQuery(options, authz); }, parse: async ( options: ActionRequestOptions, - response: IEsSearchResponse + response: IEsSearchResponse, + deps ): Promise => { const inspect = { - dsl: [inspectStringifyObject(buildResponseActionsQuery(options))], + dsl: [inspectStringifyObject(buildResponseActionsQuery(options, deps.authz))], }; return { diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/actions/query.all_actions.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/actions/query.all_actions.dsl.ts similarity index 65% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/actions/query.all_actions.dsl.ts rename to x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/actions/query.all_actions.dsl.ts index 0f0c45eb2081..0507dc6cde22 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/actions/query.all_actions.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/actions/query.all_actions.dsl.ts @@ -9,19 +9,31 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ISearchRequestParams } from '@kbn/data-plugin/common'; import { OSQUERY_ACTIONS_INDEX } from '@kbn/osquery-plugin/common/constants'; -import type { ActionRequestOptions } from '../../../../../../common/search_strategy/security_solution/response_actions'; +import type { EndpointAuthz } from '../../../../../../common/endpoint/types/authz'; +import type { ActionRequestOptions } from '../../../../../../common/search_strategy/endpoint/response_actions'; import { ENDPOINT_ACTIONS_INDEX } from '../../../../../../common/endpoint/constants'; -export const buildResponseActionsQuery = ({ - alertIds, - sort, -}: ActionRequestOptions): ISearchRequestParams => { +const EndpointFieldsLimited = [ + 'EndpointActions.action_id', + 'EndpointActions.input_type', + 'EndpointActions.expiration', + 'EndpointActions.data.command', +]; + +export const buildResponseActionsQuery = ( + { alertIds, sort }: ActionRequestOptions, + authz: EndpointAuthz | void +): ISearchRequestParams => { + const fields = authz?.canAccessEndpointActionsLogManagement + ? [{ field: '*' }, { field: 'EndpointActions.*', include_unmapped: true }] + : ['@timestamp', 'action_id', 'input_type', ...EndpointFieldsLimited]; + const dslQuery = { allow_no_indices: true, index: [ENDPOINT_ACTIONS_INDEX, OSQUERY_ACTIONS_INDEX], ignore_unavailable: true, body: { - fields: [{ field: '*' }, { field: 'EndpointActions.*', include_unmapped: true }], + fields, query: { bool: { minimum_should_match: 2, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/index.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/index.ts similarity index 71% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/index.ts rename to x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/index.ts index a9eb802b6244..c1dc1f67da05 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/index.ts @@ -5,15 +5,15 @@ * 2.0. */ -import type { FactoryQueryTypes } from '../../../../../common/search_strategy'; -import { ResponseActionsQueries } from '../../../../../common/search_strategy/security_solution/response_actions'; -import type { SecuritySolutionFactory } from '../types'; +import { ResponseActionsQueries } from '../../../../../common/search_strategy/endpoint/response_actions'; import { allActions } from './actions'; import { actionResults } from './results'; +import type { EndpointFactory } from '../types'; +import type { EndpointFactoryQueryTypes } from '../../../../../common/search_strategy/endpoint'; export const responseActionsFactory: Record< ResponseActionsQueries, - SecuritySolutionFactory + EndpointFactory > = { [ResponseActionsQueries.actions]: allActions, [ResponseActionsQueries.results]: actionResults, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/results/index.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/results/index.ts similarity index 89% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/results/index.ts rename to x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/results/index.ts index cc3d0fdda462..705018f001ac 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/results/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/results/index.ts @@ -10,12 +10,12 @@ import type { ActionResponsesRequestOptions, ActionResponsesRequestStrategyResponse, ResponseActionsQueries, -} from '../../../../../../common/search_strategy/security_solution/response_actions'; +} from '../../../../../../common/search_strategy/endpoint/response_actions'; import { buildActionResultsQuery } from './query.action_results.dsl'; -import type { SecuritySolutionFactory } from '../../types'; +import type { EndpointFactory } from '../../types'; -export const actionResults: SecuritySolutionFactory = { +export const actionResults: EndpointFactory = { buildDsl: (options: ActionResponsesRequestOptions) => { return buildActionResultsQuery(options); }, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/results/query.action_results.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/results/query.action_results.dsl.ts similarity index 96% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/results/query.action_results.dsl.ts rename to x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/results/query.action_results.dsl.ts index 80758a18513b..5b9c7558ce97 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/response_actions/results/query.action_results.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/response_actions/results/query.action_results.dsl.ts @@ -6,7 +6,7 @@ */ import type { ISearchRequestParams } from '@kbn/data-plugin/common'; -import type { ActionResponsesRequestOptions } from '../../../../../../common/search_strategy/security_solution/response_actions'; +import type { ActionResponsesRequestOptions } from '../../../../../../common/search_strategy/endpoint/response_actions'; import { ENDPOINT_ACTION_RESPONSES_INDEX } from '../../../../../../common/endpoint/constants'; export const buildActionResultsQuery = ({ diff --git a/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/types.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/types.ts new file mode 100644 index 000000000000..481be3fb32db --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/factory/types.ts @@ -0,0 +1,31 @@ +/* + * 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 { ISearchRequestParams } from '@kbn/data-plugin/common'; +import type { + EndpointFactoryQueryTypes, + EndpointStrategyParseResponseType, + EndpointStrategyRequestType, + EndpointStrategyResponseType, +} from '../../../../common/search_strategy/endpoint'; +import type { EndpointAuthz } from '../../../../common/endpoint/types/authz'; + +export interface EndpointFactory { + buildDsl: ( + options: EndpointStrategyRequestType, + deps: { + authz: EndpointAuthz | undefined; + } + ) => ISearchRequestParams; + parse: ( + options: EndpointStrategyRequestType, + response: EndpointStrategyParseResponseType, + deps: { + authz: EndpointAuthz | undefined; + } + ) => Promise>; +} diff --git a/x-pack/plugins/security_solution/server/search_strategy/endpoint/index.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint/index.ts new file mode 100644 index 000000000000..9638c44ee177 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint/index.ts @@ -0,0 +1,79 @@ +/* + * 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 { map, mergeMap } from 'rxjs/operators'; +import type { ISearchStrategy, PluginStart } from '@kbn/data-plugin/server'; +import { shimHitsTotal } from '@kbn/data-plugin/server'; +import { ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; +import { from } from 'rxjs'; +import type { + EndpointStrategyParseResponseType, + EndpointStrategyRequestType, + EndpointStrategyResponseType, + EndpointFactoryQueryTypes, +} from '../../../common/search_strategy/endpoint'; +import type { EndpointFactory } from './factory/types'; + +import type { EndpointAppContext } from '../../endpoint/types'; +import { endpointFactory } from './factory'; + +function isObj(req: unknown): req is Record { + return typeof req === 'object' && req !== null; +} + +function assertValidRequestType( + req: unknown +): asserts req is EndpointStrategyRequestType & { factoryQueryType: EndpointFactoryQueryTypes } { + if (!isObj(req) || req.factoryQueryType == null) { + throw new Error('factoryQueryType is required'); + } +} + +export const endpointSearchStrategyProvider = ( + data: PluginStart, + endpointContext: EndpointAppContext +): ISearchStrategy, EndpointStrategyResponseType> => { + const es = data.search.getSearchStrategy( + ENHANCED_ES_SEARCH_STRATEGY + ) as unknown as ISearchStrategy< + EndpointStrategyRequestType, + EndpointStrategyParseResponseType + >; + + return { + search: (request, options, deps) => { + assertValidRequestType(request); + + return from(endpointContext.service.getEndpointAuthz(deps.request)).pipe( + mergeMap((authz) => { + const queryFactory: EndpointFactory = endpointFactory[request.factoryQueryType]; + const dsl = queryFactory.buildDsl(request, { authz }); + return es.search({ ...request, params: dsl }, options, deps).pipe( + map((response) => { + return { + ...response, + ...{ + rawResponse: shimHitsTotal(response.rawResponse, options), + }, + }; + }), + mergeMap((esSearchRes) => + queryFactory.parse(request, esSearchRes, { + authz, + }) + ) + ); + }) + ); + }, + cancel: async (id, options, deps) => { + if (es.cancel) { + return es.cancel(id, options, deps); + } + }, + }; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/index.ts index a24c22aa8dfe..af94f47be89d 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/index.ts @@ -16,7 +16,6 @@ import { riskScoreFactory } from './risk_score'; import { usersFactory } from './users'; import { firstLastSeenFactory } from './last_first_seen'; import { relatedEntitiesFactory } from './related_entities'; -import { responseActionsFactory } from './response_actions'; export const securitySolutionFactory: Record< FactoryQueryTypes, @@ -30,5 +29,4 @@ export const securitySolutionFactory: Record< ...riskScoreFactory, ...firstLastSeenFactory, ...relatedEntitiesFactory, - ...responseActionsFactory, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts index 4864bde28854..f222e2130ee2 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts @@ -10,13 +10,12 @@ import type { KibanaRequest, SavedObjectsClientContract, } from '@kbn/core/server'; -import type { ISearchRequestParams } from '@kbn/data-plugin/common'; +import type { IEsSearchResponse, ISearchRequestParams } from '@kbn/data-plugin/common'; import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import type { FactoryQueryTypes, StrategyRequestType, StrategyResponseType, - StrategyParseResponseType, } from '../../../../common/search_strategy/security_solution'; import type { EndpointAppContext } from '../../../endpoint/types'; @@ -24,7 +23,7 @@ export interface SecuritySolutionFactory { buildDsl: (options: StrategyRequestType) => ISearchRequestParams; parse: ( options: StrategyRequestType, - response: StrategyParseResponseType, + response: IEsSearchResponse, deps?: { esClient: IScopedClusterClient; savedObjectsClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts index f513d07d4c04..1acb6687b8ac 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts @@ -15,7 +15,6 @@ import type { FactoryQueryTypes, StrategyResponseType, StrategyRequestType, - StrategyParseResponseType, } from '../../../common/search_strategy/security_solution'; import { securitySolutionFactory } from './factory'; import type { SecuritySolutionFactory } from './factory/types'; @@ -38,9 +37,7 @@ export const securitySolutionSearchStrategyProvider = string, ruleDataClient?: IRuleDataClient | null ): ISearchStrategy, StrategyResponseType> => { - const es = data.search.getSearchStrategy( - ENHANCED_ES_SEARCH_STRATEGY - ) as unknown as ISearchStrategy, StrategyParseResponseType>; + const es = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY); return { search: (request, options, deps) => {