[Defend Workflows] Limit endpoint fields in the query in automated response actions (#158704)

This commit is contained in:
Tomasz Ciecierski 2023-06-14 15:00:38 +02:00 committed by GitHub
parent 0d6657f831
commit 1a70ede796
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 245 additions and 76 deletions

View file

@ -37,7 +37,7 @@ export const OsqueryResult = React.memo<OsqueryResultProps>(
<AlertAttachmentContext.Provider value={ecsData}>
<EuiSpacer size="s" />
<EuiComment
username={ruleName && ruleName[0]}
username={ruleName}
timestamp={<FormattedRelative value={startDate} />}
event={ATTACHED_QUERY}
data-test-subj={'osquery-results-comment'}

View file

@ -40,7 +40,7 @@ const OsqueryResultComponent = React.memo<OsqueryActionResultProps>(
return (
<AlertAttachmentContext.Provider value={ecsData}>
<EuiComment
username={ruleName && ruleName[0]}
username={ruleName}
timestamp={<FormattedRelative value={startDate} />}
event={ATTACHED_QUERY}
data-test-subj={'osquery-results-comment'}

View file

@ -32,7 +32,7 @@ const enablePrivileges = () => {
};
const defaultProps: OsqueryActionResultsProps = {
ruleName: ['Test-rule'],
ruleName: 'Test-rule',
actionItems: [
{
_id: 'test',

View file

@ -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;

View file

@ -102,3 +102,4 @@ export const ENDPOINT_ERROR_CODES: Record<string, number> = {
};
export const ENDPOINT_FIELDS_SEARCH_STRATEGY = 'endpointFields';
export const ENDPOINT_SEARCH_STRATEGY = 'endpointSearchStrategy';

View file

@ -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 EndpointFactoryQueryTypes> =
T extends ResponseActionsQueries.results
? ActionResponsesRequestStrategyParseResponse
: IEsSearchResponse;
export type EndpointStrategyResponseType<T extends EndpointFactoryQueryTypes> =
T extends ResponseActionsQueries.actions
? ActionRequestStrategyResponse
: T extends ResponseActionsQueries.results
? ActionResponsesRequestStrategyResponse
: never;
export type EndpointStrategyRequestType<T extends EndpointFactoryQueryTypes> =
T extends ResponseActionsQueries.actions
? ActionRequestOptions
: T extends ResponseActionsQueries.results
? ActionResponsesRequestOptions
: never;

View file

@ -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<Field = string> extends RequestBasicOpt
sort: SortField<Field>;
}
export type StrategyParseResponseType<T extends FactoryQueryTypes> =
T extends ResponseActionsQueries.results
? ActionResponsesRequestStrategyParseResponse
: IEsSearchResponse;
export type StrategyResponseType<T extends FactoryQueryTypes> = T extends HostsQueries.hosts
? HostsStrategyResponse
: T extends HostsQueries.details
@ -230,10 +216,6 @@ export type StrategyResponseType<T extends FactoryQueryTypes> = 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 FactoryQueryTypes> = T extends HostsQueries.hosts
@ -304,10 +286,6 @@ export type StrategyRequestType<T extends FactoryQueryTypes> = T extends HostsQu
? UsersRelatedHostsRequestOptions
: T extends RelatedEntitiesQueries.relatedUsers
? HostsRelatedUsersRequestOptions
: T extends ResponseActionsQueries.actions
? ActionRequestOptions
: T extends ResponseActionsQueries.results
? ActionResponsesRequestOptions
: never;
export interface CommonFields {

View file

@ -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 = (
<TabContentWrapper data-test-subj="osqueryViewWrapper">

View file

@ -36,7 +36,6 @@ export const useResponseActionsView = <T extends object = JSX.Element>({
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 = <T extends object = JSX.Element>({
return;
}
const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name;
const ruleName = expandedEventFieldsObject?.kibana?.alert?.rule?.name?.[0];
const totalItemCount = automatedList?.items?.length ?? 0;

View file

@ -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 (
<EuiComment
username={rule?.name}
username={ruleName}
timestamp={<FormattedRelative value={action['@timestamp']} />}
event={eventText}
data-test-subj={'endpoint-results-comment'}

View file

@ -18,7 +18,7 @@ import { useKibana } from '../../lib/kibana';
interface ResponseActionsResultsProps {
actions: Array<LogsEndpointActionWithHosts | LogsOsqueryAction>;
ruleName?: string[];
ruleName?: string;
ecsData?: Ecs | null;
}
@ -47,7 +47,11 @@ export const ResponseActionsResults = React.memo(
}
if (isEndpoint(action)) {
return (
<EndpointResponseActionResults action={action} key={action.EndpointActions.action_id} />
<EndpointResponseActionResults
action={action}
ruleName={ruleName}
key={action.EndpointActions.action_id}
/>
);
}
return null;

View file

@ -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,
}
)
);

View file

@ -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);

View file

@ -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<EndpointFactoryQueryTypes>
> = {
...responseActionsFactory,
};

View file

@ -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<ResponseActionsQueries.actions> = {
buildDsl: (options: ActionRequestOptions) => {
return buildResponseActionsQuery(options);
export const allActions: EndpointFactory<ResponseActionsQueries.actions> = {
buildDsl: (options: ActionRequestOptions, { authz }) => {
return buildResponseActionsQuery(options, authz);
},
parse: async (
options: ActionRequestOptions,
response: IEsSearchResponse
response: IEsSearchResponse,
deps
): Promise<ActionRequestStrategyResponse> => {
const inspect = {
dsl: [inspectStringifyObject(buildResponseActionsQuery(options))],
dsl: [inspectStringifyObject(buildResponseActionsQuery(options, deps.authz))],
};
return {

View file

@ -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,

View file

@ -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<FactoryQueryTypes>
EndpointFactory<EndpointFactoryQueryTypes>
> = {
[ResponseActionsQueries.actions]: allActions,
[ResponseActionsQueries.results]: actionResults,

View file

@ -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<ResponseActionsQueries.results> = {
export const actionResults: EndpointFactory<ResponseActionsQueries.results> = {
buildDsl: (options: ActionResponsesRequestOptions) => {
return buildActionResultsQuery(options);
},

View file

@ -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 = ({

View file

@ -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<T extends EndpointFactoryQueryTypes> {
buildDsl: (
options: EndpointStrategyRequestType<T>,
deps: {
authz: EndpointAuthz | undefined;
}
) => ISearchRequestParams;
parse: (
options: EndpointStrategyRequestType<T>,
response: EndpointStrategyParseResponseType<T>,
deps: {
authz: EndpointAuthz | undefined;
}
) => Promise<EndpointStrategyResponseType<T>>;
}

View file

@ -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<string, unknown> {
return typeof req === 'object' && req !== null;
}
function assertValidRequestType<T extends EndpointFactoryQueryTypes>(
req: unknown
): asserts req is EndpointStrategyRequestType<T> & { factoryQueryType: EndpointFactoryQueryTypes } {
if (!isObj(req) || req.factoryQueryType == null) {
throw new Error('factoryQueryType is required');
}
}
export const endpointSearchStrategyProvider = <T extends EndpointFactoryQueryTypes>(
data: PluginStart,
endpointContext: EndpointAppContext
): ISearchStrategy<EndpointStrategyRequestType<T>, EndpointStrategyResponseType<T>> => {
const es = data.search.getSearchStrategy(
ENHANCED_ES_SEARCH_STRATEGY
) as unknown as ISearchStrategy<
EndpointStrategyRequestType<T>,
EndpointStrategyParseResponseType<T>
>;
return {
search: (request, options, deps) => {
assertValidRequestType<T>(request);
return from(endpointContext.service.getEndpointAuthz(deps.request)).pipe(
mergeMap((authz) => {
const queryFactory: EndpointFactory<T> = 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);
}
},
};
};

View file

@ -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,
};

View file

@ -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<T extends FactoryQueryTypes> {
buildDsl: (options: StrategyRequestType<T>) => ISearchRequestParams;
parse: (
options: StrategyRequestType<T>,
response: StrategyParseResponseType<T>,
response: IEsSearchResponse,
deps?: {
esClient: IScopedClusterClient;
savedObjectsClient: SavedObjectsClientContract;

View file

@ -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 = <T extends FactoryQueryTyp
getSpaceId?: (request: KibanaRequest) => string,
ruleDataClient?: IRuleDataClient | null
): ISearchStrategy<StrategyRequestType<T>, StrategyResponseType<T>> => {
const es = data.search.getSearchStrategy(
ENHANCED_ES_SEARCH_STRATEGY
) as unknown as ISearchStrategy<StrategyRequestType<T>, StrategyParseResponseType<T>>;
const es = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY);
return {
search: (request, options, deps) => {