From 6dbc4be8f7f418315a96532562fad683c7a493d4 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Sat, 22 Aug 2020 08:59:14 -0400 Subject: [PATCH] [SECURITY SOLUTION] Add our first search strategy for all host query (#75439) * add security solution search strategy on server side * get security solution search strategy in the public app for all host * fix types * fix Check core API changes * thank you cypress test * Remove any by the right type IESearchRequest Co-authored-by: Lukas Olson * add translation and filter error when we abort the query * pr review * fix translation * review II * fix merge issue Co-authored-by: Elastic Machine Co-authored-by: Lukas Olson --- ...kibana-plugin-core-public.doclinksstart.md | 2 +- ...n-plugins-data-public.iessearchresponse.md | 4 +- ...ta-public.iessearchresponse.rawresponse.md | 2 +- ...ugin-plugins-data-public.isearchgeneric.md | 2 +- ...n-plugins-data-server.iessearchresponse.md | 4 +- ...ta-server.iessearchresponse.rawresponse.md | 2 +- ...plugin-plugins-data-server.isearchsetup.md | 2 +- ...ver.isearchsetup.registersearchstrategy.md | 2 +- ...a-server.isearchstart.getsearchstrategy.md | 2 +- ...plugin-plugins-data-server.isearchstart.md | 4 +- ...gin-plugins-data-server.isearchstrategy.md | 4 +- ...gins-data-server.isearchstrategy.search.md | 2 +- ...plugin-plugins-data-server.plugin.start.md | 4 +- .../data/common/search/es_search/types.ts | 4 +- src/plugins/data/public/public.api.md | 6 +- .../data/public/search/search_interceptor.ts | 2 +- .../data/public/search/search_service.ts | 4 +- src/plugins/data/public/search/types.ts | 9 +- src/plugins/data/server/search/routes.test.ts | 4 +- src/plugins/data/server/search/routes.ts | 12 +- .../data/server/search/search_service.ts | 19 +- src/plugins/data/server/search/types.ts | 26 +- src/plugins/data/server/server.api.md | 16 +- .../public/search/search_interceptor.ts | 2 +- .../common/ecs/auditd/index.ts | 45 +++ .../common/ecs/cloud/index.ts | 20 ++ .../common/ecs/destination/index.ts | 21 ++ .../security_solution/common/ecs/dns/index.ts | 19 + .../common/ecs/endgame/index.ts | 33 ++ .../common/ecs/event/index.ts | 45 +++ .../common/ecs/file/index.ts | 37 ++ .../security_solution/common/ecs/geo/index.ts | 27 ++ .../common/ecs/host/index.ts | 35 ++ .../common/ecs/http/index.ts | 37 ++ .../security_solution/common/ecs/index.ts | 78 +++++ .../common/ecs/network/index.ts | 19 + .../common/ecs/process/index.ts | 39 +++ .../common/ecs/rule/index.ts | 69 ++++ .../common/ecs/signal/index.ts | 13 + .../common/ecs/source/index.ts | 21 ++ .../common/ecs/suricata/index.ts | 23 ++ .../common/ecs/system/index.ts | 39 +++ .../security_solution/common/ecs/tls/index.ts | 33 ++ .../security_solution/common/ecs/url/index.ts | 15 + .../common/ecs/user/index.ts | 21 ++ .../common/ecs/winlog/index.ts | 9 + .../common/ecs/zeek/index.ts | 133 +++++++ .../security_solution/hosts/index.ts | 84 +++++ .../security_solution/index.ts | 109 ++++++ .../public/hosts/containers/hosts/index.tsx | 324 ++++++++++-------- .../hosts/containers/hosts/translations.ts | 21 ++ .../pages/navigation/hosts_query_tab_body.tsx | 56 ++- .../security_solution/server/plugin.ts | 13 + .../hosts/dsl/query.detail_host.dsl.ts | 49 +++ .../factory/hosts/dsl/query.hosts.dsl.ts | 89 +++++ .../dsl/query.last_first_seen_host.dsl.ts | 35 ++ .../factory/hosts/helpers.ts | 115 +++++++ .../security_solution/factory/hosts/index.ts | 92 +++++ .../security_solution/factory/index.ts | 17 + .../security_solution/factory/types.ts | 23 ++ .../security_solution/index.ts | 38 ++ .../server/utils/build_query/filters.ts | 2 +- .../server/utils/build_query/index.ts | 2 +- 63 files changed, 1802 insertions(+), 238 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/ecs/auditd/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/cloud/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/destination/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/dns/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/endgame/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/event/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/file/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/geo/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/host/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/http/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/network/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/process/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/rule/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/signal/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/source/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/suricata/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/system/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/tls/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/url/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/user/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/winlog/index.ts create mode 100644 x-pack/plugins/security_solution/common/ecs/zeek/index.ts create mode 100644 x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts create mode 100644 x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts create mode 100644 x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.detail_host.dsl.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.hosts.dsl.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.last_first_seen_host.dsl.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/helpers.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/index.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md index fa2d9090e3159..4644dc432bc9a 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md @@ -17,5 +17,5 @@ export interface DocLinksStart | --- | --- | --- | | [DOC\_LINK\_VERSION](./kibana-plugin-core-public.doclinksstart.doc_link_version.md) | string | | | [ELASTIC\_WEBSITE\_URL](./kibana-plugin-core-public.doclinksstart.elastic_website_url.md) | string | | -| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly dashboard: {
readonly drilldowns: string;
};
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly startup: string;
readonly exportedFields: string;
};
readonly auditbeat: {
readonly base: string;
};
readonly metricbeat: {
readonly base: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly date_histogram: string;
readonly date_range: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessSyntax: string;
readonly luceneExpressions: string;
};
readonly indexPatterns: {
readonly loadingData: string;
readonly introduction: string;
};
readonly addData: string;
readonly kibana: string;
readonly siem: {
readonly guide: string;
readonly gettingStarted: string;
};
readonly query: {
readonly luceneQuerySyntax: string;
readonly queryDsl: string;
readonly kueryQuerySyntax: string;
};
readonly date: {
readonly dateMath: string;
};
readonly management: Record<string, string>;
} | | +| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly dashboard: {
readonly drilldowns: string;
};
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly startup: string;
readonly exportedFields: string;
};
readonly auditbeat: {
readonly base: string;
};
readonly metricbeat: {
readonly base: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly date_histogram: string;
readonly date_range: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessSyntax: string;
readonly luceneExpressions: string;
};
readonly indexPatterns: {
readonly loadingData: string;
readonly introduction: string;
};
readonly addData: string;
readonly kibana: string;
readonly siem: {
readonly guide: string;
readonly gettingStarted: string;
};
readonly query: {
readonly luceneQuerySyntax: string;
readonly queryDsl: string;
readonly kueryQuerySyntax: string;
};
readonly date: {
readonly dateMath: string;
};
readonly management: Record<string, string>;
readonly visualize: Record<string, string>;
} | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.md index 041d79de3282e..7c9a6aa702463 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.md @@ -7,7 +7,7 @@ Signature: ```typescript -export interface IEsSearchResponse extends IKibanaSearchResponse +export interface IEsSearchResponse extends IKibanaSearchResponse ``` ## Properties @@ -16,5 +16,5 @@ export interface IEsSearchResponse extends IKibanaSearchResponse | --- | --- | --- | | [isPartial](./kibana-plugin-plugins-data-public.iessearchresponse.ispartial.md) | boolean | Indicates whether the results returned are complete or partial | | [isRunning](./kibana-plugin-plugins-data-public.iessearchresponse.isrunning.md) | boolean | Indicates whether async search is still in flight | -| [rawResponse](./kibana-plugin-plugins-data-public.iessearchresponse.rawresponse.md) | SearchResponse<any> | | +| [rawResponse](./kibana-plugin-plugins-data-public.iessearchresponse.rawresponse.md) | SearchResponse<Source> | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.rawresponse.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.rawresponse.md index d7912f377ca9f..f4648143ebc2e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.rawresponse.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iessearchresponse.rawresponse.md @@ -7,5 +7,5 @@ Signature: ```typescript -rawResponse: SearchResponse; +rawResponse: SearchResponse; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md index 3bd6a398c8df5..861b59e73ef04 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type ISearchGeneric = (request: IEsSearchRequest, options?: ISearchOptions) => Observable; +export declare type ISearchGeneric = (request: SearchStrategyRequest, options?: ISearchOptions) => Observable; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.md index 0407dce5fe418..55c0399e90e2f 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.md @@ -7,7 +7,7 @@ Signature: ```typescript -export interface IEsSearchResponse extends IKibanaSearchResponse +export interface IEsSearchResponse extends IKibanaSearchResponse ``` ## Properties @@ -16,5 +16,5 @@ export interface IEsSearchResponse extends IKibanaSearchResponse | --- | --- | --- | | [isPartial](./kibana-plugin-plugins-data-server.iessearchresponse.ispartial.md) | boolean | Indicates whether the results returned are complete or partial | | [isRunning](./kibana-plugin-plugins-data-server.iessearchresponse.isrunning.md) | boolean | Indicates whether async search is still in flight | -| [rawResponse](./kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md) | SearchResponse<any> | | +| [rawResponse](./kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md) | SearchResponse<Source> | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md index 0ee1691d0f697..9987debfa551c 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md @@ -7,5 +7,5 @@ Signature: ```typescript -rawResponse: SearchResponse; +rawResponse: SearchResponse; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md index e5b11a0b997ea..ac2ae13372f7a 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md @@ -15,6 +15,6 @@ export interface ISearchSetup | Property | Type | Description | | --- | --- | --- | | [aggs](./kibana-plugin-plugins-data-server.isearchsetup.aggs.md) | AggsSetup | | -| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | (name: string, strategy: ISearchStrategy) => void | Extension point exposed for other plugins to register their own search strategies. | +| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | <SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse>(name: string, strategy: ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse>) => void | Extension point exposed for other plugins to register their own search strategies. | | [usage](./kibana-plugin-plugins-data-server.isearchsetup.usage.md) | SearchUsage | Used internally for telemetry | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md index 73c575e7095ed..f20c6f4911062 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md @@ -9,5 +9,5 @@ Extension point exposed for other plugins to register their own search strategie Signature: ```typescript -registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void; +registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md index 970b2811a574b..398ea21641942 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md @@ -9,5 +9,5 @@ Get other registered search strategies. For example, if a new strategy needs to Signature: ```typescript -getSearchStrategy: (name: string) => ISearchStrategy; +getSearchStrategy: (name: string) => ISearchStrategy; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md index 3762da963d4d9..62d954cb80eb7 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md @@ -7,7 +7,7 @@ Signature: ```typescript -export interface ISearchStart +export interface ISearchStart ``` ## Properties @@ -15,6 +15,6 @@ export interface ISearchStart | Property | Type | Description | | --- | --- | --- | | [aggs](./kibana-plugin-plugins-data-server.isearchstart.aggs.md) | AggsStart | | -| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | (name: string) => ISearchStrategy | Get other registered search strategies. For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. | +| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | (name: string) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse> | Get other registered search strategies. For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. | | [search](./kibana-plugin-plugins-data-server.isearchstart.search.md) | (context: RequestHandlerContext, request: IKibanaSearchRequest, options: ISearchOptions) => Promise<IKibanaSearchResponse> | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md index d54e027c4b847..dc076455ab272 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md @@ -9,7 +9,7 @@ Search strategy interface contains a search method that takes in a request and r Signature: ```typescript -export interface ISearchStrategy +export interface ISearchStrategy ``` ## Properties @@ -17,5 +17,5 @@ export interface ISearchStrategy | Property | Type | Description | | --- | --- | --- | | [cancel](./kibana-plugin-plugins-data-server.isearchstrategy.cancel.md) | (context: RequestHandlerContext, id: string) => Promise<void> | | -| [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) | (context: RequestHandlerContext, request: IEsSearchRequest, options?: ISearchOptions) => Promise<IEsSearchResponse> | | +| [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) | (context: RequestHandlerContext, request: SearchStrategyRequest, options?: ISearchOptions) => Promise<SearchStrategyResponse> | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md index 1a225d0c9aeab..45f43648ab603 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md @@ -7,5 +7,5 @@ Signature: ```typescript -search: (context: RequestHandlerContext, request: IEsSearchRequest, options?: ISearchOptions) => Promise; +search: (context: RequestHandlerContext, request: SearchStrategyRequest, options?: ISearchOptions) => Promise; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 74bffc516725f..2d9104ef894bc 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md @@ -8,7 +8,7 @@ ```typescript start(core: CoreStart): { - search: ISearchStart; + search: ISearchStart>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; @@ -27,7 +27,7 @@ start(core: CoreStart): { Returns: `{ - search: ISearchStart; + search: ISearchStart>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; diff --git a/src/plugins/data/common/search/es_search/types.ts b/src/plugins/data/common/search/es_search/types.ts index 8853e40dd0ad2..654ed3899656d 100644 --- a/src/plugins/data/common/search/es_search/types.ts +++ b/src/plugins/data/common/search/es_search/types.ts @@ -31,7 +31,7 @@ export interface IEsSearchRequest extends IKibanaSearchRequest { indexType?: string; } -export interface IEsSearchResponse extends IKibanaSearchResponse { +export interface IEsSearchResponse extends IKibanaSearchResponse { /** * Indicates whether async search is still in flight */ @@ -40,5 +40,5 @@ export interface IEsSearchResponse extends IKibanaSearchResponse { * Indicates whether the results returned are complete or partial */ isPartial?: boolean; - rawResponse: SearchResponse; + rawResponse: SearchResponse; } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 7defddb8f570a..35ee1789b2fdf 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -791,11 +791,11 @@ export interface IEsSearchRequest extends IKibanaSearchRequest { // Warning: (ae-missing-release-tag) "IEsSearchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface IEsSearchResponse extends IKibanaSearchResponse { +export interface IEsSearchResponse extends IKibanaSearchResponse { isPartial?: boolean; isRunning?: boolean; // (undocumented) - rawResponse: SearchResponse_2; + rawResponse: SearchResponse_2; } // Warning: (ae-missing-release-tag) "IFieldFormat" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1240,7 +1240,7 @@ export type ISearch = (request: IKibanaSearchRequest, options?: ISearchOptions) // Warning: (ae-missing-release-tag) "ISearchGeneric" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ISearchGeneric = (request: IEsSearchRequest, options?: ISearchOptions) => Observable; +export type ISearchGeneric = (request: SearchStrategyRequest, options?: ISearchOptions) => Observable; // Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 99fccda7fddf3..30e509edd4987 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -106,7 +106,7 @@ export class SearchInterceptor { ): Observable { const { id, ...searchRequest } = request; const path = trimEnd(`/internal/search/${strategy || ES_SEARCH_STRATEGY}/${id || ''}`, '/'); - const body = JSON.stringify(id != null ? {} : searchRequest); + const body = JSON.stringify(searchRequest); return from( this.deps.http.fetch({ method: 'POST', diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index a65b2b4b71f20..9a30a15936fe5 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -103,9 +103,9 @@ export class SearchService implements Plugin { { application, http, injectedMetadata, notifications, uiSettings }: CoreStart, { fieldFormats, indexPatterns }: SearchServiceStartDependencies ): ISearchStart { - const search: ISearchGeneric = (request, options) => { + const search = ((request, options) => { return this.searchInterceptor.search(request, options); - }; + }) as ISearchGeneric; const legacySearch = { esClient: this.esClient!, diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index d1a4437943402..55726e40f5a77 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -43,10 +43,13 @@ export type ISearch = ( options?: ISearchOptions ) => Observable; -export type ISearchGeneric = ( - request: IEsSearchRequest, +export type ISearchGeneric = < + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse +>( + request: SearchStrategyRequest, options?: ISearchOptions -) => Observable; +) => Observable; export interface ISearchStartLegacy { esClient: LegacyApiCaller; diff --git a/src/plugins/data/server/search/routes.test.ts b/src/plugins/data/server/search/routes.test.ts index 167bd5af5d51d..d91aeee1fe818 100644 --- a/src/plugins/data/server/search/routes.test.ts +++ b/src/plugins/data/server/search/routes.test.ts @@ -36,7 +36,7 @@ describe('Search service', () => { const response = { id: 'yay' }; mockDataStart.search.search.mockResolvedValue(response); const mockContext = {}; - const mockBody = { params: {} }; + const mockBody = { id: undefined, params: {} }; const mockParams = { strategy: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ body: mockBody, @@ -67,7 +67,7 @@ describe('Search service', () => { }); const mockContext = {}; - const mockBody = { params: {} }; + const mockBody = { id: undefined, params: {} }; const mockParams = { strategy: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ body: mockBody, diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes.ts index 32d8f8c1b09e0..3d813f745305f 100644 --- a/src/plugins/data/server/search/routes.ts +++ b/src/plugins/data/server/search/routes.ts @@ -47,10 +47,14 @@ export function registerSearchRoute(core: CoreSetup): v const [, , selfStart] = await core.getStartServices(); try { - const response = await selfStart.search.search(context, id ? { id } : searchRequest, { - signal, - strategy, - }); + const response = await selfStart.search.search( + context, + { ...searchRequest, id }, + { + signal, + strategy, + } + ); return res.ok({ body: response }); } catch (err) { return res.customError({ diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 5643406932552..cc23c455bed26 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -37,11 +37,12 @@ import { UsageCollectionSetup } from '../../../usage_collection/server'; import { registerUsageCollector } from './collectors/register'; import { usageProvider } from './collectors/usage'; import { searchTelemetry } from '../saved_objects'; -import { IEsSearchRequest } from '../../common'; +import { IEsSearchRequest, IEsSearchResponse } from '../../common'; -interface StrategyMap { - [name: string]: ISearchStrategy; -} +type StrategyMap< + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse +> = Record>; /** @internal */ export interface SearchServiceSetupDependencies { @@ -56,7 +57,7 @@ export interface SearchServiceStartDependencies { export class SearchService implements Plugin { private readonly aggsService = new AggsService(); - private searchStrategies: StrategyMap = {}; + private searchStrategies: StrategyMap = {}; constructor( private initializerContext: PluginInitializerContext, @@ -125,7 +126,13 @@ export class SearchService implements Plugin { this.aggsService.stop(); } - private registerSearchStrategy = (name: string, strategy: ISearchStrategy) => { + private registerSearchStrategy = < + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse + >( + name: string, + strategy: ISearchStrategy + ) => { this.logger.debug(`Register strategy ${name}`); this.searchStrategies[name] = strategy; }; diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index fe54975d76624..56f803512aa19 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -37,7 +37,13 @@ export interface ISearchSetup { * Extension point exposed for other plugins to register their own search * strategies. */ - registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void; + registerSearchStrategy: < + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse + >( + name: string, + strategy: ISearchStrategy + ) => void; /** * Used internally for telemetry @@ -45,13 +51,18 @@ export interface ISearchSetup { usage?: SearchUsage; } -export interface ISearchStart { +export interface ISearchStart< + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse +> { aggs: AggsStart; /** * Get other registered search strategies. For example, if a new strategy needs to use the * already-registered ES search strategy, it can use this function to accomplish that. */ - getSearchStrategy: (name: string) => ISearchStrategy; + getSearchStrategy: ( + name: string + ) => ISearchStrategy; search: ( context: RequestHandlerContext, request: IKibanaSearchRequest, @@ -63,11 +74,14 @@ export interface ISearchStart { * Search strategy interface contains a search method that takes in a request and returns a promise * that resolves to a response. */ -export interface ISearchStrategy { +export interface ISearchStrategy< + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse +> { search: ( context: RequestHandlerContext, - request: IEsSearchRequest, + request: SearchStrategyRequest, options?: ISearchOptions - ) => Promise; + ) => Promise; cancel?: (context: RequestHandlerContext, id: string) => Promise; } diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index f0a0d2763ff23..f870030ae9562 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -498,11 +498,11 @@ export interface IEsSearchRequest extends IKibanaSearchRequest { // Warning: (ae-missing-release-tag) "IEsSearchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface IEsSearchResponse extends IKibanaSearchResponse { +export interface IEsSearchResponse extends IKibanaSearchResponse { isPartial?: boolean; isRunning?: boolean; // (undocumented) - rawResponse: SearchResponse; + rawResponse: SearchResponse; } // Warning: (ae-missing-release-tag) "IFieldFormatsRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -689,19 +689,19 @@ export interface ISearchSetup { // // (undocumented) aggs: AggsSetup; - registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void; + registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void; usage?: SearchUsage; } // Warning: (ae-missing-release-tag) "ISearchStart" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface ISearchStart { +export interface ISearchStart { // Warning: (ae-forgotten-export) The symbol "AggsStart" needs to be exported by the entry point index.d.ts // // (undocumented) aggs: AggsStart; - getSearchStrategy: (name: string) => ISearchStrategy; + getSearchStrategy: (name: string) => ISearchStrategy; // Warning: (ae-forgotten-export) The symbol "RequestHandlerContext" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -711,11 +711,11 @@ export interface ISearchStart { // Warning: (ae-missing-release-tag) "ISearchStrategy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export interface ISearchStrategy { +export interface ISearchStrategy { // (undocumented) cancel?: (context: RequestHandlerContext, id: string) => Promise; // (undocumented) - search: (context: RequestHandlerContext, request: IEsSearchRequest, options?: ISearchOptions) => Promise; + search: (context: RequestHandlerContext, request: SearchStrategyRequest, options?: ISearchOptions) => Promise; } // @public (undocumented) @@ -862,7 +862,7 @@ export class Plugin implements Plugin_2>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts index ae6dddf33536f..47099e32fcc72 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts @@ -96,7 +96,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { return timer(pollInterval).pipe( // Send future requests using just the ID from the response mergeMap(() => { - return this.runSearch({ id }, combinedSignal, options?.strategy); + return this.runSearch({ ...request, id }, combinedSignal, options?.strategy); }) ); }), diff --git a/x-pack/plugins/security_solution/common/ecs/auditd/index.ts b/x-pack/plugins/security_solution/common/ecs/auditd/index.ts new file mode 100644 index 0000000000000..4b170eec98c02 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/auditd/index.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface AuditdEcs { + result?: string[]; + + session?: string[]; + + data?: AuditdDataEcs; + + summary?: SummaryEcs; + + sequence?: string[]; +} + +export interface AuditdDataEcs { + acct?: string[]; + + terminal?: string[]; + + op?: string[]; +} + +export interface SummaryEcs { + actor?: PrimarySecondaryEcs; + + object?: PrimarySecondaryEcs; + + how?: string[]; + + message_type?: string[]; + + sequence?: string[]; +} + +export interface PrimarySecondaryEcs { + primary?: string[]; + + secondary?: string[]; + + type?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/cloud/index.ts b/x-pack/plugins/security_solution/common/ecs/cloud/index.ts new file mode 100644 index 0000000000000..812b30bcc13f1 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/cloud/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface CloudEcs { + instance?: CloudInstanceEcs; + machine?: CloudMachineEcs; + provider?: string[]; + region?: string[]; +} + +export interface CloudMachineEcs { + type?: string[]; +} + +export interface CloudInstanceEcs { + id?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/destination/index.ts b/x-pack/plugins/security_solution/common/ecs/destination/index.ts new file mode 100644 index 0000000000000..9b4038205350e --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/destination/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { GeoEcs } from '../geo'; + +export interface DestinationEcs { + bytes?: number[]; + + ip?: string[]; + + port?: number[]; + + domain?: string[]; + + geo?: GeoEcs; + + packets?: number[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/dns/index.ts b/x-pack/plugins/security_solution/common/ecs/dns/index.ts new file mode 100644 index 0000000000000..6844cd517aceb --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/dns/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface DnsEcs { + question?: DnsQuestionEcs; + + resolved_ip?: string[]; + + response_code?: string[]; +} + +export interface DnsQuestionEcs { + name?: string[]; + + type?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/endgame/index.ts b/x-pack/plugins/security_solution/common/ecs/endgame/index.ts new file mode 100644 index 0000000000000..f435db4f47810 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/endgame/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface EndgameEcs { + exit_code?: number; + + file_name?: string; + + file_path?: string; + + logon_type?: number; + + parent_process_name?: string; + + pid?: number; + + process_name?: string; + + subject_domain_name?: string; + + subject_logon_id?: string; + + subject_user_name?: string; + + target_domain_name?: string; + + target_logon_id?: string; + + target_user_name?: string; +} diff --git a/x-pack/plugins/security_solution/common/ecs/event/index.ts b/x-pack/plugins/security_solution/common/ecs/event/index.ts new file mode 100644 index 0000000000000..cb18a8c5881e8 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/event/index.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface EventEcs { + action?: string[]; + + category?: string[]; + + code?: string[]; + + created?: string[]; + + dataset?: string[]; + + duration?: number[]; + + end?: string[]; + + hash?: string[]; + + id?: string[]; + + kind?: string[]; + + module?: string[]; + + original?: string[]; + + outcome?: string[]; + + risk_score?: number[]; + + risk_score_norm?: number[]; + + severity?: number[]; + + start?: string[]; + + timezone?: string[]; + + type?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/file/index.ts b/x-pack/plugins/security_solution/common/ecs/file/index.ts new file mode 100644 index 0000000000000..808e9eaa3c854 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/file/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; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface FileEcs { + name?: string[]; + + path?: string[]; + + target_path?: string[]; + + extension?: string[]; + + type?: string[]; + + device?: string[]; + + inode?: string[]; + + uid?: string[]; + + owner?: string[]; + + gid?: string[]; + + group?: string[]; + + mode?: string[]; + + size?: number[]; + + mtime?: string[]; + + ctime?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/geo/index.ts b/x-pack/plugins/security_solution/common/ecs/geo/index.ts new file mode 100644 index 0000000000000..409b5bbdc17a4 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/geo/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface GeoEcs { + city_name?: string[]; + + continent_name?: string[]; + + country_iso_code?: string[]; + + country_name?: string[]; + + location?: Location; + + region_iso_code?: string[]; + + region_name?: string[]; +} + +export interface Location { + lon?: number[]; + + lat?: number[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/host/index.ts b/x-pack/plugins/security_solution/common/ecs/host/index.ts new file mode 100644 index 0000000000000..056291a70b62f --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/host/index.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface HostEcs { + architecture?: string[]; + + id?: string[]; + + ip?: string[]; + + mac?: string[]; + + name?: string[]; + + os?: OsEcs; + + type?: string[]; +} + +export interface OsEcs { + platform?: string[]; + + name?: string[]; + + full?: string[]; + + family?: string[]; + + version?: string[]; + + kernel?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/http/index.ts b/x-pack/plugins/security_solution/common/ecs/http/index.ts new file mode 100644 index 0000000000000..ff56d15e70bb3 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/http/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; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface HttpEcs { + version?: string[]; + + request?: HttpRequestData; + + response?: HttpResponseData; +} + +export interface HttpRequestData { + method?: string[]; + + body?: HttpBodyData; + + referrer?: string[]; + + bytes?: number[]; +} + +export interface HttpBodyData { + content?: string[]; + + bytes?: number[]; +} + +export interface HttpResponseData { + status_code?: number[]; + + body?: HttpBodyData; + + bytes?: number[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/index.ts b/x-pack/plugins/security_solution/common/ecs/index.ts new file mode 100644 index 0000000000000..ff21ebc5ef973 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/index.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AuditdEcs } from './auditd'; +import { DestinationEcs } from './destination'; +import { DnsEcs } from './dns'; +import { EndgameEcs } from './endgame'; +import { EventEcs } from './event'; +import { GeoEcs } from './geo'; +import { HostEcs } from './host'; +import { NetworkEcs } from './network'; +import { RuleEcs } from './rule'; +import { SignalEcs } from './signal'; +import { SourceEcs } from './source'; +import { SuricataEcs } from './suricata'; +import { TlsEcs } from './tls'; +import { ZeekEcs } from './zeek'; +import { HttpEcs } from './http'; +import { UrlEcs } from './url'; +import { UserEcs } from './user'; +import { WinlogEcs } from './winlog'; +import { ProcessEcs } from './process'; +import { SystemEcs } from './system'; + +export interface Ecs { + _id: string; + + _index?: string; + + auditd?: AuditdEcs; + + destination?: DestinationEcs; + + dns?: DnsEcs; + + endgame?: EndgameEcs; + + event?: EventEcs; + + geo?: GeoEcs; + + host?: HostEcs; + + network?: NetworkEcs; + + rule?: RuleEcs; + + signal?: SignalEcs; + + source?: SourceEcs; + + suricata?: SuricataEcs; + + tls?: TlsEcs; + + zeek?: ZeekEcs; + + http?: HttpEcs; + + url?: UrlEcs; + + timestamp?: string; + + message?: string[]; + + user?: UserEcs; + + winlog?: WinlogEcs; + + process?: ProcessEcs; + + file?: File; + + system?: SystemEcs; +} diff --git a/x-pack/plugins/security_solution/common/ecs/network/index.ts b/x-pack/plugins/security_solution/common/ecs/network/index.ts new file mode 100644 index 0000000000000..c2fc3cb4b9f48 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/network/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface NetworkEcs { + bytes?: number[]; + + community_id?: string[]; + + direction?: string[]; + + packets?: number[]; + + protocol?: string[]; + + transport?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/process/index.ts b/x-pack/plugins/security_solution/common/ecs/process/index.ts new file mode 100644 index 0000000000000..0584d95c8059d --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/process/index.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface ProcessEcs { + hash?: ProcessHashData; + + pid?: number[]; + + name?: string[]; + + ppid?: number[]; + + args?: string[]; + + executable?: string[]; + + title?: string[]; + + thread?: Thread; + + working_directory?: string[]; +} + +export interface ProcessHashData { + md5?: string[]; + + sha1?: string[]; + + sha256?: string[]; +} + +export interface Thread { + id?: number[]; + + start?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/rule/index.ts b/x-pack/plugins/security_solution/common/ecs/rule/index.ts new file mode 100644 index 0000000000000..c1ef1ee17ca0c --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/rule/index.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface RuleEcs { + id?: string[]; + + rule_id?: string[]; + + false_positives: string[]; + + saved_id?: string[]; + + timeline_id?: string[]; + + timeline_title?: string[]; + + max_signals?: number[]; + + risk_score?: string[]; + + output_index?: string[]; + + description?: string[]; + + from?: string[]; + + immutable?: boolean[]; + + index?: string[]; + + interval?: string[]; + + language?: string[]; + + query?: string[]; + + references?: string[]; + + severity?: string[]; + + tags?: string[]; + + threat?: unknown; + + type?: string[]; + + size?: string[]; + + to?: string[]; + + enabled?: boolean[]; + + filters?: unknown; + + created_at?: string[]; + + updated_at?: string[]; + + created_by?: string[]; + + updated_by?: string[]; + + version?: string[]; + + note?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/signal/index.ts b/x-pack/plugins/security_solution/common/ecs/signal/index.ts new file mode 100644 index 0000000000000..66e35e26af341 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/signal/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RuleEcs } from '../rule'; + +export interface SignalEcs { + rule?: RuleEcs; + + original_time?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/source/index.ts b/x-pack/plugins/security_solution/common/ecs/source/index.ts new file mode 100644 index 0000000000000..9e6b6563cec68 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/source/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { GeoEcs } from '../geo'; + +export interface SourceEcs { + bytes?: number[]; + + ip?: string[]; + + port?: number[]; + + domain?: string[]; + + geo?: GeoEcs; + + packets?: number[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/suricata/index.ts b/x-pack/plugins/security_solution/common/ecs/suricata/index.ts new file mode 100644 index 0000000000000..53c193edddaf2 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/suricata/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface SuricataEcs { + eve?: SuricataEveData; +} + +export interface SuricataEveData { + alert?: SuricataAlertData; + + flow_id?: number[]; + + proto?: string[]; +} + +export interface SuricataAlertData { + signature?: string[]; + + signature_id?: number[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/system/index.ts b/x-pack/plugins/security_solution/common/ecs/system/index.ts new file mode 100644 index 0000000000000..803d8197080ff --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/system/index.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface SystemEcs { + audit?: AuditEcs; + + auth?: AuthEcs; +} + +export interface AuditEcs { + package?: PackageEcs; +} + +export interface PackageEcs { + arch?: string[]; + + entity_id?: string[]; + + name?: string[]; + + size?: number[]; + + summary?: string[]; + + version?: string[]; +} + +export interface AuthEcs { + ssh?: SshEcs; +} + +export interface SshEcs { + method?: string[]; + + signature?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/tls/index.ts b/x-pack/plugins/security_solution/common/ecs/tls/index.ts new file mode 100644 index 0000000000000..86a2a1a9459a2 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/tls/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface TlsEcs { + client_certificate?: TlsClientCertificateData; + + fingerprints?: TlsFingerprintsData; + + server_certificate?: TlsServerCertificateData; +} + +export interface TlsClientCertificateData { + fingerprint?: FingerprintData; +} + +export interface FingerprintData { + sha1?: string[]; +} + +export interface TlsFingerprintsData { + ja3?: TlsJa3Data; +} + +export interface TlsJa3Data { + hash?: string[]; +} + +export interface TlsServerCertificateData { + fingerprint?: FingerprintData; +} diff --git a/x-pack/plugins/security_solution/common/ecs/url/index.ts b/x-pack/plugins/security_solution/common/ecs/url/index.ts new file mode 100644 index 0000000000000..66033ea9f0725 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/url/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface UrlEcs { + domain?: string[]; + + original?: string[]; + + username?: string[]; + + password?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/user/index.ts b/x-pack/plugins/security_solution/common/ecs/user/index.ts new file mode 100644 index 0000000000000..d72362d5f5cf9 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/user/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface UserEcs { + domain?: string[]; + + id?: string[]; + + name?: string[]; + + full_name?: string[]; + + email?: string[]; + + hash?: string[]; + + group?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/winlog/index.ts b/x-pack/plugins/security_solution/common/ecs/winlog/index.ts new file mode 100644 index 0000000000000..a449fb9130e6f --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/winlog/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface WinlogEcs { + event_id?: number[]; +} diff --git a/x-pack/plugins/security_solution/common/ecs/zeek/index.ts b/x-pack/plugins/security_solution/common/ecs/zeek/index.ts new file mode 100644 index 0000000000000..289390a87db12 --- /dev/null +++ b/x-pack/plugins/security_solution/common/ecs/zeek/index.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface ZeekEcs { + session_id?: string[]; + + connection?: ZeekConnectionData; + + notice?: ZeekNoticeData; + + dns?: ZeekDnsData; + + http?: ZeekHttpData; + + files?: ZeekFileData; + + ssl?: ZeekSslData; +} + +export interface ZeekConnectionData { + local_resp?: boolean[]; + + local_orig?: boolean[]; + + missed_bytes?: number[]; + + state?: string[]; + + history?: string[]; +} + +export interface ZeekNoticeData { + suppress_for?: number[]; + + msg?: string[]; + + note?: string[]; + + sub?: string[]; + + dst?: string[]; + + dropped?: boolean[]; + + peer_descr?: string[]; +} + +export interface ZeekDnsData { + AA?: boolean[]; + + qclass_name?: string[]; + + RD?: boolean[]; + + qtype_name?: string[]; + + rejected?: boolean[]; + + qtype?: string[]; + + query?: string[]; + + trans_id?: number[]; + + qclass?: string[]; + + RA?: boolean[]; + + TC?: boolean[]; +} + +export interface ZeekHttpData { + resp_mime_types?: string[]; + + trans_depth?: string[]; + + status_msg?: string[]; + + resp_fuids?: string[]; + + tags?: string[]; +} + +export interface ZeekFileData { + session_ids?: string[]; + + timedout?: boolean[]; + + local_orig?: boolean[]; + + tx_host?: string[]; + + source?: string[]; + + is_orig?: boolean[]; + + overflow_bytes?: number[]; + + sha1?: string[]; + + duration?: number[]; + + depth?: number[]; + + analyzers?: string[]; + + mime_type?: string[]; + + rx_host?: string[]; + + total_bytes?: number[]; + + fuid?: string[]; + + seen_bytes?: number[]; + + missing_bytes?: number[]; + + md5?: string[]; +} + +export interface ZeekSslData { + cipher?: string[]; + + established?: boolean[]; + + resumed?: boolean[]; + + version?: string[]; +} diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts new file mode 100644 index 0000000000000..3a0942d2decb8 --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IEsSearchResponse } from '../../../../../../../src/plugins/data/common'; +import { CloudEcs } from '../../../ecs/cloud'; +import { HostEcs } from '../../../ecs/host'; + +import { + CursorType, + Inspect, + Maybe, + PageInfoPaginated, + RequestOptionsPaginated, + SortField, + TimerangeInput, +} from '..'; + +export enum HostsQueries { + hosts = 'hosts', + hostOverview = 'hostOverview', +} + +export enum HostPolicyResponseActionStatus { + success = 'success', + failure = 'failure', + warning = 'warning', +} + +export interface EndpointFields { + endpointPolicy?: Maybe; + + sensorVersion?: Maybe; + + policyStatus?: Maybe; +} + +export interface HostItem { + _id?: Maybe; + + cloud?: Maybe; + + endpoint?: Maybe; + + host?: Maybe; + + lastSeen?: Maybe; +} + +export interface HostsEdges { + node: HostItem; + + cursor: CursorType; +} + +export interface HostsStrategyResponse extends IEsSearchResponse { + edges: HostsEdges[]; + + totalCount: number; + + pageInfo: PageInfoPaginated; + + inspect?: Maybe; +} + +export interface HostOverviewStrategyResponse extends IEsSearchResponse, HostItem { + inspect?: Maybe; +} + +export interface HostsRequestOptions extends RequestOptionsPaginated { + sort: SortField; + defaultIndex: string[]; +} + +export interface HostLastFirstSeenRequestOptions extends Partial { + hostName: string; +} + +export interface HostOverviewRequestOptions extends HostLastFirstSeenRequestOptions { + fields: string[]; + timerange: TimerangeInput; +} 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 new file mode 100644 index 0000000000000..edb5dda2ca6da --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IEsSearchRequest } from '../../../../../../src/plugins/data/common'; +import { ESQuery } from '../../typed_json'; +import { + HostOverviewStrategyResponse, + HostOverviewRequestOptions, + HostsQueries, + HostsRequestOptions, + HostsStrategyResponse, +} from './hosts'; +export * from './hosts'; +export type Maybe = T | null; + +export type FactoryQueryTypes = HostsQueries; + +export interface Inspect { + dsl: string[]; + response: string[]; +} + +export interface PageInfoPaginated { + activePage: number; + fakeTotalCount: number; + showMorePagesIndicator: boolean; +} + +export interface CursorType { + value?: Maybe; + tiebreaker?: Maybe; +} + +export enum Direction { + asc = 'asc', + desc = 'desc', +} + +export interface SortField { + field: string; + direction: Direction; +} + +export interface TimerangeInput { + /** The interval string to use for last bucket. The format is '{value}{unit}'. For example '5m' would return the metrics for the last 5 minutes of the timespan. */ + interval: string; + /** The end of the timerange */ + to: string; + /** The beginning of the timerange */ + from: string; +} + +export interface PaginationInput { + /** The limit parameter allows you to configure the maximum amount of items to be returned */ + limit: number; + /** The cursor parameter defines the next result you want to fetch */ + cursor?: Maybe; + /** The tiebreaker parameter allow to be more precise to fetch the next item */ + tiebreaker?: Maybe; +} + +export interface PaginationInputPaginated { + /** The activePage parameter defines the page of results you want to fetch */ + activePage: number; + /** The cursorStart parameter defines the start of the results to be displayed */ + cursorStart: number; + /** The fakePossibleCount parameter determines the total count in order to show 5 additional pages */ + fakePossibleCount: number; + /** The querySize parameter is the number of items to be returned */ + querySize: number; +} + +export interface DocValueFields { + field: string; + format: string; +} + +export interface RequestBasicOptions extends IEsSearchRequest { + timerange: TimerangeInput; + filterQuery: ESQuery | string | undefined; + defaultIndex: string[]; + docValueFields?: DocValueFields[]; + factoryQueryType?: FactoryQueryTypes; +} + +export interface RequestOptions extends RequestBasicOptions { + pagination: PaginationInput; + sortField?: SortField; +} + +export interface RequestOptionsPaginated extends RequestBasicOptions { + pagination: PaginationInputPaginated; + sortField?: SortField; +} + +export type StrategyResponseType = T extends HostsQueries.hosts + ? HostsStrategyResponse + : T extends HostsQueries.hostOverview + ? HostOverviewStrategyResponse + : never; + +export type StrategyRequestType = T extends HostsQueries.hosts + ? HostsRequestOptions + : T extends HostsQueries.hostOverview + ? HostOverviewRequestOptions + : never; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx index 8af24e6e6abc1..346de9f87313f 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx @@ -4,185 +4,211 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get, getOr } from 'lodash/fp'; -import memoizeOne from 'memoize-one'; -import React from 'react'; -import { Query } from 'react-apollo'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; +import deepEqual from 'fast-deep-equal'; +import { noop } from 'lodash/fp'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useSelector } from 'react-redux'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { - Direction, - GetHostsTableQuery, - HostsEdges, - HostsFields, - PageInfoPaginated, -} from '../../../graphql/types'; -import { inputsModel, State, inputsSelectors } from '../../../common/store'; -import { createFilter, getDefaultFetchPolicy } from '../../../common/containers/helpers'; -import { - QueryTemplatePaginated, - QueryTemplatePaginatedProps, -} from '../../../common/containers/query_template_paginated'; -import { withKibana, WithKibanaProps } from '../../../common/lib/kibana'; +import { HostsEdges, PageInfoPaginated } from '../../../graphql/types'; +import { inputsModel, State } from '../../../common/store'; +import { createFilter } from '../../../common/containers/helpers'; +import { useKibana } from '../../../common/lib/kibana'; import { hostsModel, hostsSelectors } from '../../store'; -import { HostsTableQuery } from './hosts_table.gql_query'; import { generateTablePaginationOptions } from '../../../common/components/paginated_table/helpers'; +import { + DocValueFields, + HostsQueries, + HostsRequestOptions, + HostsStrategyResponse, +} from '../../../../common/search_strategy/security_solution'; +import { ESTermQuery } from '../../../../common/typed_json'; + +import * as i18n from './translations'; +import { AbortError } from '../../../../../../../src/plugins/data/common'; const ID = 'hostsQuery'; +type LoadPage = (newActivePage: number) => void; export interface HostsArgs { endDate: string; hosts: HostsEdges[]; id: string; inspect: inputsModel.InspectQuery; isInspected: boolean; - loading: boolean; - loadPage: (newActivePage: number) => void; + loadPage: LoadPage; pageInfo: PageInfoPaginated; refetch: inputsModel.Refetch; startDate: string; totalCount: number; } -export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: HostsArgs) => React.ReactNode; - type: hostsModel.HostsType; - startDate: string; +interface UseAllHost { + docValueFields?: DocValueFields[]; + filterQuery?: ESTermQuery | string; endDate: string; + startDate: string; + type: hostsModel.HostsType; } -export interface HostsComponentReduxProps { - activePage: number; - isInspected: boolean; - limit: number; - sortField: HostsFields; - direction: Direction; -} - -type HostsProps = OwnProps & HostsComponentReduxProps & WithKibanaProps; +export const useAllHost = ({ + docValueFields, + filterQuery, + endDate, + startDate, + type, +}: UseAllHost): [boolean, HostsArgs] => { + const getHostsSelector = hostsSelectors.hostsSelector(); + const { activePage, direction, limit, sortField } = useSelector((state: State) => + getHostsSelector(state, type) + ); + const { data, notifications, uiSettings } = useKibana().services; + const refetch = useRef(noop); + const abortCtrl = useRef(new AbortController()); + const defaultIndex = uiSettings.get(DEFAULT_INDEX_KEY); + const [loading, setLoading] = useState(false); + const [hostsRequest, setHostRequest] = useState({ + defaultIndex, + docValueFields: docValueFields ?? [], + factoryQueryType: HostsQueries.hosts, + filterQuery: createFilter(filterQuery), + pagination: generateTablePaginationOptions(activePage, limit), + timerange: { + interval: '12h', + from: startDate, + to: endDate, + }, + sort: { + direction, + field: sortField, + }, + // inspect: isInspected, + }); -class HostsComponentQuery extends QueryTemplatePaginated< - HostsProps, - GetHostsTableQuery.Query, - GetHostsTableQuery.Variables -> { - private memoizedHosts: ( - variables: string, - data: GetHostsTableQuery.Source | undefined - ) => HostsEdges[]; + const wrappedLoadMore = useCallback( + (newActivePage: number) => { + setHostRequest((prevRequest) => { + return { + ...prevRequest, + pagination: generateTablePaginationOptions(newActivePage, limit), + }; + }); + }, + [limit] + ); - constructor(props: HostsProps) { - super(props); - this.memoizedHosts = memoizeOne(this.getHosts); - } + const [hostsResponse, setHostsResponse] = useState({ + endDate, + hosts: [], + id: ID, + inspect: { + dsl: [], + response: [], + }, + isInspected: false, + loadPage: wrappedLoadMore, + pageInfo: { + activePage: 0, + fakeTotalCount: 0, + showMorePagesIndicator: false, + }, + refetch: refetch.current, + startDate, + totalCount: -1, + }); - public render() { - const { - activePage, - docValueFields, - id = ID, - isInspected, - children, - direction, - filterQuery, - endDate, - kibana, - limit, - startDate, - skip, - sourceId, - sortField, - } = this.props; - const defaultIndex = kibana.services.uiSettings.get(DEFAULT_INDEX_KEY); + const hostsSearch = useCallback( + (request: HostsRequestOptions) => { + let didCancel = false; + const asyncSearch = async () => { + abortCtrl.current = new AbortController(); + setLoading(true); - const variables: GetHostsTableQuery.Variables = { - sourceId, - timerange: { - interval: '12h', - from: startDate, - to: endDate, - }, - sort: { - direction, - field: sortField, - }, - pagination: generateTablePaginationOptions(activePage, limit), - filterQuery: createFilter(filterQuery), - defaultIndex, - docValueFields: docValueFields ?? [], - inspect: isInspected, - }; - return ( - - query={HostsTableQuery} - fetchPolicy={getDefaultFetchPolicy()} - notifyOnNetworkStatusChange - variables={variables} - skip={skip} - > - {({ data, loading, fetchMore, networkStatus, refetch }) => { - this.setFetchMore(fetchMore); - this.setFetchMoreOptions((newActivePage: number) => ({ - variables: { - pagination: generateTablePaginationOptions(newActivePage, limit), + const searchSubscription$ = data.search + .search(request, { + strategy: 'securitySolutionSearchStrategy', + signal: abortCtrl.current.signal, + }) + .subscribe({ + next: (response) => { + if (!response.isPartial && !response.isRunning) { + if (!didCancel) { + setLoading(false); + setHostsResponse((prevResponse) => ({ + ...prevResponse, + hosts: response.edges, + inspect: response.inspect ?? prevResponse.inspect, + pageInfo: response.pageInfo, + refetch: refetch.current, + totalCount: response.totalCount, + })); + } + searchSubscription$.unsubscribe(); + } else if (response.isPartial && !response.isRunning) { + if (!didCancel) { + setLoading(false); + } + // TODO: Make response error status clearer + notifications.toasts.addWarning(i18n.ERROR_ALL_HOST); + searchSubscription$.unsubscribe(); + } }, - updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult) { - return prev; + error: (msg) => { + if (!(msg instanceof AbortError)) { + notifications.toasts.addDanger({ title: i18n.FAIL_ALL_HOST, text: msg.message }); } - return { - ...fetchMoreResult, - source: { - ...fetchMoreResult.source, - Hosts: { - ...fetchMoreResult.source.Hosts, - edges: [...fetchMoreResult.source.Hosts.edges], - }, - }, - }; }, - })); - const isLoading = this.isItAValidLoading(loading, variables, networkStatus); - return children({ - endDate, - hosts: this.memoizedHosts(JSON.stringify(variables), get('source', data)), - id, - inspect: getOr(null, 'source.Hosts.inspect', data), - isInspected, - loading: isLoading, - loadPage: this.wrappedLoadMore, - pageInfo: getOr({}, 'source.Hosts.pageInfo', data), - refetch: this.memoizedRefetchQuery(variables, limit, refetch), - startDate, - totalCount: getOr(-1, 'source.Hosts.totalCount', data), }); - }} - - ); - } + }; + abortCtrl.current.abort(); + asyncSearch(); + refetch.current = asyncSearch; + return () => { + didCancel = true; + abortCtrl.current.abort(); + }; + }, + [data.search, notifications.toasts] + ); - private getHosts = ( - variables: string, - source: GetHostsTableQuery.Source | undefined - ): HostsEdges[] => getOr([], 'Hosts.edges', source); -} + useEffect(() => { + setHostRequest((prevRequest) => { + const myRequest = { + ...prevRequest, + defaultIndex, + docValueFields: docValueFields ?? [], + filterQuery: createFilter(filterQuery), + pagination: generateTablePaginationOptions(activePage, limit), + timerange: { + interval: '12h', + from: startDate, + to: endDate, + }, + sort: { + direction, + field: sortField, + }, + }; + if (!deepEqual(prevRequest, myRequest)) { + return myRequest; + } + return prevRequest; + }); + }, [ + activePage, + defaultIndex, + direction, + docValueFields, + endDate, + filterQuery, + limit, + startDate, + sortField, + ]); -const makeMapStateToProps = () => { - const getHostsSelector = hostsSelectors.hostsSelector(); - const getQuery = inputsSelectors.globalQueryByIdSelector(); - const mapStateToProps = (state: State, { type, id = ID }: OwnProps) => { - const { isInspected } = getQuery(state, id); - return { - ...getHostsSelector(state, type), - isInspected, - }; - }; - return mapStateToProps; -}; + useEffect(() => { + hostsSearch(hostsRequest); + }, [hostsRequest, hostsSearch]); -export const HostsQuery = compose>( - connect(makeMapStateToProps), - withKibana -)(HostsComponentQuery); + return [loading, hostsResponse]; +}; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts b/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts new file mode 100644 index 0000000000000..ada713d135c22 --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const ERROR_ALL_HOST = i18n.translate( + 'xpack.securitySolution.allHost.errorSearchDescription', + { + defaultMessage: `An error has occurred on all hosts search`, + } +); + +export const FAIL_ALL_HOST = i18n.translate( + 'xpack.securitySolution.allHost.failSearchDescription', + { + defaultMessage: `Failed to run search on all hosts`, + } +); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/navigation/hosts_query_tab_body.tsx b/x-pack/plugins/security_solution/public/hosts/pages/navigation/hosts_query_tab_body.tsx index 80cf62bc49f78..5232dcfd88189 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/navigation/hosts_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/navigation/hosts_query_tab_body.tsx @@ -6,7 +6,7 @@ import { getOr } from 'lodash/fp'; import React from 'react'; -import { HostsQuery } from '../../containers/hosts'; +import { useAllHost } from '../../containers/hosts'; import { HostsComponentsQueryProps } from './types'; import { HostsTable } from '../../components/hosts_table'; import { manageQuery } from '../../../common/components/page/manage_query'; @@ -23,35 +23,29 @@ export const HostsQueryTabBody = ({ setQuery, startDate, type, -}: HostsComponentsQueryProps) => ( - - {({ hosts, totalCount, loading, pageInfo, loadPage, id, inspect, isInspected, refetch }) => ( - - )} - -); +}: HostsComponentsQueryProps) => { + const [ + loading, + { hosts, totalCount, pageInfo, loadPage, id, inspect, isInspected, refetch }, + ] = useAllHost({ docValueFields, endDate, filterQuery, startDate, type }); + return ( + + ); +}; HostsQueryTabBody.displayName = 'HostsQueryTabBody'; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 85764eaaee32d..25ca89ce9186e 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -17,6 +17,8 @@ import { PluginInitializerContext, SavedObjectsClient, } from '../../../../src/core/server'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { DataPluginSetup, DataPluginStart } from '../../../../src/plugins/data/server/plugin'; import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server'; import { PluginSetupContract as AlertingSetup } from '../../alerts/server'; import { SecurityPluginSetup as SecuritySetup } from '../../security/server'; @@ -58,9 +60,11 @@ import { EndpointAppContext } from './endpoint/types'; import { registerDownloadExceptionListRoute } from './endpoint/routes/artifacts'; import { initUsageCollectors } from './usage'; import { AppRequestContext } from './types'; +import { securitySolutionSearchStrategyProvider } from './search_strategy/security_solution'; export interface SetupPlugins { alerts: AlertingSetup; + data: DataPluginSetup; encryptedSavedObjects?: EncryptedSavedObjectsSetup; features: FeaturesSetup; licensing: LicensingPluginSetup; @@ -73,6 +77,7 @@ export interface SetupPlugins { } export interface StartPlugins { + data: DataPluginStart; ingestManager?: IngestManagerStartContract; taskManager?: TaskManagerStartContract; } @@ -263,6 +268,14 @@ export class Plugin implements IPlugin { + const securitySolutionSearchStrategy = securitySolutionSearchStrategyProvider(depsStart.data); + plugins.data.search.registerSearchStrategy( + 'securitySolutionSearchStrategy', + securitySolutionSearchStrategy + ); + }); + return {}; } diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.detail_host.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.detail_host.dsl.ts new file mode 100644 index 0000000000000..5c5dec92a5100 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.detail_host.dsl.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ISearchRequestParams } from '../../../../../../../../../src/plugins/data/common'; +import { HostOverviewRequestOptions } from '../../../../../../common/search_strategy/security_solution'; +import { cloudFieldsMap, hostFieldsMap } from '../../../../../lib/ecs_fields'; +import { buildFieldsTermAggregation } from '../../../../../lib/hosts/helpers'; +import { reduceFields } from '../../../../../utils/build_query/reduce_fields'; + +export const buildHostOverviewQuery = ({ + fields, + hostName, + defaultIndex, + timerange: { from, to }, +}: HostOverviewRequestOptions): ISearchRequestParams => { + const esFields = reduceFields(fields, { ...hostFieldsMap, ...cloudFieldsMap }); + + const filter = [ + { term: { 'host.name': hostName } }, + { + range: { + '@timestamp': { + format: 'strict_date_optional_time', + gte: from, + lte: to, + }, + }, + }, + ]; + + const dslQuery = { + allowNoIndices: true, + index: defaultIndex, + ignoreUnavailable: true, + body: { + aggregations: { + ...buildFieldsTermAggregation(esFields.filter((field) => !['@timestamp'].includes(field))), + }, + query: { bool: { filter } }, + size: 0, + track_total_hits: false, + }, + }; + + return dslQuery; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.hosts.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.hosts.dsl.ts new file mode 100644 index 0000000000000..3d72f98f35355 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.hosts.dsl.ts @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { isEmpty, isString } from 'lodash/fp'; +import { ISearchRequestParams } from '../../../../../../../../../src/plugins/data/common'; +import { + Direction, + HostsRequestOptions, + SortField, +} from '../../../../../../common/search_strategy/security_solution'; +import { assertUnreachable, createQueryFilterClauses } from '../../../../../utils/build_query'; + +export const buildHostsQuery = ({ + defaultIndex, + docValueFields, + filterQuery, + pagination: { querySize }, + sort, + timerange: { from, to }, +}: HostsRequestOptions): ISearchRequestParams => { + const filter = [ + ...createQueryFilterClauses(isString(filterQuery) ? JSON.parse(filterQuery) : filterQuery), + { + range: { + '@timestamp': { + gte: from, + lte: to, + format: 'strict_date_optional_time', + }, + }, + }, + ]; + + const agg = { host_count: { cardinality: { field: 'host.name' } } }; + + const dslQuery = { + allowNoIndices: true, + index: defaultIndex, + ignoreUnavailable: true, + body: { + ...(isEmpty(docValueFields) ? { docvalue_fields: docValueFields } : {}), + aggregations: { + ...agg, + host_data: { + terms: { size: querySize, field: 'host.name', order: getQueryOrder(sort) }, + aggs: { + lastSeen: { max: { field: '@timestamp' } }, + os: { + top_hits: { + size: 1, + sort: [ + { + '@timestamp': { + order: 'desc', + }, + }, + ], + _source: { + includes: ['host.os.*'], + }, + }, + }, + }, + }, + }, + query: { bool: { filter } }, + size: 0, + track_total_hits: false, + }, + }; + + return dslQuery; +}; + +type QueryOrder = { lastSeen: Direction } | { _key: Direction }; + +const getQueryOrder = (sort: SortField): QueryOrder => { + switch (sort.field) { + case 'lastSeen': + return { lastSeen: sort.direction }; + case 'hostName': + return { _key: sort.direction }; + default: + return assertUnreachable(sort.field); + } +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.last_first_seen_host.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.last_first_seen_host.dsl.ts new file mode 100644 index 0000000000000..b57bbd2960e4f --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.last_first_seen_host.dsl.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { isEmpty } from 'lodash/fp'; +import { ISearchRequestParams } from '../../../../../../../../../src/plugins/data/common'; +import { HostLastFirstSeenRequestOptions } from '../../../../../../common/search_strategy/security_solution'; + +export const buildLastFirstSeenHostQuery = ({ + hostName, + defaultIndex, + docValueFields, +}: HostLastFirstSeenRequestOptions): ISearchRequestParams => { + const filter = [{ term: { 'host.name': hostName } }]; + + const dslQuery = { + allowNoIndices: true, + index: defaultIndex, + ignoreUnavailable: true, + body: { + ...(isEmpty(docValueFields) ? { docvalue_fields: docValueFields } : {}), + aggregations: { + firstSeen: { min: { field: '@timestamp' } }, + lastSeen: { max: { field: '@timestamp' } }, + }, + query: { bool: { filter } }, + size: 0, + track_total_hits: false, + }, + }; + + return dslQuery; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/helpers.ts new file mode 100644 index 0000000000000..a7ec822839d21 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/helpers.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { set } from '@elastic/safer-lodash-set/fp'; +import { get, has, head } from 'lodash/fp'; +import { + HostsEdges, + HostItem, +} from '../../../../../common/search_strategy/security_solution/hosts'; +import { hostFieldsMap } from '../../../../lib/ecs_fields'; + +import { HostAggEsItem, HostBuckets, HostValue } from '../../../../lib/hosts/types'; + +const hostsFields = ['_id', 'lastSeen', 'host.id', 'host.name', 'host.os.name', 'host.os.version']; + +export const formatHostEdgesData = (bucket: HostAggEsItem): HostsEdges => + hostsFields.reduce( + (flattenedFields, fieldName) => { + const hostId = get('key', bucket); + flattenedFields.node._id = hostId || null; + flattenedFields.cursor.value = hostId || ''; + const fieldValue = getHostFieldValue(fieldName, bucket); + if (fieldValue != null) { + return set( + `node.${fieldName}`, + Array.isArray(fieldValue) ? fieldValue : [fieldValue], + flattenedFields + ); + } + return flattenedFields; + }, + { + node: {}, + cursor: { + value: '', + tiebreaker: null, + }, + } as HostsEdges + ); + +const hostFields = [ + '_id', + 'host.architecture', + 'host.id', + 'host.ip', + 'host.id', + 'host.mac', + 'host.name', + 'host.os.family', + 'host.os.name', + 'host.os.platform', + 'host.os.version', + 'host.type', + 'cloud.instance.id', + 'cloud.machine.type', + 'cloud.provider', + 'cloud.region', + 'endpoint.endpointPolicy', + 'endpoint.policyStatus', + 'endpoint.sensorVersion', +]; + +export const formatHostItem = (bucket: HostAggEsItem): HostItem => + hostFields.reduce((flattenedFields, fieldName) => { + const fieldValue = getHostFieldValue(fieldName, bucket); + if (fieldValue != null) { + return set(fieldName, fieldValue, flattenedFields); + } + return flattenedFields; + }, {}); + +const getHostFieldValue = (fieldName: string, bucket: HostAggEsItem): string | string[] | null => { + const aggField = hostFieldsMap[fieldName] + ? hostFieldsMap[fieldName].replace(/\./g, '_') + : fieldName.replace(/\./g, '_'); + if ( + [ + 'host.ip', + 'host.mac', + 'cloud.instance.id', + 'cloud.machine.type', + 'cloud.provider', + 'cloud.region', + ].includes(fieldName) && + has(aggField, bucket) + ) { + const data: HostBuckets = get(aggField, bucket); + return data.buckets.map((obj) => obj.key); + } else if (has(`${aggField}.buckets`, bucket)) { + return getFirstItem(get(`${aggField}`, bucket)); + } else if (has(aggField, bucket)) { + const valueObj: HostValue = get(aggField, bucket); + return valueObj.value_as_string; + } else if (['host.name', 'host.os.name', 'host.os.version'].includes(fieldName)) { + switch (fieldName) { + case 'host.name': + return get('key', bucket) || null; + case 'host.os.name': + return get('os.hits.hits[0]._source.host.os.name', bucket) || null; + case 'host.os.version': + return get('os.hits.hits[0]._source.host.os.version', bucket) || null; + } + } + return null; +}; + +const getFirstItem = (data: HostBuckets): string | null => { + const firstItem = head(data.buckets); + if (firstItem == null) { + return null; + } + return firstItem.key; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts new file mode 100644 index 0000000000000..443e524d71ca3 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get, getOr } from 'lodash/fp'; + +import { IEsSearchResponse } from '../../../../../../../../src/plugins/data/common'; + +import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../common/constants'; +import { FactoryQueryTypes } from '../../../../../common/search_strategy/security_solution'; +import { + HostsStrategyResponse, + HostOverviewStrategyResponse, + HostsQueries, + HostsRequestOptions, + HostOverviewRequestOptions, +} from '../../../../../common/search_strategy/security_solution/hosts'; + +// TO DO need to move all this types in common +import { HostAggEsData, HostAggEsItem } from '../../../../lib/hosts/types'; + +import { inspectStringifyObject } from '../../../../utils/build_query'; +import { SecuritySolutionFactory } from '../types'; +import { buildHostOverviewQuery } from './dsl/query.detail_host.dsl'; +import { buildHostsQuery } from './dsl/query.hosts.dsl'; +import { formatHostEdgesData, formatHostItem } from './helpers'; + +export const allHosts: SecuritySolutionFactory = { + buildDsl: (options: HostsRequestOptions) => { + if (options.pagination && options.pagination.querySize >= DEFAULT_MAX_TABLE_QUERY_SIZE) { + throw new Error(`No query size above ${DEFAULT_MAX_TABLE_QUERY_SIZE}`); + } + return buildHostsQuery(options); + }, + parse: async ( + options: HostsRequestOptions, + response: IEsSearchResponse + ): Promise => { + const { activePage, cursorStart, fakePossibleCount, querySize } = options.pagination; + const totalCount = getOr(0, 'aggregations.host_count.value', response.rawResponse); + const buckets: HostAggEsItem[] = getOr( + [], + 'aggregations.host_data.buckets', + response.rawResponse + ); + const hostsEdges = buckets.map((bucket) => formatHostEdgesData(bucket)); + const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount; + const edges = hostsEdges.splice(cursorStart, querySize - cursorStart); + const inspect = { + dsl: [inspectStringifyObject(buildHostsQuery(options))], + response: [inspectStringifyObject(response)], + }; + const showMorePagesIndicator = totalCount > fakeTotalCount; + + return { + ...response, + inspect, + edges, + totalCount, + pageInfo: { + activePage: activePage ? activePage : 0, + fakeTotalCount, + showMorePagesIndicator, + }, + }; + }, +}; + +export const overviewHost: SecuritySolutionFactory = { + buildDsl: (options: HostOverviewRequestOptions) => { + return buildHostOverviewQuery(options); + }, + parse: async ( + options: HostOverviewRequestOptions, + response: IEsSearchResponse + ): Promise => { + const aggregations: HostAggEsItem = get('aggregations', response.rawResponse) || {}; + const inspect = { + dsl: [inspectStringifyObject(buildHostOverviewQuery(options))], + response: [inspectStringifyObject(response)], + }; + const formattedHostItem = formatHostItem(aggregations); + return { ...response, inspect, _id: options.hostName, ...formattedHostItem }; + }, +}; + +export const hostsFactory: Record> = { + [HostsQueries.hosts]: allHosts, + [HostsQueries.hostOverview]: overviewHost, +}; 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 new file mode 100644 index 0000000000000..53433dfc208cb --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FactoryQueryTypes } from '../../../../common/search_strategy/security_solution'; + +import { hostsFactory } from './hosts'; +import { SecuritySolutionFactory } from './types'; + +export const securitySolutionFactory: Record< + FactoryQueryTypes, + SecuritySolutionFactory +> = { + ...hostsFactory, +}; 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 new file mode 100644 index 0000000000000..cb9e3a3d7628a --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + IEsSearchResponse, + ISearchRequestParams, +} from '../../../../../../../src/plugins/data/common'; +import { + FactoryQueryTypes, + StrategyRequestType, + StrategyResponseType, +} from '../../../../common/search_strategy/security_solution'; + +export interface SecuritySolutionFactory { + buildDsl: (options: StrategyRequestType) => ISearchRequestParams; + parse: ( + options: StrategyRequestType, + response: IEsSearchResponse + ) => Promise>; +} 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 new file mode 100644 index 0000000000000..d94a32174cd7a --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ISearchStrategy, PluginStart } from '../../../../../../src/plugins/data/server'; +import { + FactoryQueryTypes, + StrategyResponseType, + StrategyRequestType, +} from '../../../common/search_strategy/security_solution'; +import { securitySolutionFactory } from './factory'; +import { SecuritySolutionFactory } from './factory/types'; + +export const securitySolutionSearchStrategyProvider = ( + data: PluginStart +): ISearchStrategy, StrategyResponseType> => { + const es = data.search.getSearchStrategy('es'); + + return { + search: async (context, request, options) => { + if (request.factoryQueryType == null) { + throw new Error('factoryQueryType is required'); + } + const queryFactory: SecuritySolutionFactory = + securitySolutionFactory[request.factoryQueryType]; + const dsl = queryFactory.buildDsl(request); + const esSearchRes = await es.search(context, { ...request, params: dsl }, options); + return queryFactory.parse(request, esSearchRes); + }, + cancel: async (context, id) => { + if (es.cancel) { + es.cancel(context, id); + } + }, + }; +}; diff --git a/x-pack/plugins/security_solution/server/utils/build_query/filters.ts b/x-pack/plugins/security_solution/server/utils/build_query/filters.ts index 95c9a975454f2..ac736e8cb51ee 100644 --- a/x-pack/plugins/security_solution/server/utils/build_query/filters.ts +++ b/x-pack/plugins/security_solution/server/utils/build_query/filters.ts @@ -8,5 +8,5 @@ import { isEmpty } from 'lodash/fp'; import { ESQuery } from '../../../common/typed_json'; -export const createQueryFilterClauses = (filterQuery: ESQuery | undefined) => +export const createQueryFilterClauses = (filterQuery: ESQuery | string | undefined) => !isEmpty(filterQuery) ? [filterQuery] : []; diff --git a/x-pack/plugins/security_solution/server/utils/build_query/index.ts b/x-pack/plugins/security_solution/server/utils/build_query/index.ts index c97e78aad2b69..233ba70968fa1 100644 --- a/x-pack/plugins/security_solution/server/utils/build_query/index.ts +++ b/x-pack/plugins/security_solution/server/utils/build_query/index.ts @@ -10,7 +10,7 @@ export * from './merge_fields_with_hits'; export * from './calculate_timeseries_interval'; export const assertUnreachable = ( - x: never, + x: unknown, message: string = 'Unknown Field in switch statement' ): never => { throw new Error(`${message} ${x}`);