From 38c708d159ebe39cd8bfce8a2e9ccb7de2a8e5a3 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Fri, 14 Aug 2020 15:53:47 -0400 Subject: [PATCH 01/11] add security solution search strategy on server side --- .../data/common/search/es_search/types.ts | 4 +- src/plugins/data/server/search/types.ts | 26 +++- .../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 | 81 +++++++++++ .../security_solution/index.ts | 92 ++++++++++++ .../security_solution/server/plugin.ts | 13 ++ .../hosts/dsl/query.detail_host.dsl.ts | 48 +++++++ .../factory/hosts/dsl/query.hosts.dsl.ts | 89 ++++++++++++ .../dsl/query.last_first_seen_host.dsl.ts | 35 +++++ .../factory/hosts/helpers.ts | 87 ++++++++++++ .../security_solution/factory/hosts/index.ts | 93 ++++++++++++ .../security_solution/factory/index.ts | 17 +++ .../security_solution/factory/types.ts | 34 +++++ .../security_solution/index.ts | 38 +++++ .../server/utils/build_query/index.ts | 2 +- 37 files changed, 1481 insertions(+), 9 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/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/src/plugins/data/common/search/es_search/types.ts b/src/plugins/data/common/search/es_search/types.ts index db2e31706e95c..18988cbf130b7 100644 --- a/src/plugins/data/common/search/es_search/types.ts +++ b/src/plugins/data/common/search/es_search/types.ts @@ -30,6 +30,6 @@ export interface IEsSearchRequest extends IKibanaSearchRequest { indexType?: string; } -export interface IEsSearchResponse extends IKibanaSearchResponse { - rawResponse: SearchResponse; +export interface IEsSearchResponse extends IKibanaSearchResponse { + rawResponse: SearchResponse; } diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 76afd7e8c951c..aaaa1b5f1e4c6 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -35,7 +35,13 @@ export interface ISearchSetup { * Extension point exposed for other plugins to register their own search * strategies. */ - registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void; + registerSearchStrategy: < + SearchStrategyRequest = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse + >( + name: string, + strategy: ISearchStrategy + ) => void; /** * Used internally for telemetry @@ -43,12 +49,17 @@ export interface ISearchSetup { usage?: SearchUsage; } -export interface ISearchStart { +export interface ISearchStart< + SearchStrategyRequest = any, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse +> { /** * 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, @@ -60,11 +71,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 = 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/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..c4f067deffa34 --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/index.ts @@ -0,0 +1,81 @@ +/* + * 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 type HostsQueries = 'host_all' | 'host_details'; + +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 HostDetailsStrategyResponse 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..852c7b32e5dab --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/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 { ESQuery } from '../../typed_json'; +import { HostsQueries } 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 DocValueFieldsInput { + field: string; + format: string; +} + +export interface RequestBasicOptions { + timerange: TimerangeInput; + filterQuery: ESQuery | undefined; + defaultIndex: string[]; + docValueFields?: DocValueFieldsInput[]; + factoryQueryType?: FactoryQueryTypes; +} + +export interface RequestOptions extends RequestBasicOptions { + pagination: PaginationInput; + fields: readonly string[]; + sortField?: SortField; +} + +export interface RequestOptionsPaginated extends RequestBasicOptions { + pagination: PaginationInputPaginated; + fields: readonly string[]; + sortField?: SortField; +} diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index f2fad16d80414..736ef97621b2e 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..140a66be73eef --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/dsl/query.detail_host.dsl.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +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) => { + 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..d4e3fb19d243c --- /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 } from 'lodash/fp'; +import { + Direction, + HostsRequestOptions, + SortField, +} from '../../../../../../common/search_strategy/security_solution'; +import { assertUnreachable, createQueryFilterClauses } from '../../../../../utils/build_query'; + +export const buildHostsQuery = ({ + defaultIndex, + docValueFields, + fields, + filterQuery, + pagination: { querySize }, + sort, + timerange: { from, to }, +}: HostsRequestOptions) => { + const filter = [ + ...createQueryFilterClauses(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..42dbf46305b49 --- /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 { HostLastFirstSeenRequestOptions } from '../../../../../../common/search_strategy/security_solution'; + +export const buildLastFirstSeenHostQuery = ({ + hostName, + defaultIndex, + docValueFields, +}: HostLastFirstSeenRequestOptions) => { + 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..0d99050286c85 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/helpers.ts @@ -0,0 +1,87 @@ +/* + * 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'; + +export const formatHostEdgesData = (fields: readonly string[], bucket: HostAggEsItem): HostsEdges => + fields.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}`, fieldValue, flattenedFields); + } + return flattenedFields; + }, + { + node: {}, + cursor: { + value: '', + tiebreaker: null, + }, + } as HostsEdges + ); + +export const formatHostItem = (fields: readonly string[], bucket: HostAggEsItem): HostItem => + fields.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..d3e4c91b37712 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts @@ -0,0 +1,93 @@ +/* + * 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, + HostDetailsStrategyResponse, + 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 { TermAggregation } from '../../../../lib/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 allHost: SecuritySolutionFactory<'host_all'> = { + 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(options.fields, 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 detailsHost: SecuritySolutionFactory<'host_details'> = { + 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(options.fields, aggregations); + return { ...response, inspect, _id: options.hostName, ...formattedHostItem }; + }, +}; + +export const hostsFactory: Record> = { + host_all: allHost, + host_details: detailsHost, +}; 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..8ede77222bb24 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts @@ -0,0 +1,34 @@ +/* + * 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 { FactoryQueryTypes } from '../../../../common/search_strategy/security_solution'; +import { + HostDetailsStrategyResponse, + HostsStrategyResponse, + HostsRequestOptions, + HostOverviewRequestOptions, +} from '../../../../common/search_strategy/security_solution/hosts'; + +export interface SecuritySolutionFactory { + buildDsl: (options: StrategyRequestType) => unknown; + parse: ( + options: StrategyRequestType, + response: IEsSearchResponse + ) => Promise>; +} + +export type StrategyResponseType = T extends 'host_all' + ? HostsStrategyResponse + : T extends 'host_details' + ? HostDetailsStrategyResponse + : never; + +export type StrategyRequestType = T extends 'host_all' + ? HostsRequestOptions + : T extends 'host_details' + ? HostOverviewRequestOptions + : never; 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..2ee40f70686ac --- /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 } from '../../../common/search_strategy/security_solution'; +import { securitySolutionFactory } from './factory'; +import { + StrategyResponseType, + StrategyRequestType, + 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/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}`); From 0fdc5d6dbab8dd470fe7ea836a4c7843c3125b8e Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Wed, 19 Aug 2020 10:29:28 -0400 Subject: [PATCH 02/11] get security solution search strategy in the public app for all host --- .../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 +- .../public/search/search_interceptor.ts | 2 +- .../security_solution/index.ts | 28 +- .../public/hosts/containers/hosts/index.tsx | 320 ++++++++++-------- .../pages/navigation/hosts_query_tab_body.tsx | 56 ++- .../factory/hosts/dsl/query.hosts.dsl.ts | 1 - .../factory/hosts/helpers.ts | 38 ++- .../security_solution/factory/hosts/index.ts | 4 +- .../security_solution/factory/types.ts | 22 +- .../security_solution/index.ts | 8 +- .../server/utils/build_query/filters.ts | 2 +- 16 files changed, 294 insertions(+), 237 deletions(-) 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 bd9c1b1253fe2..64c16b63f1b94 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -87,9 +87,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..e6d916348ae25 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 = 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 a8b1cdd608a84..9a37fcb6c9aac 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 = 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 = IEsSearchRequest, + SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse + >( + name: string, + strategy: ISearchStrategy + ) => { this.logger.info(`Register strategy ${name}`); this.searchStrategies[name] = strategy; }; 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/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts index 852c7b32e5dab..8fa3dc6835639 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts @@ -5,7 +5,13 @@ */ import { ESQuery } from '../../typed_json'; -import { HostsQueries } from './hosts'; +import { + HostDetailsStrategyResponse, + HostOverviewRequestOptions, + HostsQueries, + HostsRequestOptions, + HostsStrategyResponse, +} from './hosts'; export * from './hosts'; export type Maybe = T | null; @@ -66,27 +72,37 @@ export interface PaginationInputPaginated { querySize: number; } -export interface DocValueFieldsInput { +export interface DocValueFields { field: string; format: string; } export interface RequestBasicOptions { timerange: TimerangeInput; - filterQuery: ESQuery | undefined; + filterQuery: ESQuery | string | undefined; defaultIndex: string[]; - docValueFields?: DocValueFieldsInput[]; + docValueFields?: DocValueFields[]; factoryQueryType?: FactoryQueryTypes; } export interface RequestOptions extends RequestBasicOptions { pagination: PaginationInput; - fields: readonly string[]; sortField?: SortField; } export interface RequestOptionsPaginated extends RequestBasicOptions { pagination: PaginationInputPaginated; - fields: readonly string[]; sortField?: SortField; } + +export type StrategyResponseType = T extends 'host_all' + ? HostsStrategyResponse + : T extends 'host_details' + ? HostDetailsStrategyResponse + : never; + +export type StrategyRequestType = T extends 'host_all' + ? HostsRequestOptions + : T extends 'host_details' + ? 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..ec4730feea2c6 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,205 @@ * 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, + HostsRequestOptions, + HostsStrategyResponse, +} from '../../../../common/search_strategy/security_solution'; +import { ESTermQuery } from '../../../../common/typed_json'; 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: 'host_all', + 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), - }, - updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult) { - return prev; + 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('An error has occurred'); + searchSubscription$.unsubscribe(); } - 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), + error: () => { + notifications.toasts.addDanger('Failed to run search'); + }, }); - }} - - ); - } + }; + 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/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/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 index d4e3fb19d243c..b05aa623ee0c4 100644 --- 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 @@ -15,7 +15,6 @@ import { assertUnreachable, createQueryFilterClauses } from '../../../../../util export const buildHostsQuery = ({ defaultIndex, docValueFields, - fields, filterQuery, pagination: { querySize }, sort, 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 index 0d99050286c85..a7ec822839d21 100644 --- 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 @@ -13,15 +13,21 @@ import { hostFieldsMap } from '../../../../lib/ecs_fields'; import { HostAggEsItem, HostBuckets, HostValue } from '../../../../lib/hosts/types'; -export const formatHostEdgesData = (fields: readonly string[], bucket: HostAggEsItem): HostsEdges => - fields.reduce( +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}`, fieldValue, flattenedFields); + return set( + `node.${fieldName}`, + Array.isArray(fieldValue) ? fieldValue : [fieldValue], + flattenedFields + ); } return flattenedFields; }, @@ -34,8 +40,30 @@ export const formatHostEdgesData = (fields: readonly string[], bucket: HostAggEs } as HostsEdges ); -export const formatHostItem = (fields: readonly string[], bucket: HostAggEsItem): HostItem => - fields.reduce((flattenedFields, fieldName) => { +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); 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 index d3e4c91b37712..f7df6095ef959 100644 --- 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 @@ -46,7 +46,7 @@ export const allHost: SecuritySolutionFactory<'host_all'> = { 'aggregations.host_data.buckets', response.rawResponse ); - const hostsEdges = buckets.map((bucket) => formatHostEdgesData(options.fields, bucket)); + const hostsEdges = buckets.map((bucket) => formatHostEdgesData(bucket)); const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount; const edges = hostsEdges.splice(cursorStart, querySize - cursorStart); const inspect = { @@ -82,7 +82,7 @@ export const detailsHost: SecuritySolutionFactory<'host_details'> = { dsl: [inspectStringifyObject(buildHostOverviewQuery(options))], response: [inspectStringifyObject(response)], }; - const formattedHostItem = formatHostItem(options.fields, aggregations); + const formattedHostItem = formatHostItem(aggregations); return { ...response, inspect, _id: options.hostName, ...formattedHostItem }; }, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts index 8ede77222bb24..50d90cb799476 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts @@ -5,13 +5,11 @@ */ import { IEsSearchResponse } from '../../../../../../../src/plugins/data/common'; -import { FactoryQueryTypes } from '../../../../common/search_strategy/security_solution'; import { - HostDetailsStrategyResponse, - HostsStrategyResponse, - HostsRequestOptions, - HostOverviewRequestOptions, -} from '../../../../common/search_strategy/security_solution/hosts'; + FactoryQueryTypes, + StrategyRequestType, + StrategyResponseType, +} from '../../../../common/search_strategy/security_solution'; export interface SecuritySolutionFactory { buildDsl: (options: StrategyRequestType) => unknown; @@ -20,15 +18,3 @@ export interface SecuritySolutionFactory { response: IEsSearchResponse ) => Promise>; } - -export type StrategyResponseType = T extends 'host_all' - ? HostsStrategyResponse - : T extends 'host_details' - ? HostDetailsStrategyResponse - : never; - -export type StrategyRequestType = T extends 'host_all' - ? HostsRequestOptions - : T extends 'host_details' - ? HostOverviewRequestOptions - : never; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts index 2ee40f70686ac..d94a32174cd7a 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/index.ts @@ -5,13 +5,13 @@ */ import { ISearchStrategy, PluginStart } from '../../../../../../src/plugins/data/server'; -import { FactoryQueryTypes } from '../../../common/search_strategy/security_solution'; -import { securitySolutionFactory } from './factory'; import { + FactoryQueryTypes, StrategyResponseType, StrategyRequestType, - SecuritySolutionFactory, -} from './factory/types'; +} from '../../../common/search_strategy/security_solution'; +import { securitySolutionFactory } from './factory'; +import { SecuritySolutionFactory } from './factory/types'; export const securitySolutionSearchStrategyProvider = ( data: PluginStart 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] : []; From 9756431aca34f82ff4ad069b7ad960088ac49a20 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Wed, 19 Aug 2020 12:43:50 -0400 Subject: [PATCH 03/11] fix types --- src/plugins/data/common/search/es_search/types.ts | 4 ++-- .../search_strategy/security_solution/factory/hosts/index.ts | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/data/common/search/es_search/types.ts b/src/plugins/data/common/search/es_search/types.ts index 6c81202857b05..47e7fbc863bec 100644 --- a/src/plugins/data/common/search/es_search/types.ts +++ b/src/plugins/data/common/search/es_search/types.ts @@ -30,7 +30,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 */ @@ -39,5 +39,5 @@ export interface IEsSearchResponse extends IKibanaSear * Indicates whether the results returned are complete or partial */ isPartial?: boolean; - rawResponse: SearchResponse; + rawResponse: SearchResponse; } 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 index f7df6095ef959..5a04786ab89fa 100644 --- 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 @@ -20,7 +20,6 @@ import { // TO DO need to move all this types in common import { HostAggEsData, HostAggEsItem } from '../../../../lib/hosts/types'; -import { TermAggregation } from '../../../../lib/types'; import { inspectStringifyObject } from '../../../../utils/build_query'; import { SecuritySolutionFactory } from '../types'; @@ -37,7 +36,7 @@ export const allHost: SecuritySolutionFactory<'host_all'> = { }, parse: async ( options: HostsRequestOptions, - response: IEsSearchResponse + response: IEsSearchResponse ): Promise => { const { activePage, cursorStart, fakePossibleCount, querySize } = options.pagination; const totalCount = getOr(0, 'aggregations.host_count.value', response.rawResponse); @@ -75,7 +74,7 @@ export const detailsHost: SecuritySolutionFactory<'host_details'> = { }, parse: async ( options: HostOverviewRequestOptions, - response: IEsSearchResponse + response: IEsSearchResponse ): Promise => { const aggregations: HostAggEsItem = get('aggregations', response.rawResponse) || {}; const inspect = { From 819e0ca6e0ccbfd5d6b612d6d684d4c39c68836e Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Wed, 19 Aug 2020 14:50:00 -0400 Subject: [PATCH 04/11] fix Check core API changes --- .../kibana-plugin-core-public.doclinksstart.md | 2 +- ...ugin-plugins-data-public.iessearchresponse.md | 4 ++-- ...-data-public.iessearchresponse.rawresponse.md | 2 +- ...-plugin-plugins-data-public.isearchgeneric.md | 2 +- ...ugin-plugins-data-server.iessearchresponse.md | 4 ++-- ...-data-server.iessearchresponse.rawresponse.md | 2 +- ...na-plugin-plugins-data-server.isearchsetup.md | 2 +- ...server.isearchsetup.registersearchstrategy.md | 2 +- ...data-server.isearchstart.getsearchstrategy.md | 2 +- ...na-plugin-plugins-data-server.isearchstart.md | 4 ++-- ...plugin-plugins-data-server.isearchstrategy.md | 4 ++-- ...plugins-data-server.isearchstrategy.search.md | 2 +- ...na-plugin-plugins-data-server.plugin.start.md | 4 ++-- src/plugins/data/public/public.api.md | 6 +++--- src/plugins/data/server/server.api.md | 16 ++++++++-------- 15 files changed, 29 insertions(+), 29 deletions(-) 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..f4a25354282e0 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..4f12a3ae41ee1 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 = 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..40cdfdeecae42 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..1e83e72d5c8a9 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..1a04236e0dc57 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..b7d85a970be1f 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/public/public.api.md b/src/plugins/data/public/public.api.md index 58c2bd9957ab8..f8e1f332f43ac 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -792,11 +792,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) @@ -1241,7 +1241,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/server/server.api.md b/src/plugins/data/server/server.api.md index 9c8a79f27a9db..fe609d941bf68 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -496,11 +496,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) @@ -687,19 +687,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) @@ -709,11 +709,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) @@ -860,7 +860,7 @@ export class Plugin implements Plugin_2>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; From 630913509b87caab1e9c7df51a9552908ff4e06c Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Wed, 19 Aug 2020 17:16:44 -0400 Subject: [PATCH 05/11] thank you cypress test --- .../security_solution/factory/hosts/dsl/query.hosts.dsl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index b05aa623ee0c4..f6e128a73882c 100644 --- 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 @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { isEmpty } from 'lodash/fp'; +import { isEmpty, isString } from 'lodash/fp'; import { Direction, HostsRequestOptions, @@ -21,7 +21,7 @@ export const buildHostsQuery = ({ timerange: { from, to }, }: HostsRequestOptions) => { const filter = [ - ...createQueryFilterClauses(filterQuery), + ...createQueryFilterClauses(isString(filterQuery) ? JSON.parse(filterQuery) : filterQuery), { range: { '@timestamp': { From 8cc574e7101b926b9a34ee9feaa8c4ee09a7b314 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Thu, 20 Aug 2020 07:45:50 -0400 Subject: [PATCH 06/11] Remove any by the right type IESearchRequest Co-authored-by: Lukas Olson --- src/plugins/data/server/search/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 9dc49386cc6d8..5fa6c6c04ed40 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -52,7 +52,7 @@ export interface ISearchSetup { } export interface ISearchStart< - SearchStrategyRequest = any, + SearchStrategyRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse > { aggs: AggsStart; From 0b66d2a8045ebccb0ca09a66d16fe4e9c050dbb4 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Thu, 20 Aug 2020 09:06:35 -0400 Subject: [PATCH 07/11] add translation and filter error when we abort the query --- .../public/hosts/containers/hosts/index.tsx | 10 +++++++--- .../hosts/containers/hosts/translations.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts 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 ec4730feea2c6..0f44da3cb541b 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 @@ -23,6 +23,8 @@ import { } from '../../../../common/search_strategy/security_solution'; import { ESTermQuery } from '../../../../common/typed_json'; +import * as i18n from './translations'; + const ID = 'hostsQuery'; type LoadPage = (newActivePage: number) => void; @@ -145,12 +147,14 @@ export const useAllHost = ({ setLoading(false); } // TODO: Make response error status clearer - notifications.toasts.addWarning('An error has occurred'); + notifications.toasts.addWarning(i18n.ERROR_ALL_HOST); searchSubscription$.unsubscribe(); } }, - error: () => { - notifications.toasts.addDanger('Failed to run search'); + error: (msg) => { + if (msg.message !== 'Aborted') { + notifications.toasts.addDanger({ title: i18n.FAIL_ALL_HOST, text: msg.message }); + } }, }); }; 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..2a7c401eff201 --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.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. + */ + +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.errorSearchDescription', { + defaultMessage: `Failed to run search on all hosts`, + }); From 9accea59f35ceaff3f51687f0e221cb3b924f81c Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Thu, 20 Aug 2020 10:32:26 -0400 Subject: [PATCH 08/11] pr review --- ...a-plugin-plugins-data-public.isearchgeneric.md | 2 +- ...ana-plugin-plugins-data-server.isearchsetup.md | 2 +- ...-server.isearchsetup.registersearchstrategy.md | 2 +- ...ana-plugin-plugins-data-server.isearchstart.md | 2 +- ...-plugin-plugins-data-server.isearchstrategy.md | 2 +- ...ana-plugin-plugins-data-server.plugin.start.md | 4 ++-- src/plugins/data/public/public.api.md | 2 +- src/plugins/data/public/search/types.ts | 2 +- src/plugins/data/server/search/search_service.ts | 4 ++-- src/plugins/data/server/search/types.ts | 6 +++--- src/plugins/data/server/server.api.md | 8 ++++---- .../security_solution/hosts/index.ts | 7 +++++-- .../search_strategy/security_solution/index.ts | 15 ++++++++------- .../public/hosts/containers/hosts/index.tsx | 3 ++- .../public/hosts/containers/hosts/translations.ts | 8 +++++--- .../factory/hosts/dsl/query.detail_host.dsl.ts | 3 ++- .../factory/hosts/dsl/query.hosts.dsl.ts | 3 ++- .../hosts/dsl/query.last_first_seen_host.dsl.ts | 4 ++-- .../security_solution/factory/hosts/index.ts | 12 ++++++------ .../security_solution/factory/types.ts | 7 +++++-- 20 files changed, 55 insertions(+), 43 deletions(-) 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 f4a25354282e0..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: SearchStrategyRequest, 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.isearchsetup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md index 4f12a3ae41ee1..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) | <SearchStrategyRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse>(name: string, strategy: ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse>) => 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 40cdfdeecae42..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.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md index 1e83e72d5c8a9..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 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 1a04236e0dc57..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 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 b7d85a970be1f..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/public/public.api.md b/src/plugins/data/public/public.api.md index 5ba3c93094aa4..6efa4e05f3b16 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1241,7 +1241,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: SearchStrategyRequest, 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/types.ts b/src/plugins/data/public/search/types.ts index e6d916348ae25..55726e40f5a77 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -44,7 +44,7 @@ export type ISearch = ( ) => Observable; export type ISearchGeneric = < - SearchStrategyRequest = IEsSearchRequest, + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse >( request: SearchStrategyRequest, diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 9a37fcb6c9aac..a522cef23a991 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -40,7 +40,7 @@ import { searchTelemetry } from '../saved_objects'; import { IEsSearchRequest, IEsSearchResponse } from '../../common'; type StrategyMap< - SearchStrategyRequest = IEsSearchRequest, + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse > = Record>; @@ -127,7 +127,7 @@ export class SearchService implements Plugin { } private registerSearchStrategy = < - SearchStrategyRequest = IEsSearchRequest, + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse >( name: string, diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 5fa6c6c04ed40..56f803512aa19 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -38,7 +38,7 @@ export interface ISearchSetup { * strategies. */ registerSearchStrategy: < - SearchStrategyRequest = IEsSearchRequest, + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse >( name: string, @@ -52,7 +52,7 @@ export interface ISearchSetup { } export interface ISearchStart< - SearchStrategyRequest = IEsSearchRequest, + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse > { aggs: AggsStart; @@ -75,7 +75,7 @@ export interface ISearchStart< * that resolves to a response. */ export interface ISearchStrategy< - SearchStrategyRequest = IEsSearchRequest, + SearchStrategyRequest extends IEsSearchRequest = IEsSearchRequest, SearchStrategyResponse extends IEsSearchResponse = IEsSearchResponse > { search: ( diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 57e2f6be1c43b..969eb721143d2 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -688,14 +688,14 @@ 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) @@ -710,7 +710,7 @@ export interface ISearchStart { +export interface ISearchStrategy { // (undocumented) cancel?: (context: RequestHandlerContext, id: string) => Promise; // (undocumented) @@ -861,7 +861,7 @@ export class Plugin implements Plugin_2>; + search: ISearchStart>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; 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 index c4f067deffa34..3a0942d2decb8 100644 --- 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 @@ -18,7 +18,10 @@ import { TimerangeInput, } from '..'; -export type HostsQueries = 'host_all' | 'host_details'; +export enum HostsQueries { + hosts = 'hosts', + hostOverview = 'hostOverview', +} export enum HostPolicyResponseActionStatus { success = 'success', @@ -62,7 +65,7 @@ export interface HostsStrategyResponse extends IEsSearchResponse { inspect?: Maybe; } -export interface HostDetailsStrategyResponse extends IEsSearchResponse, HostItem { +export interface HostOverviewStrategyResponse extends IEsSearchResponse, HostItem { inspect?: Maybe; } diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts index 8fa3dc6835639..edb5dda2ca6da 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts @@ -4,9 +4,10 @@ * 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 { - HostDetailsStrategyResponse, + HostOverviewStrategyResponse, HostOverviewRequestOptions, HostsQueries, HostsRequestOptions, @@ -77,7 +78,7 @@ export interface DocValueFields { format: string; } -export interface RequestBasicOptions { +export interface RequestBasicOptions extends IEsSearchRequest { timerange: TimerangeInput; filterQuery: ESQuery | string | undefined; defaultIndex: string[]; @@ -95,14 +96,14 @@ export interface RequestOptionsPaginated extends RequestBasicOptions { sortField?: SortField; } -export type StrategyResponseType = T extends 'host_all' +export type StrategyResponseType = T extends HostsQueries.hosts ? HostsStrategyResponse - : T extends 'host_details' - ? HostDetailsStrategyResponse + : T extends HostsQueries.hostOverview + ? HostOverviewStrategyResponse : never; -export type StrategyRequestType = T extends 'host_all' +export type StrategyRequestType = T extends HostsQueries.hosts ? HostsRequestOptions - : T extends 'host_details' + : 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 0f44da3cb541b..55a387f563e12 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 @@ -18,6 +18,7 @@ import { hostsModel, hostsSelectors } from '../../store'; import { generateTablePaginationOptions } from '../../../common/components/paginated_table/helpers'; import { DocValueFields, + HostsQueries, HostsRequestOptions, HostsStrategyResponse, } from '../../../../common/search_strategy/security_solution'; @@ -68,7 +69,7 @@ export const useAllHost = ({ const [hostsRequest, setHostRequest] = useState({ defaultIndex, docValueFields: docValueFields ?? [], - factoryQueryType: 'host_all', + factoryQueryType: HostsQueries.hosts, filterQuery: createFilter(filterQuery), pagination: generateTablePaginationOptions(activePage, limit), timerange: { 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 index 2a7c401eff201..ab666bd3de6bb 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts @@ -13,7 +13,9 @@ export const ERROR_ALL_HOST = i18n.translate( } ); -export const FAIL_ALL_HOST = () => - i18n.translate('xpack.securitySolution.allHost.errorSearchDescription', { +export const FAIL_ALL_HOST = i18n.translate( + 'xpack.securitySolution.allHost.errorSearchDescription', + { defaultMessage: `Failed to run search on all hosts`, - }); + } +); 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 index 140a66be73eef..5c5dec92a5100 100644 --- 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 @@ -4,6 +4,7 @@ * 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'; @@ -14,7 +15,7 @@ export const buildHostOverviewQuery = ({ hostName, defaultIndex, timerange: { from, to }, -}: HostOverviewRequestOptions) => { +}: HostOverviewRequestOptions): ISearchRequestParams => { const esFields = reduceFields(fields, { ...hostFieldsMap, ...cloudFieldsMap }); const filter = [ 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 index f6e128a73882c..3d72f98f35355 100644 --- 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 @@ -5,6 +5,7 @@ */ import { isEmpty, isString } from 'lodash/fp'; +import { ISearchRequestParams } from '../../../../../../../../../src/plugins/data/common'; import { Direction, HostsRequestOptions, @@ -19,7 +20,7 @@ export const buildHostsQuery = ({ pagination: { querySize }, sort, timerange: { from, to }, -}: HostsRequestOptions) => { +}: HostsRequestOptions): ISearchRequestParams => { const filter = [ ...createQueryFilterClauses(isString(filterQuery) ? JSON.parse(filterQuery) : filterQuery), { 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 index 42dbf46305b49..b57bbd2960e4f 100644 --- 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 @@ -5,14 +5,14 @@ */ 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) => { +}: HostLastFirstSeenRequestOptions): ISearchRequestParams => { const filter = [{ term: { 'host.name': hostName } }]; const dslQuery = { 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 index 5a04786ab89fa..443e524d71ca3 100644 --- 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 @@ -12,7 +12,7 @@ import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../common/constants'; import { FactoryQueryTypes } from '../../../../../common/search_strategy/security_solution'; import { HostsStrategyResponse, - HostDetailsStrategyResponse, + HostOverviewStrategyResponse, HostsQueries, HostsRequestOptions, HostOverviewRequestOptions, @@ -27,7 +27,7 @@ import { buildHostOverviewQuery } from './dsl/query.detail_host.dsl'; import { buildHostsQuery } from './dsl/query.hosts.dsl'; import { formatHostEdgesData, formatHostItem } from './helpers'; -export const allHost: SecuritySolutionFactory<'host_all'> = { +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}`); @@ -68,14 +68,14 @@ export const allHost: SecuritySolutionFactory<'host_all'> = { }, }; -export const detailsHost: SecuritySolutionFactory<'host_details'> = { +export const overviewHost: SecuritySolutionFactory = { buildDsl: (options: HostOverviewRequestOptions) => { return buildHostOverviewQuery(options); }, parse: async ( options: HostOverviewRequestOptions, response: IEsSearchResponse - ): Promise => { + ): Promise => { const aggregations: HostAggEsItem = get('aggregations', response.rawResponse) || {}; const inspect = { dsl: [inspectStringifyObject(buildHostOverviewQuery(options))], @@ -87,6 +87,6 @@ export const detailsHost: SecuritySolutionFactory<'host_details'> = { }; export const hostsFactory: Record> = { - host_all: allHost, - host_details: detailsHost, + [HostsQueries.hosts]: allHosts, + [HostsQueries.hostOverview]: overviewHost, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts index 50d90cb799476..cb9e3a3d7628a 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/types.ts @@ -4,7 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IEsSearchResponse } from '../../../../../../../src/plugins/data/common'; +import { + IEsSearchResponse, + ISearchRequestParams, +} from '../../../../../../../src/plugins/data/common'; import { FactoryQueryTypes, StrategyRequestType, @@ -12,7 +15,7 @@ import { } from '../../../../common/search_strategy/security_solution'; export interface SecuritySolutionFactory { - buildDsl: (options: StrategyRequestType) => unknown; + buildDsl: (options: StrategyRequestType) => ISearchRequestParams; parse: ( options: StrategyRequestType, response: IEsSearchResponse From 8731418f3ceeb1dc873886904397b63af1abe8b8 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Thu, 20 Aug 2020 13:25:49 -0400 Subject: [PATCH 09/11] fix translation --- .../public/hosts/containers/hosts/translations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index ab666bd3de6bb..ada713d135c22 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/translations.ts @@ -14,7 +14,7 @@ export const ERROR_ALL_HOST = i18n.translate( ); export const FAIL_ALL_HOST = i18n.translate( - 'xpack.securitySolution.allHost.errorSearchDescription', + 'xpack.securitySolution.allHost.failSearchDescription', { defaultMessage: `Failed to run search on all hosts`, } From 1a38f1e8894fb6cb9ccab585097142f062622265 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Fri, 21 Aug 2020 21:35:14 -0400 Subject: [PATCH 10/11] review II --- .../security_solution/public/hosts/containers/hosts/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 55a387f563e12..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 @@ -25,6 +25,7 @@ import { import { ESTermQuery } from '../../../../common/typed_json'; import * as i18n from './translations'; +import { AbortError } from '../../../../../../../src/plugins/data/common'; const ID = 'hostsQuery'; @@ -153,7 +154,7 @@ export const useAllHost = ({ } }, error: (msg) => { - if (msg.message !== 'Aborted') { + if (!(msg instanceof AbortError)) { notifications.toasts.addDanger({ title: i18n.FAIL_ALL_HOST, text: msg.message }); } }, From d70def0856671b879038752f1e58409b58e947e2 Mon Sep 17 00:00:00 2001 From: Xavier Mouligneau <189600+XavierM@users.noreply.github.com> Date: Sat, 22 Aug 2020 06:26:43 -0400 Subject: [PATCH 11/11] fix merge issue --- src/plugins/data/server/search/search_service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 07705e4267717..cc23c455bed26 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -133,7 +133,7 @@ export class SearchService implements Plugin { name: string, strategy: ISearchStrategy ) => { - this.logger.info(`Register strategy ${name}`); + this.logger.debug(`Register strategy ${name}`); this.searchStrategies[name] = strategy; };