From c9ed87c696ff99f257fba6619072f2aa6d198cbd Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Tue, 17 Dec 2019 11:56:33 +0100 Subject: [PATCH 01/60] [SIEM] Fix Edit Filter suggestions displayed behind Filter Popover (#53166) --- .../components/edit_data_provider/index.tsx | 184 ++++++++---------- .../siem/public/components/loading/index.tsx | 52 ++--- .../siem/public/components/page/index.tsx | 13 ++ 3 files changed, 120 insertions(+), 129 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/edit_data_provider/index.tsx b/x-pack/legacy/plugins/siem/public/components/edit_data_provider/index.tsx index 18b271a3abc297..87e83e0c47b6d2 100644 --- a/x-pack/legacy/plugins/siem/public/components/edit_data_provider/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/edit_data_provider/index.tsx @@ -18,7 +18,7 @@ import { EuiToolTip, } from '@elastic/eui'; import React, { useEffect, useState, useCallback } from 'react'; -import styled, { createGlobalStyle } from 'styled-components'; +import styled from 'styled-components'; import { BrowserFields } from '../../containers/source'; import { OnDataProviderEdited } from '../timeline/events'; @@ -46,15 +46,6 @@ export const HeaderContainer = styled.div` HeaderContainer.displayName = 'HeaderContainer'; -// SIDE EFFECT: the following `createGlobalStyle` overrides the default styling -// of euiComboBoxOptionsList because it's implemented as a popover, so it's -// not selectable as a child of the styled component -const StatefulEditDataProviderGlobalStyle = createGlobalStyle` - .euiComboBoxOptionsList { - z-index: 9999; - } -`; - interface Props { andProviderId?: string; browserFields: BrowserFields; @@ -157,107 +148,104 @@ export const StatefulEditDataProvider = React.memo( }, []); return ( - <> - - - - - - - 0 ? updatedField[0].label : null}> - - - - - - - + + + + + + + 0 ? updatedField[0].label : null}> - - - - - - - - + + + - {updatedOperator.length > 0 && - updatedOperator[0].label !== i18n.EXISTS && - updatedOperator[0].label !== i18n.DOES_NOT_EXIST ? ( - - + - ) : null} + + - - - + + + + {updatedOperator.length > 0 && + updatedOperator[0].label !== i18n.EXISTS && + updatedOperator[0].label !== i18n.DOES_NOT_EXIST ? ( - - - { - onDataProviderEdited({ - andProviderId, - excluded: getExcludedFromSelection(updatedOperator), - field: updatedField.length > 0 ? updatedField[0].label : '', - id: timelineId, - operator: getQueryOperatorFromSelection(updatedOperator), - providerId, - value: updatedValue, - }); - }} - size="s" - > - {i18n.SAVE} - - - + + + - - - - + ) : null} + + + + + + + + + { + onDataProviderEdited({ + andProviderId, + excluded: getExcludedFromSelection(updatedOperator), + field: updatedField.length > 0 ? updatedField[0].label : '', + id: timelineId, + operator: getQueryOperatorFromSelection(updatedOperator), + providerId, + value: updatedValue, + }); + }} + size="s" + > + {i18n.SAVE} + + + + + + ); } ); diff --git a/x-pack/legacy/plugins/siem/public/components/loading/index.tsx b/x-pack/legacy/plugins/siem/public/components/loading/index.tsx index 1a3c2fefbf47f0..cd437911ab5897 100644 --- a/x-pack/legacy/plugins/siem/public/components/loading/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/loading/index.tsx @@ -6,14 +6,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiPanel, EuiText } from '@elastic/eui'; import * as React from 'react'; -import styled, { createGlobalStyle } from 'styled-components'; - -// SIDE EFFECT: the following `createGlobalStyle` overrides default styling in angular code that was not theme-friendly -const LoadingPanelGlobalStyle = createGlobalStyle` - .euiPanel-loading-hide-border { - border: none; - } -`; +import styled from 'styled-components'; const SpinnerFlexItem = styled(EuiFlexItem)` margin-right: 5px; @@ -39,30 +32,27 @@ export const LoadingPanel = React.memo( position = 'relative', zIndex = 'inherit', }) => ( - <> - - - - - - - + + + + + + + - - {text} - - - - - - - + + {text} + + + + + ) ); diff --git a/x-pack/legacy/plugins/siem/public/components/page/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/index.tsx index 5782a90ffa106a..781155c3ddc381 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/index.tsx @@ -34,6 +34,19 @@ export const AppGlobalStyle = createGlobalStyle` .euiToolTip { z-index: 9950 !important; } + + /* + overrides the default styling of euiComboBoxOptionsList because it's implemented + as a popover, so it's not selectable as a child of the styled component + */ + .euiComboBoxOptionsList { + z-index: 9999; + } + + /* overrides default styling in angular code that was not theme-friendly */ + .euiPanel-loading-hide-border { + border: none; + } `; export const DescriptionListStyled = styled(EuiDescriptionList)` From fc1911931d7190cc7f6a0513cbc682e129c9abfc Mon Sep 17 00:00:00 2001 From: Andrew Wilkins Date: Tue, 17 Dec 2019 19:01:55 +0800 Subject: [PATCH 02/60] update apm index pattern (#53250) --- .../core_plugins/kibana/server/tutorials/apm/index_pattern.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json b/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json index 9001613623ccb8..25ce0cb58a0ca8 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json +++ b/src/legacy/core_plugins/kibana/server/tutorials/apm/index_pattern.json @@ -1,7 +1,7 @@ { "attributes": { "fieldFormatMap": "{\"client.bytes\":{\"id\":\"bytes\"},\"client.nat.port\":{\"id\":\"string\"},\"client.port\":{\"id\":\"string\"},\"destination.bytes\":{\"id\":\"bytes\"},\"destination.nat.port\":{\"id\":\"string\"},\"destination.port\":{\"id\":\"string\"},\"event.duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"nanoseconds\",\"outputFormat\":\"asMilliseconds\",\"outputPrecision\":1}},\"event.sequence\":{\"id\":\"string\"},\"event.severity\":{\"id\":\"string\"},\"http.request.body.bytes\":{\"id\":\"bytes\"},\"http.request.bytes\":{\"id\":\"bytes\"},\"http.response.body.bytes\":{\"id\":\"bytes\"},\"http.response.bytes\":{\"id\":\"bytes\"},\"http.response.status_code\":{\"id\":\"string\"},\"log.syslog.facility.code\":{\"id\":\"string\"},\"log.syslog.priority\":{\"id\":\"string\"},\"network.bytes\":{\"id\":\"bytes\"},\"package.size\":{\"id\":\"string\"},\"process.pgid\":{\"id\":\"string\"},\"process.pid\":{\"id\":\"string\"},\"process.ppid\":{\"id\":\"string\"},\"process.thread.id\":{\"id\":\"string\"},\"server.bytes\":{\"id\":\"bytes\"},\"server.nat.port\":{\"id\":\"string\"},\"server.port\":{\"id\":\"string\"},\"source.bytes\":{\"id\":\"bytes\"},\"source.nat.port\":{\"id\":\"string\"},\"source.port\":{\"id\":\"string\"},\"system.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.memory.actual.free\":{\"id\":\"bytes\"},\"system.memory.total\":{\"id\":\"bytes\"},\"system.process.cpu.total.norm.pct\":{\"id\":\"percent\"},\"system.process.memory.rss.bytes\":{\"id\":\"bytes\"},\"system.process.memory.size\":{\"id\":\"bytes\"},\"url.port\":{\"id\":\"string\"},\"view spans\":{\"id\":\"url\",\"params\":{\"labelTemplate\":\"View Spans\"}}}", - "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.cpu.ns\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.samples.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]", + "fields": "[{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"@timestamp\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"client.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.account.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.availability_zone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.instance.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.machine.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.region\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.image.tag\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"container.runtime\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"destination.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.data\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.ttl\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.answers.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.header_flags\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.op_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.class\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.subdomain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.question.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.resolved_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.response_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"dns.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"ecs.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.stack_trace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.category\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.dataset\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.end\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.kind\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.outcome\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.provider\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.risk_score_norm\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.sequence\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.severity\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.timezone\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"event.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.accessed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.created\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.ctime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.device\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.gid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.group\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.inode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mode\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.mtime\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.owner\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.target_path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"file.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.method\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.request.referrer\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.body.content\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.status_code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.logger\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.file.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.origin.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.facility.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.priority\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.code\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"log.syslog.severity.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.application\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.community_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.direction\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.forwarded_ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.iana_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.protocol\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.transport\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"network.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.product\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.serial_number\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.vendor\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.architecture\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.checksum\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.description\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.install_scope\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.installed\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.license\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"package.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.args\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.executable\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.md5\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha1\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha256\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.hash.sha512\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pgid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.pid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.ppid\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.start\",\"scripted\":false,\"searchable\":true,\"type\":\"date\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.id\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.thread.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.title\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.uptime\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"process.working_directory\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"related.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"server.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.ephemeral_id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.state\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.address\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.number\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.as.organization.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.city_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.continent_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.country_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.location\",\"scripted\":false,\"searchable\":true,\"type\":\"geo_point\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_iso_code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.geo.region_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.mac\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.ip\",\"scripted\":false,\"searchable\":true,\"type\":\"ip\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.nat.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.packets\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"source.user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.framework\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.tactic.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"threat.technique.reference\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"tracing.transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.extension\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.fragment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.password\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.path\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.port\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.query\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.registered_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.scheme\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.top_level_domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"url.username\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.email\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.full_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.domain\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.group.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.hash\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.device.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.family\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.full\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.kernel\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.platform\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.os.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"agent.hostname\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"fields\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"timeseries.instance\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.project.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"cloud.image.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"docker.container.labels\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.containerized\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.build\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"host.os.codename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.pod.uid\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.namespace\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.node.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.labels.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.annotations.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.replicaset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.deployment.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.statefulset.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"kubernetes.container.image\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"processor.event\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"timestamp.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.request.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"http.response.finished\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"enabled\":false,\"indexed\":false,\"name\":\"http.response.headers\",\"scripted\":false,\"searchable\":false},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.environment\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.language.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.runtime.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"service.framework.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.sampled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.name.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.breakdown.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.subtype\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.self_time.sum.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"trace.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"parent.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.listening\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"observer.version_major\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"user_agent.original.text\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"experimental\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.culprit\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.grouping_key\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.code\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.module\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":4,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.exception.handled\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.level\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.logger_name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":2,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"error.log.param_message\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.total\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.memory.actual.free\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.cpu.total.norm.pct\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.size\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"system.process.memory.rss.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.cpu.ns\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.samples.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.alloc_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_objects.count\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.inuse_space.bytes\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.duration\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.top.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.function\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.filename\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"profile.stack.line\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.service.version\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"sourcemap.bundle_filepath\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"view spans\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.id\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.action\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.start.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":1,\"doc_values\":true,\"indexed\":true,\"name\":\"span.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.sync\",\"scripted\":false,\"searchable\":true,\"type\":\"boolean\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.db.link\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.name\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"span.destination.service.resource\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.duration.us\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.result\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.marks.*.*\",\"scripted\":false,\"searchable\":true},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":true,\"indexed\":true,\"name\":\"transaction.span_count.dropped\",\"scripted\":false,\"searchable\":true,\"type\":\"number\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_id\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":true,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_type\",\"scripted\":false,\"searchable\":true,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_index\",\"scripted\":false,\"searchable\":false,\"type\":\"string\"},{\"aggregatable\":false,\"analyzed\":false,\"count\":0,\"doc_values\":false,\"indexed\":false,\"name\":\"_score\",\"scripted\":false,\"searchable\":false,\"type\":\"number\"}]", "sourceFilters": "[{\"value\":\"sourcemap.sourcemap\"}]", "timeFieldName": "@timestamp" }, From 2ef2bcaee6cd85a6eb976c0aac425f45bfbc4ea2 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 17 Dec 2019 12:02:49 +0100 Subject: [PATCH 03/60] [Dashboard] Deangularize saved object handling (SavedObjectDashboard) (#52850) * Initial typescript version * Use extracted functions * Fix types * Extract save & initialize functions * Add even more typescript * Improve types * Improving types, extracting another function * Code refactoring, deangularisation, migrate to Promise * Migrate Visualize AngularPromise to native promise * Fix Discover Edit URL link * Migrate to use of NP services (savedObjects + indexPatterns) * Migrate confirmModalPromise to a NP backed version - add code :) * cleanup confirmModalPromise, fix creation of visualize data table * Fix JSON import test * Remove init from types * Split between createSavedObjectClass and SavedObjectProvider * Adapt Discover to use deangularized SavedObject version * Fix type errors * Remove redundant file * Fix functional test failure importing JSON * Migrate chrome.untrackNavLinksForDeletedSavedObjects * Improve types * Code improvements * Require NP chrome for SavedObjectLoader * Fix type error * Fix IndexPatterns type error * maja review improvements * Fix broken functional test * Add missing static properties of SavedSearch class * Migrate indexPatterns to data plugin * Deangularize saved_workspaces.js and saved_workspaces.js * Fix types * Migrate to TypeScript * use encodeURIComponent in saved_visualizations.js, remove kbnUrl * Remove unnecessary type cast * Further deangularize gis_map_saved_object_loader.js * Remove npStart imports from helper functions * Fix types * Review changes * Improve types * Fix mocha tests that broke due to refactoring * Add more types * Add missing savedObjects property in dashboard_app_controller.tsx * Type improvements * Convert saved_dashboard.js to saved_dashboard.ts * Convert saved_dashboard.js to saved_dashboard.ts * remove console.error * fix jest tests * Address review comments * Solve type conflict * Fix types * Adapt types * Restore statics values at SavedSearch * Revert "Address review comments" This reverts commit 87b0ba7e2f9f99059457a8203e0c9a68170626a6. * Revert "Restore statics values at SavedSearch" This reverts commit 5b7b989ac590224c4ab565616c69756cbd34d8fc. * Restore statics values at SavedSearch * Complete TypeScript conversion * Fix types * Set seachSource to true * Fix tests * Minor adaptions * Migrate import from 'kibana/server' to 'kibana/public' * Remove redundant ! from savedDashboard.searchSource --- .../saved_dashboard/saved_dashboard.d.ts | 42 ------- .../saved_dashboard/saved_dashboard.js | 116 ----------------- .../saved_dashboard/saved_dashboard.ts | 118 ++++++++++++++++++ ....js => saved_dashboard_references.test.ts} | 32 ++--- ...ences.js => saved_dashboard_references.ts} | 22 +++- ...egister.js => saved_dashboard_register.ts} | 2 +- ...aved_dashboards.js => saved_dashboards.ts} | 22 +++- .../saved_objects/helpers/apply_es_resp.ts | 22 ++-- src/legacy/ui/public/saved_objects/types.ts | 2 +- 9 files changed, 179 insertions(+), 199 deletions(-) delete mode 100644 src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts delete mode 100644 src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts rename src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/{saved_dashboard_references.test.js => saved_dashboard_references.test.ts} (91%) rename src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/{saved_dashboard_references.js => saved_dashboard_references.ts} (79%) rename src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/{saved_dashboard_register.js => saved_dashboard_register.ts} (93%) rename src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/{saved_dashboards.js => saved_dashboards.ts} (68%) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts deleted file mode 100644 index 20544fa97fdb09..00000000000000 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { SavedObject } from 'ui/saved_objects/types'; -import { SearchSourceContract } from '../../../../../ui/public/courier'; -import { esFilters, Query, RefreshInterval } from '../../../../../../plugins/data/public'; - -export interface SavedObjectDashboard extends SavedObject { - id?: string; - copyOnSave: boolean; - timeRestore: boolean; - timeTo?: string; - timeFrom?: string; - title: string; - description?: string; - panelsJSON: string; - optionsJSON?: string; - // TODO: write a migration to rid of this, it's only around for bwc. - uiStateJSON?: string; - lastSavedTitle: string; - searchSource: SearchSourceContract; - destroy: () => void; - refreshInterval?: RefreshInterval; - getQuery(): Query; - getFilters(): esFilters.Filter[]; -} diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js deleted file mode 100644 index a98625cf3af929..00000000000000 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import angular from 'angular'; -import { uiModules } from 'ui/modules'; -import { createDashboardEditUrl } from '../dashboard_constants'; -import { createLegacyClass } from 'ui/utils/legacy_class'; -import { SavedObjectProvider } from 'ui/saved_objects/saved_object'; -import { extractReferences, injectReferences } from './saved_dashboard_references'; - -const module = uiModules.get('app/dashboard'); - -// Used only by the savedDashboards service, usually no reason to change this -module.factory('SavedDashboard', function(Private) { - // SavedDashboard constructor. Usually you'd interact with an instance of this. - // ID is option, without it one will be generated on save. - const SavedObject = Private(SavedObjectProvider); - createLegacyClass(SavedDashboard).inherits(SavedObject); - function SavedDashboard(id) { - // Gives our SavedDashboard the properties of a SavedObject - SavedDashboard.Super.call(this, { - type: SavedDashboard.type, - mapping: SavedDashboard.mapping, - searchSource: SavedDashboard.searchsource, - extractReferences: extractReferences, - injectReferences: injectReferences, - - // if this is null/undefined then the SavedObject will be assigned the defaults - id: id, - - // default values that will get assigned if the doc is new - defaults: { - title: '', - hits: 0, - description: '', - panelsJSON: '[]', - optionsJSON: angular.toJson({ - // for BWC reasons we can't default dashboards that already exist without this setting to true. - useMargins: id ? false : true, - hidePanelTitles: false, - }), - version: 1, - timeRestore: false, - timeTo: undefined, - timeFrom: undefined, - refreshInterval: undefined, - }, - - // if an indexPattern was saved with the searchsource of a SavedDashboard - // object, clear it. It was a mistake - clearSavedIndexPattern: true, - }); - - this.showInRecentlyAccessed = true; - } - - // save these objects with the 'dashboard' type - SavedDashboard.type = 'dashboard'; - - // if type:dashboard has no mapping, we push this mapping into ES - SavedDashboard.mapping = { - title: 'text', - hits: 'integer', - description: 'text', - panelsJSON: 'text', - optionsJSON: 'text', - version: 'integer', - timeRestore: 'boolean', - timeTo: 'keyword', - timeFrom: 'keyword', - refreshInterval: { - type: 'object', - properties: { - display: { type: 'keyword' }, - pause: { type: 'boolean' }, - section: { type: 'integer' }, - value: { type: 'integer' }, - }, - }, - }; - - // Order these fields to the top, the rest are alphabetical - SavedDashboard.fieldOrder = ['title', 'description']; - - SavedDashboard.searchsource = true; - - SavedDashboard.prototype.getFullPath = function() { - return `/app/kibana#${createDashboardEditUrl(this.id)}`; - }; - - SavedDashboard.prototype.getQuery = function() { - return this.searchSource.getOwnField('query') || { query: '', language: 'kuery' }; - }; - - SavedDashboard.prototype.getFilters = function() { - return this.searchSource.getOwnField('filter') || []; - }; - - return SavedDashboard; -}); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts new file mode 100644 index 00000000000000..dc52b3ab7ad177 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.ts @@ -0,0 +1,118 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SearchSourceContract } from 'ui/courier'; +import { SavedObject, SavedObjectKibanaServices } from 'ui/saved_objects/types'; +import { createSavedObjectClass } from 'ui/saved_objects/saved_object'; +import { extractReferences, injectReferences } from './saved_dashboard_references'; +import { createDashboardEditUrl } from '../dashboard_constants'; + +import { esFilters, Query, RefreshInterval } from '../../../../../../plugins/data/public'; + +export interface SavedObjectDashboard extends SavedObject { + id?: string; + timeRestore: boolean; + timeTo?: string; + timeFrom?: string; + description?: string; + panelsJSON: string; + optionsJSON?: string; + // TODO: write a migration to rid of this, it's only around for bwc. + uiStateJSON?: string; + lastSavedTitle: string; + refreshInterval?: RefreshInterval; + searchSource: SearchSourceContract; + getQuery(): Query; + getFilters(): esFilters.Filter[]; +} + +// Used only by the savedDashboards service, usually no reason to change this +export function createSavedDashboardClass(services: SavedObjectKibanaServices) { + const SavedObjectClass = createSavedObjectClass(services); + class SavedDashboard extends SavedObjectClass { + // save these objects with the 'dashboard' type + public static type = 'dashboard'; + + // if type:dashboard has no mapping, we push this mapping into ES + public static mapping = { + title: 'text', + hits: 'integer', + description: 'text', + panelsJSON: 'text', + optionsJSON: 'text', + version: 'integer', + timeRestore: 'boolean', + timeTo: 'keyword', + timeFrom: 'keyword', + refreshInterval: { + type: 'object', + properties: { + display: { type: 'keyword' }, + pause: { type: 'boolean' }, + section: { type: 'integer' }, + value: { type: 'integer' }, + }, + }, + }; + public static fieldOrder = ['title', 'description']; + public static searchSource = true; + public showInRecentlyAccessed = true; + + constructor(id: string) { + super({ + type: SavedDashboard.type, + mapping: SavedDashboard.mapping, + searchSource: SavedDashboard.searchSource, + extractReferences, + injectReferences, + + // if this is null/undefined then the SavedObject will be assigned the defaults + id, + + // default values that will get assigned if the doc is new + defaults: { + title: '', + hits: 0, + description: '', + panelsJSON: '[]', + optionsJSON: JSON.stringify({ + // for BWC reasons we can't default dashboards that already exist without this setting to true. + useMargins: !id, + hidePanelTitles: false, + }), + version: 1, + timeRestore: false, + timeTo: undefined, + timeFrom: undefined, + refreshInterval: undefined, + }, + }); + this.getFullPath = () => `/app/kibana#${createDashboardEditUrl(String(this.id))}`; + } + + getQuery() { + return this.searchSource!.getOwnField('query') || { query: '', language: 'kuery' }; + } + + getFilters() { + return this.searchSource!.getOwnField('filter') || []; + } + } + + return SavedDashboard; +} diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.test.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.test.ts similarity index 91% rename from src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.test.js rename to src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.test.ts index efb596b1a86d37..48f15e84c93072 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.test.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.test.ts @@ -18,6 +18,7 @@ */ import { extractReferences, injectReferences } from './saved_dashboard_references'; +import { SavedObjectDashboard } from './saved_dashboard'; describe('extractReferences', () => { test('extracts references from panelsJSON', () => { @@ -38,6 +39,7 @@ describe('extractReferences', () => { }, ]), }, + references: [], }; const updatedDoc = extractReferences(doc); @@ -75,6 +77,7 @@ Object { }, ]), }, + references: [], }; expect(() => extractReferences(doc)).toThrowErrorMatchingInlineSnapshot( `"\\"type\\" attribute is missing from panel \\"0\\""` @@ -93,6 +96,7 @@ Object { }, ]), }, + references: [], }; expect(extractReferences(doc)).toMatchInlineSnapshot(` Object { @@ -110,7 +114,7 @@ describe('injectReferences', () => { test('injects references into context', () => { const context = { id: '1', - foo: true, + title: 'test', panelsJSON: JSON.stringify([ { panelRefName: 'panel_0', @@ -121,7 +125,7 @@ describe('injectReferences', () => { title: 'Title 2', }, ]), - }; + } as SavedObjectDashboard; const references = [ { name: 'panel_0', @@ -138,9 +142,9 @@ describe('injectReferences', () => { expect(context).toMatchInlineSnapshot(` Object { - "foo": true, "id": "1", "panelsJSON": "[{\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\",\\"type\\":\\"visualization\\"},{\\"title\\":\\"Title 2\\",\\"id\\":\\"2\\",\\"type\\":\\"visualization\\"}]", + "title": "test", } `); }); @@ -148,13 +152,13 @@ Object { test('skips when panelsJSON is missing', () => { const context = { id: '1', - foo: true, - }; + title: 'test', + } as SavedObjectDashboard; injectReferences(context, []); expect(context).toMatchInlineSnapshot(` Object { - "foo": true, "id": "1", + "title": "test", } `); }); @@ -162,15 +166,15 @@ Object { test('skips when panelsJSON is not an array', () => { const context = { id: '1', - foo: true, panelsJSON: '{}', - }; + title: 'test', + } as SavedObjectDashboard; injectReferences(context, []); expect(context).toMatchInlineSnapshot(` Object { - "foo": true, "id": "1", "panelsJSON": "{}", + "title": "test", } `); }); @@ -178,7 +182,7 @@ Object { test('skips a panel when panelRefName is missing', () => { const context = { id: '1', - foo: true, + title: 'test', panelsJSON: JSON.stringify([ { panelRefName: 'panel_0', @@ -188,7 +192,7 @@ Object { title: 'Title 2', }, ]), - }; + } as SavedObjectDashboard; const references = [ { name: 'panel_0', @@ -199,9 +203,9 @@ Object { injectReferences(context, references); expect(context).toMatchInlineSnapshot(` Object { - "foo": true, "id": "1", "panelsJSON": "[{\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\",\\"type\\":\\"visualization\\"},{\\"title\\":\\"Title 2\\"}]", + "title": "test", } `); }); @@ -209,14 +213,14 @@ Object { test(`fails when it can't find the reference in the array`, () => { const context = { id: '1', - foo: true, + title: 'test', panelsJSON: JSON.stringify([ { panelRefName: 'panel_0', title: 'Title 1', }, ]), - }; + } as SavedObjectDashboard; expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot( `"Could not find reference \\"panel_0\\""` ); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.ts similarity index 79% rename from src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.js rename to src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.ts index 121814cdc2150b..3e49b6636f5623 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_references.ts @@ -17,9 +17,18 @@ * under the License. */ -export function extractReferences({ attributes, references = [] }) { - const panelReferences = []; - const panels = JSON.parse(attributes.panelsJSON); +import { SavedObjectAttributes, SavedObjectReference } from 'kibana/public'; +import { SavedObjectDashboard } from './saved_dashboard'; + +export function extractReferences({ + attributes, + references = [], +}: { + attributes: SavedObjectAttributes; + references: SavedObjectReference[]; +}) { + const panelReferences: SavedObjectReference[] = []; + const panels: Array> = JSON.parse(String(attributes.panelsJSON)); panels.forEach((panel, i) => { if (!panel.type) { throw new Error(`"type" attribute is missing from panel "${i}"`); @@ -46,7 +55,10 @@ export function extractReferences({ attributes, references = [] }) { }; } -export function injectReferences(savedObject, references) { +export function injectReferences( + savedObject: SavedObjectDashboard, + references: SavedObjectReference[] +) { // Skip if panelsJSON is missing otherwise this will cause saved object import to fail when // importing objects without panelsJSON. At development time of this, there is no guarantee each saved // object has panelsJSON in all previous versions of kibana. @@ -62,7 +74,7 @@ export function injectReferences(savedObject, references) { if (!panel.panelRefName) { return; } - const reference = references.find(reference => reference.name === panel.panelRefName); + const reference = references.find(ref => ref.name === panel.panelRefName); if (!reference) { // Throw an error since "panelRefName" means the reference exists within // "references" and in this scenario we have bad data. diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_register.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_register.ts similarity index 93% rename from src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_register.js rename to src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_register.ts index 6da514a7e7f5f8..31ee7299e1ff16 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_register.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard_register.ts @@ -20,6 +20,6 @@ import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry'; import './saved_dashboards'; -SavedObjectRegistryProvider.register(savedDashboards => { +SavedObjectRegistryProvider.register((savedDashboards: any) => { return savedDashboards; }); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.ts similarity index 68% rename from src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js rename to src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.ts index 3cb30386dd499b..768dc6650595f7 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.ts @@ -18,11 +18,13 @@ */ import { i18n } from '@kbn/i18n'; -import './saved_dashboard'; +import { npStart } from 'ui/new_platform'; +// @ts-ignore import { uiModules } from 'ui/modules'; -import { SavedObjectLoader, SavedObjectsClientProvider } from 'ui/saved_objects'; +import { SavedObjectLoader } from 'ui/saved_objects'; +// @ts-ignore import { savedObjectManagementRegistry } from '../../management/saved_object_registry'; -import { npStart } from '../../../../../ui/public/new_platform'; +import { createSavedDashboardClass } from './saved_dashboard'; const module = uiModules.get('app/dashboard'); @@ -36,7 +38,15 @@ savedObjectManagementRegistry.register({ }); // This is the only thing that gets injected into controllers -module.service('savedDashboards', function(Private, SavedDashboard) { - const savedObjectClient = Private(SavedObjectsClientProvider); - return new SavedObjectLoader(SavedDashboard, savedObjectClient, npStart.core.chrome); +module.service('savedDashboards', function() { + const savedObjectsClient = npStart.core.savedObjects.client; + const services = { + savedObjectsClient, + indexPatterns: npStart.plugins.data.indexPatterns, + chrome: npStart.core.chrome, + overlays: npStart.core.overlays, + }; + + const SavedDashboard = createSavedDashboardClass(services); + return new SavedObjectLoader(SavedDashboard, savedObjectsClient, npStart.core.chrome); }); diff --git a/src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts b/src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts index 77f504d1080767..1d1707418efe6b 100644 --- a/src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts +++ b/src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts @@ -64,19 +64,13 @@ export async function applyESResp( _.assign(savedObject, savedObject._source); savedObject.lastSavedTitle = savedObject.title; - try { - await parseSearchSource(savedObject, esType, meta.searchSourceJSON, resp.references); - await hydrateIndexPattern(); - if (injectReferences && resp.references && resp.references.length > 0) { - injectReferences(savedObject, resp.references); - } - if (typeof config.afterESResp === 'function') { - await config.afterESResp.call(savedObject); - } - return savedObject; - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - throw e; + await parseSearchSource(savedObject, esType, meta.searchSourceJSON, resp.references); + await hydrateIndexPattern(); + if (injectReferences && resp.references && resp.references.length > 0) { + injectReferences(savedObject, resp.references); + } + if (typeof config.afterESResp === 'function') { + await config.afterESResp.call(savedObject); } + return savedObject; } diff --git a/src/legacy/ui/public/saved_objects/types.ts b/src/legacy/ui/public/saved_objects/types.ts index bccf73917882a8..7b587591fbe277 100644 --- a/src/legacy/ui/public/saved_objects/types.ts +++ b/src/legacy/ui/public/saved_objects/types.ts @@ -30,7 +30,7 @@ export interface SavedObject { creationOpts: (opts: SavedObjectCreationOpts) => Record; defaults: any; delete?: () => Promise<{}>; - destroy?: () => void; + destroy: () => void; getDisplayName: () => string; getEsType: () => string; getFullPath: () => string; From 2b1cb0666b3b2b191f5c80749ac6c2b54df5737d Mon Sep 17 00:00:00 2001 From: Liza Katz Date: Tue, 17 Dec 2019 13:01:56 +0000 Subject: [PATCH 04/60] register per app top nav items (#53136) --- .../top_nav_menu/create_top_nav_menu.tsx | 9 ++-- .../public/top_nav_menu/top_nav_menu_data.tsx | 4 ++ .../top_nav_menu_extensions_registry.ts | 6 +-- .../plugins/kbn_tp_top_nav/index.js | 1 + .../kbn_tp_top_nav/public/initialize.js | 41 +++++++++++++++++++ .../plugins/kbn_tp_top_nav/public/top_nav.tsx | 13 +----- 6 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 test/plugin_functional/plugins/kbn_tp_top_nav/public/initialize.js diff --git a/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx index 0b3b7b5b2a2729..a78c48b6759112 100644 --- a/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/create_top_nav_menu.tsx @@ -20,11 +20,14 @@ import React from 'react'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { TopNavMenuProps, TopNavMenu } from './top_nav_menu'; -import { TopNavMenuData } from './top_nav_menu_data'; +import { RegisteredTopNavMenuData } from './top_nav_menu_data'; -export function createTopNav(data: DataPublicPluginStart, extraConfig: TopNavMenuData[]) { +export function createTopNav(data: DataPublicPluginStart, extraConfig: RegisteredTopNavMenuData[]) { return (props: TopNavMenuProps) => { - const config = (props.config || []).concat(extraConfig); + const relevantConfig = extraConfig.filter( + dataItem => dataItem.appName === undefined || dataItem.appName === props.appName + ); + const config = (props.config || []).concat(relevantConfig); return ; }; diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx index 4ab45005892e0c..f709985bcf4537 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx @@ -29,3 +29,7 @@ export interface TopNavMenuData { disableButton?: boolean | (() => boolean); tooltip?: string | (() => string); } + +export interface RegisteredTopNavMenuData extends TopNavMenuData { + appName?: string; +} diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_extensions_registry.ts b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_extensions_registry.ts index c3eab3cce18e6b..a29d769a5d8a72 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_extensions_registry.ts +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_extensions_registry.ts @@ -17,10 +17,10 @@ * under the License. */ -import { TopNavMenuData } from './top_nav_menu_data'; +import { RegisteredTopNavMenuData } from './top_nav_menu_data'; export class TopNavMenuExtensionsRegistry { - private menuItems: TopNavMenuData[]; + private menuItems: RegisteredTopNavMenuData[]; constructor() { this.menuItems = []; @@ -28,7 +28,7 @@ export class TopNavMenuExtensionsRegistry { /** @public **/ // Items registered into this registry will be appended to any TopNavMenu rendered in any application. - public register(menuItem: TopNavMenuData) { + public register(menuItem: RegisteredTopNavMenuData) { this.menuItems.push(menuItem); } diff --git a/test/plugin_functional/plugins/kbn_tp_top_nav/index.js b/test/plugin_functional/plugins/kbn_tp_top_nav/index.js index de39a085bd20d5..b4c3e05c28b663 100644 --- a/test/plugin_functional/plugins/kbn_tp_top_nav/index.js +++ b/test/plugin_functional/plugins/kbn_tp_top_nav/index.js @@ -25,6 +25,7 @@ export default function(kibana) { description: 'This is a sample plugin for the functional tests.', main: 'plugins/kbn_tp_top_nav/app', }, + hacks: ['plugins/kbn_tp_top_nav/initialize'], }, }); } diff --git a/test/plugin_functional/plugins/kbn_tp_top_nav/public/initialize.js b/test/plugin_functional/plugins/kbn_tp_top_nav/public/initialize.js new file mode 100644 index 00000000000000..d46e47f6d248a3 --- /dev/null +++ b/test/plugin_functional/plugins/kbn_tp_top_nav/public/initialize.js @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { npSetup } from 'ui/new_platform'; + +const customExtension = { + id: 'registered-prop', + label: 'Registered Button', + description: 'Registered Demo', + run() {}, + testId: 'demoRegisteredNewButton', +}; + +npSetup.plugins.navigation.registerMenuItem(customExtension); + +const customDiscoverExtension = { + id: 'registered-discover-prop', + label: 'Registered Discover Button', + description: 'Registered Discover Demo', + run() {}, + testId: 'demoDiscoverRegisteredNewButton', + appName: 'discover', +}; + +npSetup.plugins.navigation.registerMenuItem(customDiscoverExtension); diff --git a/test/plugin_functional/plugins/kbn_tp_top_nav/public/top_nav.tsx b/test/plugin_functional/plugins/kbn_tp_top_nav/public/top_nav.tsx index 6a6bf9e82d5c0f..f77db4fe1654e3 100644 --- a/test/plugin_functional/plugins/kbn_tp_top_nav/public/top_nav.tsx +++ b/test/plugin_functional/plugins/kbn_tp_top_nav/public/top_nav.tsx @@ -18,17 +18,8 @@ */ import React from 'react'; -import { npSetup, npStart } from 'ui/new_platform'; - -const customExtension = { - id: 'registered-prop', - label: 'Registered Button', - description: 'Registered Demo', - run() {}, - testId: 'demoRegisteredNewButton', -}; - -npSetup.plugins.navigation.registerMenuItem(customExtension); +import './initialize'; +import { npStart } from 'ui/new_platform'; export const AppWithTopNav = () => { const { TopNavMenu } = npStart.plugins.navigation.ui; From 341630d5b3f3cbece6c80f834bd813a034ba46f8 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Tue, 17 Dec 2019 15:04:25 +0100 Subject: [PATCH 05/60] Use `savedObjects` provided by the platform instead of legacy shim. (#53264) --- .../plugins/encrypted_saved_objects/index.ts | 1 - .../encrypted_saved_objects/server/plugin.ts | 24 ++++--------------- .../server/saved_objects/index.ts | 14 ++++------- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts index 3969959d03cffd..85aa5c22135b6c 100644 --- a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts +++ b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts @@ -33,7 +33,6 @@ export const encryptedSavedObjects = (kibana: { } encryptedSavedObjectsPlugin.__legacyCompat.registerLegacyAPI({ - savedObjects: server.savedObjects, auditLogger: new AuditLogger( server, 'encryptedSavedObjects', diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts index 73c2439f777ccc..39da4c7d2d3531 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts @@ -9,9 +9,6 @@ import { SavedObjectsBaseOptions, PluginInitializerContext, CoreSetup, - SavedObjectsLegacyService, - KibanaRequest, - LegacyRequest, } from 'src/core/server'; import { first } from 'rxjs/operators'; import { createConfig$ } from './config'; @@ -37,7 +34,6 @@ export interface PluginStartContract extends SavedObjectsSetup { * to function properly. */ export interface LegacyAPI { - savedObjects: SavedObjectsLegacyService; auditLogger: { log: (eventType: string, message: string, data?: Record) => void; }; @@ -48,7 +44,7 @@ export interface LegacyAPI { */ export class Plugin { private readonly logger: Logger; - private savedObjectsSetup?: ReturnType; + private savedObjectsSetup!: SavedObjectsSetup; private legacyAPI?: LegacyAPI; private readonly getLegacyAPI = () => { @@ -66,7 +62,6 @@ export class Plugin { const config = await createConfig$(this.initializerContext) .pipe(first()) .toPromise(); - const adminClusterClient = await core.elasticsearch.adminClient$.pipe(first()).toPromise(); const service = Object.freeze( new EncryptedSavedObjectsService( @@ -76,19 +71,12 @@ export class Plugin { ) ); + this.savedObjectsSetup = setupSavedObjects({ service, savedObjects: core.savedObjects }); + return { registerType: (typeRegistration: EncryptedSavedObjectTypeRegistration) => service.registerType(typeRegistration), - __legacyCompat: { - registerLegacyAPI: (legacyAPI: LegacyAPI) => { - this.legacyAPI = legacyAPI; - this.savedObjectsSetup = setupSavedObjects({ - adminClusterClient, - service, - savedObjects: legacyAPI.savedObjects, - }); - }, - }, + __legacyCompat: { registerLegacyAPI: (legacyAPI: LegacyAPI) => (this.legacyAPI = legacyAPI) }, }; } @@ -98,10 +86,6 @@ export class Plugin { return { isEncryptionError: (error: Error) => error instanceof EncryptionError, getDecryptedAsInternalUser: (type: string, id: string, options?: SavedObjectsBaseOptions) => { - if (!this.savedObjectsSetup) { - throw new Error('Legacy SavedObjects API is not registered!'); - } - return this.savedObjectsSetup.getDecryptedAsInternalUser(type, id, options); }, }; diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts index e5445e187e2cc1..c967c92deb6ffb 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts @@ -5,19 +5,17 @@ */ import { - IClusterClient, + CoreSetup, SavedObject, SavedObjectAttributes, SavedObjectsBaseOptions, } from 'src/core/server'; -import { LegacyAPI } from '../plugin'; import { EncryptedSavedObjectsService } from '../crypto'; import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; interface SetupSavedObjectsParams { - adminClusterClient: IClusterClient; service: PublicMethodsOf; - savedObjects: LegacyAPI['savedObjects']; + savedObjects: CoreSetup['savedObjects']; } export interface SavedObjectsSetup { @@ -29,7 +27,6 @@ export interface SavedObjectsSetup { } export function setupSavedObjects({ - adminClusterClient, service, savedObjects, }: SetupSavedObjectsParams): SavedObjectsSetup { @@ -38,16 +35,13 @@ export function setupSavedObjects({ // priority for this wrapper to allow all other wrappers to set proper `namespace` for the Saved // Object (e.g. wrapper registered by the Spaces plugin) before we encrypt attributes since // `namespace` is included into AAD. - savedObjects.addScopedSavedObjectsClientWrapperFactory( + savedObjects.addClientWrapper( Number.MAX_SAFE_INTEGER, 'encryptedSavedObjects', ({ client: baseClient }) => new EncryptedSavedObjectsClientWrapper({ baseClient, service }) ); - const internalRepository = savedObjects.getSavedObjectsRepository( - adminClusterClient.callAsInternalUser - ); - + const internalRepository = savedObjects.createInternalRepository(); return { getDecryptedAsInternalUser: async ( type: string, From 4f5db1498b1cd7d7502da9762ea05563b267e7ca Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Tue, 17 Dec 2019 09:13:44 -0500 Subject: [PATCH 06/60] adds per-actionType enablement via config xpack.actions.enabledActionTypes (#52967) * adds per-actionType enablement via config xpack.actions.enabledTypes resolves: https://github.com/elastic/kibana/issues/52326 --- docs/setup/settings.asciidoc | 6 +- x-pack/legacy/plugins/actions/README.md | 3 + x-pack/legacy/plugins/actions/index.ts | 9 +- .../server/action_type_registry.mock.ts | 1 + .../server/action_type_registry.test.ts | 3 + .../actions/server/action_type_registry.ts | 21 ++- .../actions/server/actions_client.test.ts | 56 +++++++ .../plugins/actions/server/actions_client.ts | 7 + .../actions/server/actions_config.mock.ts | 2 + .../actions/server/actions_config.test.ts | 138 ++++++++++++++++-- .../plugins/actions/server/actions_config.ts | 53 +++++-- .../server/builtin_action_types/email.test.ts | 9 +- .../server/builtin_action_types/index.test.ts | 1 + .../server/lib/action_executor.test.ts | 33 +++++ .../actions/server/lib/action_executor.ts | 7 + .../legacy/plugins/actions/server/plugin.ts | 4 +- .../server/routes/list_action_types.test.ts | 1 + x-pack/legacy/plugins/actions/server/shim.ts | 1 + x-pack/legacy/plugins/actions/server/types.ts | 1 + .../alerting_api_integration/common/config.ts | 17 +++ .../common/fixtures/plugins/actions/index.ts | 11 ++ .../actions/builtin_action_types/pagerduty.ts | 2 +- .../actions/builtin_action_types/slack.ts | 2 +- .../actions/builtin_action_types/webhook.ts | 2 +- .../tests/actions/create.ts | 36 +++++ .../spaces_only/tests/actions/index.ts | 1 + .../tests/actions/type_not_enabled.ts | 109 ++++++++++++++ .../functional/es_archives/alerting/data.json | 15 ++ 28 files changed, 502 insertions(+), 49 deletions(-) create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/actions/type_not_enabled.ts create mode 100644 x-pack/test/functional/es_archives/alerting/data.json diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index c836386d003642..01e6bd51ea50b7 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -390,12 +390,16 @@ Rollup user interface. `i18n.locale`:: *Default: en* Set this value to change the Kibana interface language. Valid locales are: `en`, `zh-CN`, `ja-JP`. +`xpack.actions.enabledActionTypes:`:: *Default: +[ {asterisk} ]+* Set this value +to an array of action types that are enabled. An element of `*` indicates all +action types registered are enabled. The action types provided by Kibana are: +`.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, `.webhook`. + `xpack.actions.whitelistedHosts:`:: *Default: +[ {asterisk} ]+* Set this value to an array of host names which actions such as email, slack, pagerduty, and webhook can connect to. An element of `*` indicates any host can be connected to. An empty array indicates no hosts can be connected to. - include::{docdir}/settings/apm-settings.asciidoc[] include::{docdir}/settings/dev-settings.asciidoc[] include::{docdir}/settings/graph-settings.asciidoc[] diff --git a/x-pack/legacy/plugins/actions/README.md b/x-pack/legacy/plugins/actions/README.md index 3c420704fcb349..3d7409d1613e13 100644 --- a/x-pack/legacy/plugins/actions/README.md +++ b/x-pack/legacy/plugins/actions/README.md @@ -34,6 +34,7 @@ Built-In-Actions are configured using the _xpack.actions_ namespoace under _kiba | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | | _xpack.actions._**enabled** | Feature toggle which enabled Actions in Kibana. | boolean | | _xpack.actions._**whitelistedHosts** | Which _hostnames_ are whitelisted for the Built-In-Action? This list should contain hostnames of every external service you wish to interact with using Webhooks, Email or any other built in Action. Note that you may use the string "\*" in place of a specific hostname to enable Kibana to target any URL, but keep in mind the potential use of such a feature to execute [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) attacks from your server. | Array | +| _xpack.actions._**enabledActionTypes** | A list of _actionTypes_ id's that are enabled. A "\*" may be used as an element to indicate all registered actionTypes should be enabled. The actionTypes registered for Kibana are `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, `.webhook`. Default: `["*"]` | Array | #### Whitelisting Built-in Action Types It is worth noting that the **whitelistedHosts** configuation applies to built-in action types (such as Slack, or PagerDuty) as well. @@ -49,8 +50,10 @@ This module provides a Utilities for interacting with the configuration. | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | isWhitelistedUri | _uri_: The URI you wish to validate is whitelisted | Validates whether the URI is whitelisted. This checks the configuration and validates that the hostname of the URI is in the list of whitelisted Hosts and returns `true` if it is whitelisted. If the configuration says that all URI's are whitelisted (using an "\*") then it will always return `true`. | Boolean | | isWhitelistedHostname | _hostname_: The Hostname you wish to validate is whitelisted | Validates whether the Hostname is whitelisted. This checks the configuration and validates that the hostname is in the list of whitelisted Hosts and returns `true` if it is whitelisted. If the configuration says that all Hostnames are whitelisted (using an "\*") then it will always return `true`. | Boolean | +| isActionTypeEnabled | _actionType_: The actionType to check to see if it's enabled | Returns true if the actionType is enabled, otherwise false. | Boolean | | ensureWhitelistedUri | _uri_: The URI you wish to validate is whitelisted | Validates whether the URI is whitelisted. This checks the configuration and validates that the hostname of the URI is in the list of whitelisted Hosts and throws an error if it is not whitelisted. If the configuration says that all URI's are whitelisted (using an "\*") then it will never throw. | No return value, throws if URI isn't whitelisted | | ensureWhitelistedHostname | _hostname_: The Hostname you wish to validate is whitelisted | Validates whether the Hostname is whitelisted. This checks the configuration and validates that the hostname is in the list of whitelisted Hosts and throws an error if it is not whitelisted. If the configuration says that all Hostnames are whitelisted (using an "\*") then it will never throw | No return value, throws if Hostname isn't whitelisted | +| ensureActionTypeEnabled | _actionType_: The actionType to check to see if it's enabled | Throws an error if the actionType is not enabled | No return value, throws if actionType isn't enabled | ## Action types diff --git a/x-pack/legacy/plugins/actions/index.ts b/x-pack/legacy/plugins/actions/index.ts index 7c539f74924cbb..dd91d85cd84930 100644 --- a/x-pack/legacy/plugins/actions/index.ts +++ b/x-pack/legacy/plugins/actions/index.ts @@ -8,6 +8,7 @@ import { Legacy } from 'kibana'; import { Root } from 'joi'; import mappings from './mappings.json'; import { init } from './server'; +import { WhitelistedHosts, EnabledActionTypes } from './server/actions_config'; export { ActionsPlugin, @@ -38,10 +39,14 @@ export function actions(kibana: any) { .items( Joi.string() .hostname() - .allow('*') + .allow(WhitelistedHosts.Any) ) .sparse(false) - .default(['*']), + .default([WhitelistedHosts.Any]), + enabledActionTypes: Joi.array() + .items(Joi.string()) + .sparse(false) + .default([EnabledActionTypes.Any]), }) .default(); }, diff --git a/x-pack/legacy/plugins/actions/server/action_type_registry.mock.ts b/x-pack/legacy/plugins/actions/server/action_type_registry.mock.ts index be78a4d747b854..5589a15932ecf7 100644 --- a/x-pack/legacy/plugins/actions/server/action_type_registry.mock.ts +++ b/x-pack/legacy/plugins/actions/server/action_type_registry.mock.ts @@ -12,6 +12,7 @@ const createActionTypeRegistryMock = () => { register: jest.fn(), get: jest.fn(), list: jest.fn(), + ensureActionTypeEnabled: jest.fn(), }; return mocked; }; diff --git a/x-pack/legacy/plugins/actions/server/action_type_registry.test.ts b/x-pack/legacy/plugins/actions/server/action_type_registry.test.ts index c0a01bc85e9169..98721c56758248 100644 --- a/x-pack/legacy/plugins/actions/server/action_type_registry.test.ts +++ b/x-pack/legacy/plugins/actions/server/action_type_registry.test.ts @@ -8,11 +8,13 @@ import { taskManagerMock } from '../../task_manager/task_manager.mock'; import { ActionTypeRegistry } from './action_type_registry'; import { ExecutorType } from './types'; import { ActionExecutor, ExecutorError, TaskRunnerFactory } from './lib'; +import { configUtilsMock } from './actions_config.mock'; const mockTaskManager = taskManagerMock.create(); const actionTypeRegistryParams = { taskManager: mockTaskManager, taskRunnerFactory: new TaskRunnerFactory(new ActionExecutor()), + actionsConfigUtils: configUtilsMock, }; beforeEach(() => jest.resetAllMocks()); @@ -123,6 +125,7 @@ describe('list()', () => { { id: 'my-action-type', name: 'My action type', + enabled: true, }, ]); }); diff --git a/x-pack/legacy/plugins/actions/server/action_type_registry.ts b/x-pack/legacy/plugins/actions/server/action_type_registry.ts index 6007851f870844..a09788e45c3941 100644 --- a/x-pack/legacy/plugins/actions/server/action_type_registry.ts +++ b/x-pack/legacy/plugins/actions/server/action_type_registry.ts @@ -10,20 +10,23 @@ import { TaskManagerSetupContract } from './shim'; import { RunContext } from '../../task_manager'; import { ExecutorError, TaskRunnerFactory } from './lib'; import { ActionType } from './types'; - +import { ActionsConfigurationUtilities } from './actions_config'; interface ConstructorOptions { taskManager: TaskManagerSetupContract; taskRunnerFactory: TaskRunnerFactory; + actionsConfigUtils: ActionsConfigurationUtilities; } export class ActionTypeRegistry { private readonly taskManager: TaskManagerSetupContract; private readonly actionTypes: Map = new Map(); private readonly taskRunnerFactory: TaskRunnerFactory; + private readonly actionsConfigUtils: ActionsConfigurationUtilities; - constructor({ taskManager, taskRunnerFactory }: ConstructorOptions) { - this.taskManager = taskManager; - this.taskRunnerFactory = taskRunnerFactory; + constructor(constructorParams: ConstructorOptions) { + this.taskManager = constructorParams.taskManager; + this.taskRunnerFactory = constructorParams.taskRunnerFactory; + this.actionsConfigUtils = constructorParams.actionsConfigUtils; } /** @@ -33,6 +36,13 @@ export class ActionTypeRegistry { return this.actionTypes.has(id); } + /** + * Throws error if action type is not enabled. + */ + public ensureActionTypeEnabled(id: string) { + this.actionsConfigUtils.ensureActionTypeEnabled(id); + } + /** * Registers an action type to the action type registry */ @@ -86,12 +96,13 @@ export class ActionTypeRegistry { } /** - * Returns a list of registered action types [{ id, name }] + * Returns a list of registered action types [{ id, name, enabled }] */ public list() { return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => ({ id: actionTypeId, name: actionType.name, + enabled: this.actionsConfigUtils.isActionTypeEnabled(actionTypeId), })); } } diff --git a/x-pack/legacy/plugins/actions/server/actions_client.test.ts b/x-pack/legacy/plugins/actions/server/actions_client.test.ts index 1cbf3949d20f8c..73b1de224eb320 100644 --- a/x-pack/legacy/plugins/actions/server/actions_client.test.ts +++ b/x-pack/legacy/plugins/actions/server/actions_client.test.ts @@ -11,6 +11,9 @@ import { ActionsClient } from './actions_client'; import { ExecutorType } from './types'; import { ActionExecutor, TaskRunnerFactory } from './lib'; import { taskManagerMock } from '../../task_manager/task_manager.mock'; +import { configUtilsMock } from './actions_config.mock'; +import { getActionsConfigurationUtilities } from './actions_config'; + import { elasticsearchServiceMock, savedObjectsClientMock, @@ -25,6 +28,7 @@ const mockTaskManager = taskManagerMock.create(); const actionTypeRegistryParams = { taskManager: mockTaskManager, taskRunnerFactory: new TaskRunnerFactory(new ActionExecutor()), + actionsConfigUtils: configUtilsMock, }; let actionsClient: ActionsClient; @@ -190,6 +194,58 @@ describe('create()', () => { ] `); }); + + test('throws error creating action with disabled actionType', async () => { + const localConfigUtils = getActionsConfigurationUtilities({ + enabled: true, + enabledActionTypes: ['some-not-ignored-action-type'], + whitelistedHosts: ['*'], + }); + + const localActionTypeRegistryParams = { + taskManager: mockTaskManager, + taskRunnerFactory: new TaskRunnerFactory(new ActionExecutor()), + actionsConfigUtils: localConfigUtils, + }; + + actionTypeRegistry = new ActionTypeRegistry(localActionTypeRegistryParams); + actionsClient = new ActionsClient({ + actionTypeRegistry, + savedObjectsClient, + scopedClusterClient, + defaultKibanaIndex, + }); + + const savedObjectCreateResult = { + id: '1', + type: 'type', + attributes: { + name: 'my name', + actionTypeId: 'my-action-type', + config: {}, + }, + references: [], + }; + actionTypeRegistry.register({ + id: 'my-action-type', + name: 'My action type', + executor, + }); + savedObjectsClient.create.mockResolvedValueOnce(savedObjectCreateResult); + + await expect( + actionsClient.create({ + action: { + name: 'my name', + actionTypeId: 'my-action-type', + config: {}, + secrets: {}, + }, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"action type \\"my-action-type\\" is not enabled in the Kibana config xpack.actions.enabledActionTypes"` + ); + }); }); describe('get()', () => { diff --git a/x-pack/legacy/plugins/actions/server/actions_client.ts b/x-pack/legacy/plugins/actions/server/actions_client.ts index 10713d72a38587..104439ca4401fe 100644 --- a/x-pack/legacy/plugins/actions/server/actions_client.ts +++ b/x-pack/legacy/plugins/actions/server/actions_client.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import Boom from 'boom'; import { IScopedClusterClient, SavedObjectsClientContract, @@ -92,6 +93,12 @@ export class ActionsClient { const validatedActionTypeConfig = validateConfig(actionType, config); const validatedActionTypeSecrets = validateSecrets(actionType, secrets); + try { + this.actionTypeRegistry.ensureActionTypeEnabled(actionTypeId); + } catch (err) { + throw Boom.badRequest(err.message); + } + const result = await this.savedObjectsClient.create('action', { actionTypeId, name, diff --git a/x-pack/legacy/plugins/actions/server/actions_config.mock.ts b/x-pack/legacy/plugins/actions/server/actions_config.mock.ts index 0430d712e62671..b4e0324f9feadf 100644 --- a/x-pack/legacy/plugins/actions/server/actions_config.mock.ts +++ b/x-pack/legacy/plugins/actions/server/actions_config.mock.ts @@ -9,6 +9,8 @@ import { ActionsConfigurationUtilities } from './actions_config'; export const configUtilsMock: ActionsConfigurationUtilities = { isWhitelistedHostname: _ => true, isWhitelistedUri: _ => true, + isActionTypeEnabled: _ => true, ensureWhitelistedHostname: _ => {}, ensureWhitelistedUri: _ => {}, + ensureActionTypeEnabled: _ => {}, }; diff --git a/x-pack/legacy/plugins/actions/server/actions_config.test.ts b/x-pack/legacy/plugins/actions/server/actions_config.test.ts index 7b4176fb69dbfa..7d9d431d1c1be3 100644 --- a/x-pack/legacy/plugins/actions/server/actions_config.test.ts +++ b/x-pack/legacy/plugins/actions/server/actions_config.test.ts @@ -5,13 +5,24 @@ */ import { ActionsConfigType } from './types'; -import { getActionsConfigurationUtilities, WhitelistedHosts } from './actions_config'; +import { + getActionsConfigurationUtilities, + WhitelistedHosts, + EnabledActionTypes, +} from './actions_config'; + +const DefaultActionsConfig: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: [], +}; describe('ensureWhitelistedUri', () => { test('returns true when "any" hostnames are allowed', () => { const config: ActionsConfigType = { enabled: false, whitelistedHosts: [WhitelistedHosts.Any], + enabledActionTypes: [], }; expect( getActionsConfigurationUtilities(config).ensureWhitelistedUri( @@ -21,27 +32,31 @@ describe('ensureWhitelistedUri', () => { }); test('throws when the hostname in the requested uri is not in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: [] }; + const config: ActionsConfigType = DefaultActionsConfig; expect(() => getActionsConfigurationUtilities(config).ensureWhitelistedUri( 'https://github.com/elastic/kibana' ) ).toThrowErrorMatchingInlineSnapshot( - `"target url \\"https://github.com/elastic/kibana\\" is not in the Kibana whitelist"` + `"target url \\"https://github.com/elastic/kibana\\" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts"` ); }); test('throws when the uri cannot be parsed as a valid URI', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: [] }; + const config: ActionsConfigType = DefaultActionsConfig; expect(() => getActionsConfigurationUtilities(config).ensureWhitelistedUri('github.com/elastic') ).toThrowErrorMatchingInlineSnapshot( - `"target url \\"github.com/elastic\\" is not in the Kibana whitelist"` + `"target url \\"github.com/elastic\\" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts"` ); }); test('returns true when the hostname in the requested uri is in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: ['github.com'] }; + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: ['github.com'], + enabledActionTypes: [], + }; expect( getActionsConfigurationUtilities(config).ensureWhitelistedUri( 'https://github.com/elastic/kibana' @@ -55,6 +70,7 @@ describe('ensureWhitelistedHostname', () => { const config: ActionsConfigType = { enabled: false, whitelistedHosts: [WhitelistedHosts.Any], + enabledActionTypes: [], }; expect( getActionsConfigurationUtilities(config).ensureWhitelistedHostname('github.com') @@ -62,16 +78,20 @@ describe('ensureWhitelistedHostname', () => { }); test('throws when the hostname in the requested uri is not in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: [] }; + const config: ActionsConfigType = DefaultActionsConfig; expect(() => getActionsConfigurationUtilities(config).ensureWhitelistedHostname('github.com') ).toThrowErrorMatchingInlineSnapshot( - `"target hostname \\"github.com\\" is not in the Kibana whitelist"` + `"target hostname \\"github.com\\" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts"` ); }); test('returns true when the hostname in the requested uri is in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: ['github.com'] }; + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: ['github.com'], + enabledActionTypes: [], + }; expect( getActionsConfigurationUtilities(config).ensureWhitelistedHostname('github.com') ).toBeUndefined(); @@ -83,6 +103,7 @@ describe('isWhitelistedUri', () => { const config: ActionsConfigType = { enabled: false, whitelistedHosts: [WhitelistedHosts.Any], + enabledActionTypes: [], }; expect( getActionsConfigurationUtilities(config).isWhitelistedUri('https://github.com/elastic/kibana') @@ -90,21 +111,25 @@ describe('isWhitelistedUri', () => { }); test('throws when the hostname in the requested uri is not in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: [] }; + const config: ActionsConfigType = DefaultActionsConfig; expect( getActionsConfigurationUtilities(config).isWhitelistedUri('https://github.com/elastic/kibana') ).toEqual(false); }); test('throws when the uri cannot be parsed as a valid URI', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: [] }; + const config: ActionsConfigType = DefaultActionsConfig; expect(getActionsConfigurationUtilities(config).isWhitelistedUri('github.com/elastic')).toEqual( false ); }); test('returns true when the hostname in the requested uri is in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: ['github.com'] }; + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: ['github.com'], + enabledActionTypes: [], + }; expect( getActionsConfigurationUtilities(config).isWhitelistedUri('https://github.com/elastic/kibana') ).toEqual(true); @@ -116,6 +141,7 @@ describe('isWhitelistedHostname', () => { const config: ActionsConfigType = { enabled: false, whitelistedHosts: [WhitelistedHosts.Any], + enabledActionTypes: [], }; expect(getActionsConfigurationUtilities(config).isWhitelistedHostname('github.com')).toEqual( true @@ -123,16 +149,100 @@ describe('isWhitelistedHostname', () => { }); test('throws when the hostname in the requested uri is not in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: [] }; + const config: ActionsConfigType = DefaultActionsConfig; expect(getActionsConfigurationUtilities(config).isWhitelistedHostname('github.com')).toEqual( false ); }); test('returns true when the hostname in the requested uri is in the whitelist', () => { - const config: ActionsConfigType = { enabled: false, whitelistedHosts: ['github.com'] }; + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: ['github.com'], + enabledActionTypes: [], + }; expect(getActionsConfigurationUtilities(config).isWhitelistedHostname('github.com')).toEqual( true ); }); }); + +describe('isActionTypeEnabled', () => { + test('returns true when "any" actionTypes are allowed', () => { + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: ['ignore', EnabledActionTypes.Any], + }; + expect(getActionsConfigurationUtilities(config).isActionTypeEnabled('foo')).toEqual(true); + }); + + test('returns false when no actionType is allowed', () => { + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: [], + }; + expect(getActionsConfigurationUtilities(config).isActionTypeEnabled('foo')).toEqual(false); + }); + + test('returns false when the actionType is not in the enabled list', () => { + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: ['foo'], + }; + expect(getActionsConfigurationUtilities(config).isActionTypeEnabled('bar')).toEqual(false); + }); + + test('returns true when the actionType is in the enabled list', () => { + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: ['ignore', 'foo'], + }; + expect(getActionsConfigurationUtilities(config).isActionTypeEnabled('foo')).toEqual(true); + }); +}); + +describe('ensureActionTypeEnabled', () => { + test('does not throw when any actionType is allowed', () => { + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: ['ignore', EnabledActionTypes.Any], + }; + expect(getActionsConfigurationUtilities(config).ensureActionTypeEnabled('foo')).toBeUndefined(); + }); + + test('throws when no actionType is not allowed', () => { + const config: ActionsConfigType = DefaultActionsConfig; + expect(() => + getActionsConfigurationUtilities(config).ensureActionTypeEnabled('foo') + ).toThrowErrorMatchingInlineSnapshot( + `"action type \\"foo\\" is not enabled in the Kibana config xpack.actions.enabledActionTypes"` + ); + }); + + test('throws when actionType is not enabled', () => { + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: ['ignore'], + }; + expect(() => + getActionsConfigurationUtilities(config).ensureActionTypeEnabled('foo') + ).toThrowErrorMatchingInlineSnapshot( + `"action type \\"foo\\" is not enabled in the Kibana config xpack.actions.enabledActionTypes"` + ); + }); + + test('does not throw when actionType is enabled', () => { + const config: ActionsConfigType = { + enabled: false, + whitelistedHosts: [], + enabledActionTypes: ['ignore', 'foo'], + }; + expect(getActionsConfigurationUtilities(config).ensureActionTypeEnabled('foo')).toBeUndefined(); + }); +}); diff --git a/x-pack/legacy/plugins/actions/server/actions_config.ts b/x-pack/legacy/plugins/actions/server/actions_config.ts index 3053c88f1c9ef4..e589969c50e545 100644 --- a/x-pack/legacy/plugins/actions/server/actions_config.ts +++ b/x-pack/legacy/plugins/actions/server/actions_config.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import { tryCatch, fromNullable, isSome, map, mapNullable, getOrElse } from 'fp-ts/lib/Option'; +import { tryCatch, map, mapNullable, getOrElse } from 'fp-ts/lib/Option'; import { URL } from 'url'; import { curry } from 'lodash'; import { pipe } from 'fp-ts/lib/pipeable'; @@ -16,6 +16,10 @@ export enum WhitelistedHosts { Any = '*', } +export enum EnabledActionTypes { + Any = '*', +} + enum WhitelistingField { url = 'url', hostname = 'hostname', @@ -24,13 +28,16 @@ enum WhitelistingField { export interface ActionsConfigurationUtilities { isWhitelistedHostname: (hostname: string) => boolean; isWhitelistedUri: (uri: string) => boolean; + isActionTypeEnabled: (actionType: string) => boolean; ensureWhitelistedHostname: (hostname: string) => void; ensureWhitelistedUri: (uri: string) => void; + ensureActionTypeEnabled: (actionType: string) => void; } function whitelistingErrorMessage(field: WhitelistingField, value: string) { return i18n.translate('xpack.actions.urlWhitelistConfigurationError', { - defaultMessage: 'target {field} "{value}" is not in the Kibana whitelist', + defaultMessage: + 'target {field} "{value}" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', values: { value, field, @@ -38,22 +45,21 @@ function whitelistingErrorMessage(field: WhitelistingField, value: string) { }); } -function doesValueWhitelistAnyHostname(whitelistedHostname: string): boolean { - return whitelistedHostname === WhitelistedHosts.Any; +function disabledActionTypeErrorMessage(actionType: string) { + return i18n.translate('xpack.actions.disabledActionTypeError', { + defaultMessage: + 'action type "{actionType}" is not enabled in the Kibana config xpack.actions.enabledActionTypes', + values: { + actionType, + }, + }); } function isWhitelisted({ whitelistedHosts }: ActionsConfigType, hostname: string): boolean { - return ( - Array.isArray(whitelistedHosts) && - isSome( - fromNullable( - whitelistedHosts.find( - whitelistedHostname => - doesValueWhitelistAnyHostname(whitelistedHostname) || whitelistedHostname === hostname - ) - ) - ) - ); + const whitelisted = new Set(whitelistedHosts); + if (whitelisted.has(WhitelistedHosts.Any)) return true; + if (whitelisted.has(hostname)) return true; + return false; } function isWhitelistedHostnameInUri(config: ActionsConfigType, uri: string): boolean { @@ -65,14 +71,26 @@ function isWhitelistedHostnameInUri(config: ActionsConfigType, uri: string): boo ); } +function isActionTypeEnabledInConfig( + { enabledActionTypes }: ActionsConfigType, + actionType: string +): boolean { + const enabled = new Set(enabledActionTypes); + if (enabled.has(EnabledActionTypes.Any)) return true; + if (enabled.has(actionType)) return true; + return false; +} + export function getActionsConfigurationUtilities( config: ActionsConfigType ): ActionsConfigurationUtilities { const isWhitelistedHostname = curry(isWhitelisted)(config); const isWhitelistedUri = curry(isWhitelistedHostnameInUri)(config); + const isActionTypeEnabled = curry(isActionTypeEnabledInConfig)(config); return { isWhitelistedHostname, isWhitelistedUri, + isActionTypeEnabled, ensureWhitelistedUri(uri: string) { if (!isWhitelistedUri(uri)) { throw new Error(whitelistingErrorMessage(WhitelistingField.url, uri)); @@ -83,5 +101,10 @@ export function getActionsConfigurationUtilities( throw new Error(whitelistingErrorMessage(WhitelistingField.hostname, hostname)); } }, + ensureActionTypeEnabled(actionType: string) { + if (!isActionTypeEnabled(actionType)) { + throw new Error(disabledActionTypeErrorMessage(actionType)); + } + }, }; } diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts index 513f51f644534a..4aaecc8e9d7df4 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts @@ -12,7 +12,7 @@ import { Logger } from '../../../../../../src/core/server'; import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; import { ActionType, ActionTypeExecutorOptions } from '../types'; -import { ActionsConfigurationUtilities } from '../actions_config'; +import { configUtilsMock } from '../actions_config.mock'; import { validateConfig, validateSecrets, validateParams } from '../lib'; import { createActionTypeRegistry } from './index.test'; import { sendEmail } from './lib/send_email'; @@ -25,13 +25,6 @@ import { const sendEmailMock = sendEmail as jest.Mock; -const configUtilsMock: ActionsConfigurationUtilities = { - isWhitelistedHostname: _ => true, - isWhitelistedUri: _ => true, - ensureWhitelistedHostname: _ => {}, - ensureWhitelistedUri: _ => {}, -}; - const ACTION_TYPE_ID = '.email'; const NO_OP_FN = () => {}; diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/index.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/index.test.ts index 9b58c124d02053..a39aaf3a3e2d12 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/index.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/index.test.ts @@ -22,6 +22,7 @@ export function createActionTypeRegistry(): { const actionTypeRegistry = new ActionTypeRegistry({ taskManager: taskManagerMock.create(), taskRunnerFactory: new TaskRunnerFactory(new ActionExecutor()), + actionsConfigUtils: configUtilsMock, }); registerBuiltInActionTypes({ logger, diff --git a/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts b/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts index 6767468509d25c..7d9bf20e22aceb 100644 --- a/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/legacy/plugins/actions/server/lib/action_executor.test.ts @@ -202,3 +202,36 @@ test('throws an error when failing to load action through savedObjectsClient', a `"No access"` ); }); + +test('returns an error if actionType is not enabled', async () => { + const actionType = { + id: 'test', + name: 'Test', + executor: jest.fn(), + }; + const actionSavedObject = { + id: '1', + type: 'action', + attributes: { + actionTypeId: 'test', + }, + references: [], + }; + savedObjectsClient.get.mockResolvedValueOnce(actionSavedObject); + encryptedSavedObjectsPlugin.getDecryptedAsInternalUser.mockResolvedValueOnce(actionSavedObject); + actionTypeRegistry.get.mockReturnValueOnce(actionType); + actionTypeRegistry.ensureActionTypeEnabled.mockImplementationOnce(() => { + throw new Error('not enabled for test'); + }); + const result = await actionExecutor.execute(executeParams); + + expect(actionTypeRegistry.ensureActionTypeEnabled).toHaveBeenCalledWith('test'); + expect(result).toMatchInlineSnapshot(` + Object { + "actionId": "1", + "message": "not enabled for test", + "retry": false, + "status": "error", + } + `); +}); diff --git a/x-pack/legacy/plugins/actions/server/lib/action_executor.ts b/x-pack/legacy/plugins/actions/server/lib/action_executor.ts index c532b76a904d5a..f0259c739654b2 100644 --- a/x-pack/legacy/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/legacy/plugins/actions/server/lib/action_executor.ts @@ -69,6 +69,13 @@ export class ActionExecutor { const { attributes: { actionTypeId, config, name }, } = await services.savedObjectsClient.get('action', actionId); + + try { + actionTypeRegistry.ensureActionTypeEnabled(actionTypeId); + } catch (err) { + return { status: 'error', actionId, message: err.message, retry: false }; + } + // Only get encrypted attributes here, the remaining attributes can be fetched in // the savedObjectsClient call const { diff --git a/x-pack/legacy/plugins/actions/server/plugin.ts b/x-pack/legacy/plugins/actions/server/plugin.ts index 510e2a3b948946..6a41bf9a8b459c 100644 --- a/x-pack/legacy/plugins/actions/server/plugin.ts +++ b/x-pack/legacy/plugins/actions/server/plugin.ts @@ -85,9 +85,11 @@ export class Plugin { const actionExecutor = new ActionExecutor(); const taskRunnerFactory = new TaskRunnerFactory(actionExecutor); + const actionsConfigUtils = getActionsConfigurationUtilities(config as ActionsConfigType); const actionTypeRegistry = new ActionTypeRegistry({ taskRunnerFactory, taskManager: plugins.task_manager, + actionsConfigUtils, }); this.taskRunnerFactory = taskRunnerFactory; this.actionTypeRegistry = actionTypeRegistry; @@ -97,7 +99,7 @@ export class Plugin { registerBuiltInActionTypes({ logger: this.logger, actionTypeRegistry, - actionsConfigUtils: getActionsConfigurationUtilities(config as ActionsConfigType), + actionsConfigUtils, }); // Routes diff --git a/x-pack/legacy/plugins/actions/server/routes/list_action_types.test.ts b/x-pack/legacy/plugins/actions/server/routes/list_action_types.test.ts index 3bacbe4f0911b0..3bfc3d736cda69 100644 --- a/x-pack/legacy/plugins/actions/server/routes/list_action_types.test.ts +++ b/x-pack/legacy/plugins/actions/server/routes/list_action_types.test.ts @@ -23,6 +23,7 @@ it('calls the list function', async () => { { id: '1', name: 'One', + enabled: true, }, ]; diff --git a/x-pack/legacy/plugins/actions/server/shim.ts b/x-pack/legacy/plugins/actions/server/shim.ts index c40e4ea79d1c39..1fa8f755cc7ee2 100644 --- a/x-pack/legacy/plugins/actions/server/shim.ts +++ b/x-pack/legacy/plugins/actions/server/shim.ts @@ -110,6 +110,7 @@ export function shim( return Rx.of({ enabled: server.config().get('xpack.actions.enabled') as boolean, whitelistedHosts: server.config().get('xpack.actions.whitelistedHosts') as string[], + enabledActionTypes: server.config().get('xpack.actions.enabledActionTypes') as string[], }) as Rx.Observable; }, }, diff --git a/x-pack/legacy/plugins/actions/server/types.ts b/x-pack/legacy/plugins/actions/server/types.ts index 94b34034cd8b23..6a6fb7d660cbbd 100644 --- a/x-pack/legacy/plugins/actions/server/types.ts +++ b/x-pack/legacy/plugins/actions/server/types.ts @@ -27,6 +27,7 @@ export interface ActionsPlugin { export interface ActionsConfigType { enabled: boolean; whitelistedHosts: string[]; + enabledActionTypes: string[]; } // the parameters passed to an action type executor function diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index 3a2cdb5397ad86..6749c11c77036a 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -16,6 +16,21 @@ interface CreateTestConfigOptions { ssl?: boolean; } +// test.not-enabled is specifically not enabled +const enabledActionTypes = [ + '.server-log', + '.slack', + '.email', + '.index', + '.pagerduty', + '.webhook', + 'test.noop', + 'test.index-record', + 'test.failing', + 'test.rate-limit', + 'test.authorization', +]; + // eslint-disable-next-line import/no-default-export export function createTestConfig(name: string, options: CreateTestConfigOptions) { const { license = 'trial', disabledPlugins = [], ssl = false } = options; @@ -57,6 +72,8 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) 'localhost', 'some.non.existent.com', ])}`, + `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, + '--xpack.alerting.enabled=true', ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts index 73279cd0c2ff0c..a5a9353d83cbcc 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import Hapi from 'hapi'; +import { ActionType } from '../../../../../../legacy/plugins/actions'; + import { initPlugin as initSlack } from './slack_simulation'; import { initPlugin as initWebhook } from './webhook_simulation'; import { initPlugin as initPagerduty } from './pagerduty_simulation'; @@ -32,6 +34,15 @@ export default function(kibana: any) { require: ['actions'], name: NAME, init: (server: Hapi.Server) => { + // this action is specifically NOT enabled in ../../config.ts + const notEnabledActionType: ActionType = { + id: 'test.not-enabled', + name: 'Test: Not Enabled', + async executor() { + return { status: 'ok', actionId: '' }; + }, + }; + server.plugins.actions!.setup.registerType(notEnabledActionType); server.plugins.xpack_main.registerFeature({ id: 'actions', name: 'Actions', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts index e2b44d84a2b7f3..cfc04663c6a4f3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts @@ -111,7 +111,7 @@ export default function pagerdutyTest({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'error validating action type config: error configuring pagerduty action: target url "https://events.pagerduty.com/v2/enqueue" is not in the Kibana whitelist', + 'error validating action type config: error configuring pagerduty action: target url "https://events.pagerduty.com/v2/enqueue" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts index 8a1c6d31ec07fb..87280169c0960e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts @@ -103,7 +103,7 @@ export default function slackTest({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'error validating action type secrets: error configuring slack action: target url "http://slack.mynonexistent.com" is not in the Kibana whitelist', + 'error validating action type secrets: error configuring slack action: target url "http://slack.mynonexistent.com" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts index b98e820b5f67d5..841c96acdc3b11 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts @@ -180,7 +180,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { .expect(400); expect(result.error).to.eql('Bad Request'); - expect(result.message).to.match(/not in the Kibana whitelist/); + expect(result.message).to.match(/is not whitelisted in the Kibana config/); }); it('should handle unreachable webhook targets', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/create.ts index 5d5692685c81b4..57614aa816ff24 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/create.ts @@ -179,6 +179,42 @@ export default function createActionTests({ getService }: FtrProviderContext) { throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); + + it(`should handle create action requests for action types that are not enabled`, async () => { + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/api/action`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send({ + name: 'my name', + actionTypeId: 'test.not-enabled', + }); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'global_read at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + break; + case 'superuser at space1': + case 'space_1_all at space1': + expect(response.statusCode).to.eql(400); + expect(response.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'action type "test.not-enabled" is not enabled in the Kibana config xpack.actions.enabledActionTypes', + }); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); }); } }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts index a3447e730c28d8..accee08a00c612 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/index.ts @@ -17,5 +17,6 @@ export default function actionsTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./update')); loadTestFile(require.resolve('./execute')); loadTestFile(require.resolve('./builtin_action_types/es_index')); + loadTestFile(require.resolve('./type_not_enabled')); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/type_not_enabled.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/type_not_enabled.ts new file mode 100644 index 00000000000000..7193a80b94498c --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/type_not_enabled.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +const PREWRITTEN_ACTION_ID = 'uuid-actionId'; +const DISABLED_ACTION_TYPE = 'test.not-enabled'; + +// eslint-disable-next-line import/no-default-export +export default function typeNotEnabledTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + describe('actionType not enabled', () => { + // loads action PREWRITTEN_ACTION_ID with actionType DISABLED_ACTION_TYPE + before(() => esArchiver.load('alerting')); + after(() => esArchiver.unload('alerting')); + + it('should handle create action with disabled actionType request appropriately', async () => { + const response = await supertest + .post(`/api/action`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'My action', + actionTypeId: DISABLED_ACTION_TYPE, + }); + + expect(response.statusCode).to.eql(400); + expect(response.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'action type "test.not-enabled" is not enabled in the Kibana config xpack.actions.enabledActionTypes', + }); + }); + + it(`should handle execute request with disabled actionType appropriately`, async () => { + const response = await supertest + .post(`/api/action/${PREWRITTEN_ACTION_ID}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: {}, + }); + + expect(response.statusCode).to.eql(200); + expect(response.body).to.eql({ + status: 'error', + retry: false, + actionId: PREWRITTEN_ACTION_ID, + message: + 'action type "test.not-enabled" is not enabled in the Kibana config xpack.actions.enabledActionTypes', + }); + }); + + it('should handle get action request with disabled actionType appropriately', async () => { + const response = await supertest.get(`/api/action/${PREWRITTEN_ACTION_ID}`); + + expect(response.statusCode).to.eql(200); + expect(response.body).to.eql({ + actionTypeId: 'test.not-enabled', + config: {}, + id: 'uuid-actionId', + name: 'an action created before test.not-enabled was disabled', + }); + }); + + it('should handle update action request with disabled actionType appropriately', async () => { + const responseUpdate = await supertest + .put(`/api/action/${PREWRITTEN_ACTION_ID}`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'an action created before test.not-enabled was disabled (updated)', + }); + + expect(responseUpdate.statusCode).to.eql(200); + expect(responseUpdate.body).to.eql({ + actionTypeId: 'test.not-enabled', + config: {}, + id: 'uuid-actionId', + name: 'an action created before test.not-enabled was disabled (updated)', + }); + + const response = await supertest.get(`/api/action/${PREWRITTEN_ACTION_ID}`); + expect(response.statusCode).to.eql(200); + expect(response.body).to.eql({ + actionTypeId: 'test.not-enabled', + config: {}, + id: 'uuid-actionId', + name: 'an action created before test.not-enabled was disabled (updated)', + }); + }); + + it('should handle delete action request with disabled actionType appropriately', async () => { + let response; + + response = await supertest + .delete(`/api/action/${PREWRITTEN_ACTION_ID}`) + .set('kbn-xsrf', 'foo'); + expect(response.statusCode).to.eql(204); + + response = await supertest.get(`/api/action/${PREWRITTEN_ACTION_ID}`); + expect(response.statusCode).to.eql(404); + }); + }); +} diff --git a/x-pack/test/functional/es_archives/alerting/data.json b/x-pack/test/functional/es_archives/alerting/data.json new file mode 100644 index 00000000000000..325d79651196b9 --- /dev/null +++ b/x-pack/test/functional/es_archives/alerting/data.json @@ -0,0 +1,15 @@ +{ + "type": "doc", + "value": { + "index": ".kibana", + "id": "action:uuid-actionId", + "source": { + "type": "action", + "action": { + "actionTypeId": "test.not-enabled", + "name": "an action created before test.not-enabled was disabled", + "config": {} + } + } + } +} From 74e1d17cf4e07baee2c017c17678083187d794c0 Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Tue, 17 Dec 2019 15:43:19 +0100 Subject: [PATCH 07/60] Support 'enterprise' license type (#52273) * add enterprise license type to licensing plugin * add enterprise license to x-pack plugins * update uptime license list * improve naming in security plugin * update reporting licensing --- x-pack/legacy/common/constants/index.ts | 1 + .../legacy/common/constants/license_types.ts | 3 ++ .../common/constants/security.ts | 13 ++++++-- .../lib/adapters/framework/adapter_types.ts | 1 + .../server/lib/check_license/check_license.js | 2 +- .../check_license/__tests__/check_license.js | 2 +- .../server/lib/check_license/check_license.js | 2 +- .../request_trial_extension.test.js.snap | 2 ++ .../__snapshots__/start_trial.test.js.snap | 2 ++ .../__jest__/request_trial_extension.test.js | 14 +++++++++ .../__jest__/start_trial.test.js | 30 +++++++++++++++++++ .../store/reducers/license_management.js | 6 ++-- .../check_license/__tests__/check_license.js | 2 +- .../server/lib/check_license/check_license.js | 2 +- x-pack/legacy/plugins/maps/check_license.js | 1 + .../plugins/ml/common/constants/license.ts | 2 +- ...check_license.ts => check_license.test.ts} | 16 +++++----- .../server/lib/check_license/check_license.ts | 2 +- .../plugins/monitoring/common/constants.js | 2 +- .../cluster_alerts/__tests__/check_license.js | 7 +++++ .../server/cluster_alerts/check_license.js | 2 +- .../plugins/reporting/common/constants.ts | 1 + .../reporting/export_types/csv/index.ts | 2 ++ .../csv_from_savedobject/index.ts | 2 ++ .../reporting/export_types/png/index.ts | 2 ++ .../export_types/printable_pdf/index.ts | 2 ++ .../server/lib/__tests__/check_license.js | 2 +- .../check_license/__tests__/check_license.js | 2 +- .../server/lib/check_license/check_license.js | 2 +- .../server/np_ready/lib/check_license.test.ts | 2 +- .../server/np_ready/lib/check_license.ts | 11 ++++++- .../tilemap/server/lib/inspect_settings.js | 9 +++++- .../uptime/server/lib/domains/license.ts | 2 +- x-pack/plugins/features/common/feature.ts | 2 +- .../plugins/features/server/feature_schema.ts | 4 ++- .../plugins/licensing/common/license.test.ts | 6 ++++ x-pack/plugins/licensing/common/types.ts | 3 +- .../server/licensing/license_service.test.ts | 8 +++-- .../server/licensing/license_service.ts | 6 ++-- 39 files changed, 143 insertions(+), 39 deletions(-) rename x-pack/legacy/plugins/ml/server/lib/check_license/{__tests__/check_license.ts => check_license.test.ts} (89%) diff --git a/x-pack/legacy/common/constants/index.ts b/x-pack/legacy/common/constants/index.ts index 842b0aea91d304..4db0f994fd47e4 100644 --- a/x-pack/legacy/common/constants/index.ts +++ b/x-pack/legacy/common/constants/index.ts @@ -16,6 +16,7 @@ export { LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, LICENSE_TYPE_TRIAL, RANKED_LICENSE_TYPES, LicenseType, diff --git a/x-pack/legacy/common/constants/license_types.ts b/x-pack/legacy/common/constants/license_types.ts index 3971ed5e95174e..8c329df2f85f78 100644 --- a/x-pack/legacy/common/constants/license_types.ts +++ b/x-pack/legacy/common/constants/license_types.ts @@ -8,6 +8,7 @@ export const LICENSE_TYPE_BASIC = 'basic'; export const LICENSE_TYPE_STANDARD = 'standard'; export const LICENSE_TYPE_GOLD = 'gold'; export const LICENSE_TYPE_PLATINUM = 'platinum'; +export const LICENSE_TYPE_ENTERPRISE = 'enterprise'; export const LICENSE_TYPE_TRIAL = 'trial'; export type LicenseType = @@ -15,6 +16,7 @@ export type LicenseType = | typeof LICENSE_TYPE_STANDARD | typeof LICENSE_TYPE_GOLD | typeof LICENSE_TYPE_PLATINUM + | typeof LICENSE_TYPE_ENTERPRISE | typeof LICENSE_TYPE_TRIAL; // These are ordered from least featureful to most featureful, so we can assume that someone holding @@ -24,5 +26,6 @@ export const RANKED_LICENSE_TYPES = [ LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, LICENSE_TYPE_TRIAL, ]; diff --git a/x-pack/legacy/plugins/beats_management/common/constants/security.ts b/x-pack/legacy/plugins/beats_management/common/constants/security.ts index c80b036dddf835..3a9858979dbb91 100644 --- a/x-pack/legacy/plugins/beats_management/common/constants/security.ts +++ b/x-pack/legacy/plugins/beats_management/common/constants/security.ts @@ -5,6 +5,13 @@ */ export const REQUIRED_ROLES = ['beats_admin']; -export const REQUIRED_LICENSES = ['standard', 'gold', 'trial', 'platinum']; -export const LICENSES = ['oss', 'basic', 'standard', 'gold', 'trial', 'platinum']; -export type LicenseType = 'oss' | 'basic' | 'trial' | 'standard' | 'basic' | 'gold' | 'platinum'; +export const REQUIRED_LICENSES = ['standard', 'gold', 'trial', 'platinum', 'enterprise']; +export const LICENSES = ['oss', 'basic', 'standard', 'gold', 'trial', 'platinum', 'enterprise']; +export type LicenseType = + | 'oss' + | 'basic' + | 'trial' + | 'standard' + | 'gold' + | 'platinum' + | 'enterprise'; diff --git a/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts b/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts index 08832772dd0473..bb1f68e1c03b37 100644 --- a/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/legacy/plugins/beats_management/server/lib/adapters/framework/adapter_types.ts @@ -82,6 +82,7 @@ export const RuntimeFrameworkInfo = t.interface( basic: null, gold: null, platinum: null, + enterprise: null, }), expired: t.boolean, expiry_date_in_millis: t.number, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/cross_cluster_replication/server/lib/check_license/check_license.js index 29e6f2d3f8a5b2..6cf12896fa472d 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/lib/check_license/check_license.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/server/lib/check_license/check_license.js @@ -27,7 +27,7 @@ export function checkLicense(xpackLicenseInfo) { }; } - const VALID_LICENSE_MODES = ['trial', 'platinum']; + const VALID_LICENSE_MODES = ['trial', 'platinum', 'enterprise']; const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); const isLicenseActive = xpackLicenseInfo.license.isActive(); diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js index 4e57bd77578e39..933fda01c055db 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js +++ b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/__tests__/check_license.js @@ -58,7 +58,7 @@ describe('check_license', function() { set(mockLicenseInfo, 'license.getType', () => 'basic'); }); - describe('& license is trial, standard, gold, platinum', () => { + describe('& license is > basic', () => { beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); describe('& license is active', () => { diff --git a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.js index 7df956af98c7ba..e71820a346f918 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.js +++ b/x-pack/legacy/plugins/index_lifecycle_management/server/lib/check_license/check_license.js @@ -22,7 +22,7 @@ export function checkLicense(xpackLicenseInfo) { }; } - const VALID_LICENSE_MODES = ['trial', 'basic', 'standard', 'gold', 'platinum']; + const VALID_LICENSE_MODES = ['basic', 'standard', 'gold', 'platinum', 'enterprise', 'trial']; const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); const isLicenseActive = xpackLicenseInfo.license.isActive(); diff --git a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap index 8670b2c378dca1..0f4e8f9b63aa06 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap +++ b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/request_trial_extension.test.js.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`RequestTrialExtension component should display when enterprise license is not active and trial has been used 1`] = `"
Extend your trial

If you’d like to continue using machine learning, advanced security, and our other awesome Platinum features, request an extension now.

"`; + exports[`RequestTrialExtension component should display when license is active and trial has been used 1`] = `"
Extend your trial

If you’d like to continue using machine learning, advanced security, and our other awesome Platinum features, request an extension now.

"`; exports[`RequestTrialExtension component should display when license is not active and trial has been used 1`] = `"
Extend your trial

If you’d like to continue using machine learning, advanced security, and our other awesome Platinum features, request an extension now.

"`; diff --git a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap index df82a820e95136..9370b77e295607 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap +++ b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/start_trial.test.js.snap @@ -2,6 +2,8 @@ exports[`StartTrial component when trial is allowed display for basic license 1`] = `"
Start a 30-day trial

Experience what machine learning, advanced security, and all our other Platinum features have to offer.

"`; +exports[`StartTrial component when trial is allowed should display for expired enterprise license 1`] = `"
Start a 30-day trial

Experience what machine learning, advanced security, and all our other Platinum features have to offer.

"`; + exports[`StartTrial component when trial is allowed should display for expired platinum license 1`] = `"
Start a 30-day trial

Experience what machine learning, advanced security, and all our other Platinum features have to offer.

"`; exports[`StartTrial component when trial is allowed should display for gold license 1`] = `"
Start a 30-day trial

Experience what machine learning, advanced security, and all our other Platinum features have to offer.

"`; diff --git a/x-pack/legacy/plugins/license_management/__jest__/request_trial_extension.test.js b/x-pack/legacy/plugins/license_management/__jest__/request_trial_extension.test.js index 4de8f6ea6efd24..a74a7b16185c6d 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/request_trial_extension.test.js +++ b/x-pack/legacy/plugins/license_management/__jest__/request_trial_extension.test.js @@ -75,6 +75,20 @@ describe('RequestTrialExtension component', () => { expect(html).not.toBeNull(); expect(html).toMatchSnapshot(); }); + test('should display when enterprise license is not active and trial has been used', () => { + const rendered = getComponent( + { + trialStatus: { + canStartTrial: false, + }, + license: createMockLicense('enterprise', 0), + }, + RequestTrialExtension + ); + const html = rendered.html(); + expect(html).not.toBeNull(); + expect(html).toMatchSnapshot(); + }); test('should not display when platinum license is active and trial has been used', () => { const rendered = getComponent( { diff --git a/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js b/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js index c37c56aa7a1adc..69c606c866eef3 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js +++ b/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js @@ -60,6 +60,26 @@ describe('StartTrial component when trial is allowed', () => { ); expect(rendered.html()).toMatchSnapshot(); }); + test('should not display for active enterprise license', () => { + const rendered = getComponent( + { + license: createMockLicense('enterprise'), + trialStatus: { canStartTrial: true }, + }, + StartTrial + ); + expect(rendered.isEmptyRender()).toBeTruthy(); + }); + test('should display for expired enterprise license', () => { + const rendered = getComponent( + { + license: createMockLicense('enterprise', 0), + trialStatus: { canStartTrial: true }, + }, + StartTrial + ); + expect(rendered.html()).toMatchSnapshot(); + }); }); describe('StartTrial component when trial is not available', () => { @@ -93,6 +113,16 @@ describe('StartTrial component when trial is not available', () => { ); expect(rendered.isEmptyRender()).toBeTruthy(); }); + test('should not display for enterprise license', () => { + const rendered = getComponent( + { + license: createMockLicense('enterprise'), + trialStatus: { canStartTrial: false }, + }, + StartTrial + ); + expect(rendered.isEmptyRender()).toBeTruthy(); + }); test('should not display for trial license', () => { const rendered = getComponent( diff --git a/x-pack/legacy/plugins/license_management/public/np_ready/application/store/reducers/license_management.js b/x-pack/legacy/plugins/license_management/public/np_ready/application/store/reducers/license_management.js index 3023a12101c5d5..c821b7bb294f95 100644 --- a/x-pack/legacy/plugins/license_management/public/np_ready/application/store/reducers/license_management.js +++ b/x-pack/legacy/plugins/license_management/public/np_ready/application/store/reducers/license_management.js @@ -110,8 +110,8 @@ export const shouldShowStartTrial = state => { return ( state.trialStatus.canStartTrial && licenseType !== 'trial' && - //don't show for platinum unless it is expired - (licenseType !== 'platinum' || isExpired(state)) + //don't show for platinum & enterprise unless it is expired + ((licenseType !== 'platinum' && licenseType !== 'enterprise') || isExpired(state)) ); }; @@ -120,7 +120,7 @@ export const shouldShowRequestTrialExtension = state => { return false; } const { type } = getLicense(state); - return type !== 'platinum' || isExpired(state); + return (type !== 'platinum' && type !== 'enterprise') || isExpired(state); }; export const startTrialError = state => { diff --git a/x-pack/legacy/plugins/logstash/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/logstash/server/lib/check_license/__tests__/check_license.js index 51d2d7198234f9..5fcce0aaa12190 100755 --- a/x-pack/legacy/plugins/logstash/server/lib/check_license/__tests__/check_license.js +++ b/x-pack/legacy/plugins/logstash/server/lib/check_license/__tests__/check_license.js @@ -58,7 +58,7 @@ describe('check_license', function() { set(mockLicenseInfo, 'license.getType', () => 'basic'); }); - describe('& license is trial, standard, gold, platinum', () => { + describe('& license is > basic', () => { beforeEach(() => { set(mockLicenseInfo, 'license.isOneOf', () => true); mockLicenseInfo.feature = () => ({ isEnabled: () => true }); // Security feature is enabled diff --git a/x-pack/legacy/plugins/logstash/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/logstash/server/lib/check_license/check_license.js index fe68d37e0f4968..31136ae1c72a5c 100755 --- a/x-pack/legacy/plugins/logstash/server/lib/check_license/check_license.js +++ b/x-pack/legacy/plugins/logstash/server/lib/check_license/check_license.js @@ -24,7 +24,7 @@ export function checkLicense(xpackLicenseInfo) { }; } - const VALID_LICENSE_MODES = ['trial', 'standard', 'gold', 'platinum']; + const VALID_LICENSE_MODES = ['trial', 'standard', 'gold', 'platinum', 'enterprise']; const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); const isLicenseActive = xpackLicenseInfo.license.isActive(); diff --git a/x-pack/legacy/plugins/maps/check_license.js b/x-pack/legacy/plugins/maps/check_license.js index 54c423220b68a4..9e5397ee5dc755 100644 --- a/x-pack/legacy/plugins/maps/check_license.js +++ b/x-pack/legacy/plugins/maps/check_license.js @@ -21,6 +21,7 @@ export function checkLicense(xPackInfo) { 'standard', 'gold', 'platinum', + 'enterprise', 'trial', ]); diff --git a/x-pack/legacy/plugins/ml/common/constants/license.ts b/x-pack/legacy/plugins/ml/common/constants/license.ts index 23663db69b050a..2027e2c8b18653 100644 --- a/x-pack/legacy/plugins/ml/common/constants/license.ts +++ b/x-pack/legacy/plugins/ml/common/constants/license.ts @@ -6,5 +6,5 @@ export enum LICENSE_TYPE { BASIC, - FULL, // platinum or trial + FULL, // >= platinum } diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.test.ts similarity index 89% rename from x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts rename to x-pack/legacy/plugins/ml/server/lib/check_license/check_license.test.ts index 5a8b4fdcc76dba..1d80a226486bb1 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts +++ b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.test.ts @@ -7,30 +7,28 @@ import expect from '@kbn/expect'; import sinon from 'sinon'; import { set } from 'lodash'; -import { XPackInfo } from '../../../../../../../legacy/plugins/xpack_main/server/lib/xpack_info'; -import { checkLicense } from '../check_license'; +import { XPackInfo } from '../../../../xpack_main/server/lib/xpack_info'; +import { checkLicense } from './check_license'; describe('check_license', () => { let mockLicenseInfo: XPackInfo; beforeEach(() => (mockLicenseInfo = {} as XPackInfo)); describe('license information is undefined', () => { - beforeEach(() => (mockLicenseInfo = {} as XPackInfo)); - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); + expect(checkLicense(undefined as any).isAvailable).to.be(false); }); it('should set showLinks to true', () => { - expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); + expect(checkLicense(undefined as any).showLinks).to.be(true); }); it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); + expect(checkLicense(undefined as any).enableLinks).to.be(false); }); it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); + expect(checkLicense(undefined as any).message).to.not.be(undefined); }); }); @@ -101,7 +99,7 @@ describe('check_license', () => { ); }); - describe('& license is trial or platinum', () => { + describe('& license is >= platinum', () => { beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); describe('& license is active', () => { diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts index bb92705880dde9..c88ab087a81985 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts +++ b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts @@ -47,7 +47,7 @@ export function checkLicense(xpackLicenseInfo: XPackInfo): Response { }; } - const VALID_FULL_LICENSE_MODES = ['trial', 'platinum']; + const VALID_FULL_LICENSE_MODES = ['platinum', 'enterprise', 'trial']; const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_FULL_LICENSE_MODES); const licenseType = isLicenseModeValid === true ? LICENSE_TYPE.FULL : LICENSE_TYPE.BASIC; diff --git a/x-pack/legacy/plugins/monitoring/common/constants.js b/x-pack/legacy/plugins/monitoring/common/constants.js index e4936d8003552c..917f7fab1ed304 100644 --- a/x-pack/legacy/plugins/monitoring/common/constants.js +++ b/x-pack/legacy/plugins/monitoring/common/constants.js @@ -96,7 +96,7 @@ export const CALCULATE_DURATION_UNTIL = 'until'; /** * In order to show ML Jobs tab in the Elasticsearch section / tab navigation, license must be supported */ -export const ML_SUPPORTED_LICENSES = ['trial', 'platinum']; +export const ML_SUPPORTED_LICENSES = ['trial', 'platinum', 'enterprise']; /** * Metadata service URLs for the different cloud services that have constant URLs (e.g., unlike GCP, which is a constant prefix). diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js index d7b524c9d5c82e..e0528209c50ae7 100644 --- a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js +++ b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js @@ -62,6 +62,13 @@ describe('Monitoring Check License', () => { }); }); + it('enterprise active license - results true with no message', () => { + const result = checkLicense('enterprise', true, 'test-cluster-pqr'); + expect(result).to.eql({ + clusterAlerts: { enabled: true }, + }); + }); + describe('Watcher is not enabled', () => { it('platinum active license - watcher disabled - results false with message', () => { const result = checkLicense('platinum', true, 'test-cluster-pqr', false); diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/check_license.js b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/check_license.js index fe9c5de7e5a859..a6c033b6b1f13a 100644 --- a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/check_license.js +++ b/x-pack/legacy/plugins/monitoring/server/cluster_alerts/check_license.js @@ -38,7 +38,7 @@ export function checkLicense(type, active, clusterSource, watcher = true) { } // Disabled because the license type is not valid (basic) - if (!includes(['trial', 'standard', 'gold', 'platinum'], type)) { + if (!includes(['trial', 'standard', 'gold', 'platinum', 'enterprise'], type)) { return Object.assign(licenseInfo, { message: i18n.translate( 'xpack.monitoring.clusterAlerts.checkLicense.licenseIsBasicDescription', diff --git a/x-pack/legacy/plugins/reporting/common/constants.ts b/x-pack/legacy/plugins/reporting/common/constants.ts index 03b2d51c7b3965..e602d5fc608d33 100644 --- a/x-pack/legacy/plugins/reporting/common/constants.ts +++ b/x-pack/legacy/plugins/reporting/common/constants.ts @@ -56,3 +56,4 @@ export const LICENSE_TYPE_BASIC = 'basic'; export const LICENSE_TYPE_STANDARD = 'standard'; export const LICENSE_TYPE_GOLD = 'gold'; export const LICENSE_TYPE_PLATINUM = 'platinum'; +export const LICENSE_TYPE_ENTERPRISE = 'enterprise'; diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/index.ts b/x-pack/legacy/plugins/reporting/export_types/csv/index.ts index 4f8aeb2be0c993..942cb954785acd 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/index.ts @@ -11,6 +11,7 @@ import { LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, } from '../../common/constants'; import { ExportTypeDefinition, ESQueueCreateJobFn, ESQueueWorkerExecuteFn } from '../../types'; import { metadata } from './metadata'; @@ -35,5 +36,6 @@ export const getExportType = (): ExportTypeDefinition< LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, ], }); diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts index 4876cea0b1b28b..606630944c604d 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts @@ -11,6 +11,7 @@ import { LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, } from '../../common/constants'; import { ExportTypeDefinition, ImmediateCreateJobFn, ImmediateExecuteFn } from '../../types'; import { createJobFactory } from './server/create_job'; @@ -42,5 +43,6 @@ export const getExportType = (): ExportTypeDefinition< LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, ], }); diff --git a/x-pack/legacy/plugins/reporting/export_types/png/index.ts b/x-pack/legacy/plugins/reporting/export_types/png/index.ts index bc00bc428f3066..b6206a8bf9599b 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/png/index.ts @@ -10,6 +10,7 @@ import { LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, } from '../../common/constants'; import { ExportTypeDefinition, ESQueueCreateJobFn, ESQueueWorkerExecuteFn } from '../../types'; import { createJobFactory } from './server/create_job'; @@ -34,5 +35,6 @@ export const getExportType = (): ExportTypeDefinition< LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, ], }); diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts index 99880c1237a7a5..b7b71ff5c57411 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts @@ -10,6 +10,7 @@ import { LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, } from '../../common/constants'; import { ExportTypeDefinition, ESQueueCreateJobFn, ESQueueWorkerExecuteFn } from '../../types'; import { createJobFactory } from './server/create_job'; @@ -34,5 +35,6 @@ export const getExportType = (): ExportTypeDefinition< LICENSE_TYPE_STANDARD, LICENSE_TYPE_GOLD, LICENSE_TYPE_PLATINUM, + LICENSE_TYPE_ENTERPRISE, ], }); diff --git a/x-pack/legacy/plugins/reporting/server/lib/__tests__/check_license.js b/x-pack/legacy/plugins/reporting/server/lib/__tests__/check_license.js index 19af54f98236af..394f88c37087c9 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/__tests__/check_license.js +++ b/x-pack/legacy/plugins/reporting/server/lib/__tests__/check_license.js @@ -55,7 +55,7 @@ describe('check_license', function() { set(mockLicenseInfo, 'license.getType', () => 'basic'); }); - describe('& license is trial, standard, gold, platinum', () => { + describe('& license is > basic', () => { beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); describe('& license is active', () => { diff --git a/x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js index 4e57bd77578e39..933fda01c055db 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js +++ b/x-pack/legacy/plugins/rollup/server/lib/check_license/__tests__/check_license.js @@ -58,7 +58,7 @@ describe('check_license', function() { set(mockLicenseInfo, 'license.getType', () => 'basic'); }); - describe('& license is trial, standard, gold, platinum', () => { + describe('& license is > basic', () => { beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); describe('& license is active', () => { diff --git a/x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js index ba59c5e4e44439..3885a20a1f358a 100644 --- a/x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js +++ b/x-pack/legacy/plugins/rollup/server/lib/check_license/check_license.js @@ -24,7 +24,7 @@ export function checkLicense(xpackLicenseInfo) { }; } - const VALID_LICENSE_MODES = ['trial', 'basic', 'standard', 'gold', 'platinum']; + const VALID_LICENSE_MODES = ['trial', 'basic', 'standard', 'gold', 'platinum', 'enterprise']; const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); const isLicenseActive = xpackLicenseInfo.license.isActive(); diff --git a/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.test.ts b/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.test.ts index f473533fbd48ae..1b8155221cb9d1 100644 --- a/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.test.ts +++ b/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.test.ts @@ -30,7 +30,7 @@ describe('check_license', () => { set(mockLicenseInfo, 'license.getType', () => 'basic'); }); - describe('& license is trial, standard, gold, platinum', () => { + describe('& license is > basic', () => { beforeEach(() => set(mockLicenseInfo, 'license.isOneOf', () => true)); describe('& license is active', () => { diff --git a/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.ts b/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.ts index e41925da3e2688..2a22d615ca6e54 100644 --- a/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.ts +++ b/x-pack/legacy/plugins/searchprofiler/server/np_ready/lib/check_license.ts @@ -29,7 +29,16 @@ export function checkLicense( }); } - if (xpackLicenseInfo.license.isOneOf(['trial', 'basic', 'standard', 'gold', 'platinum'])) { + if ( + xpackLicenseInfo.license.isOneOf([ + 'trial', + 'basic', + 'standard', + 'gold', + 'platinum', + 'enterprise', + ]) + ) { return { showAppLink: true, enableAppLink: isLicenseActive, diff --git a/x-pack/legacy/plugins/tilemap/server/lib/inspect_settings.js b/x-pack/legacy/plugins/tilemap/server/lib/inspect_settings.js index 41c15c1387648a..cd6fb8bd8c1100 100644 --- a/x-pack/legacy/plugins/tilemap/server/lib/inspect_settings.js +++ b/x-pack/legacy/plugins/tilemap/server/lib/inspect_settings.js @@ -19,7 +19,14 @@ export function inspectSettings(xpackInfo) { license: { uid: xpackInfo.license.getUid(), active: xpackInfo.license.isActive(), - valid: xpackInfo.license.isOneOf(['trial', 'standard', 'basic', 'gold', 'platinum']), + valid: xpackInfo.license.isOneOf([ + 'trial', + 'standard', + 'basic', + 'gold', + 'platinum', + 'enterprise', + ]), }, }; } diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts b/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts index 9c52667aeeab49..947bad75075ef9 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts @@ -21,7 +21,7 @@ export const licenseCheck: UMLicenseCheck = license => { statusCode: 400, }; } - if (!license.isOneOf(['basic', 'standard', 'gold', 'platinum', 'trial'])) { + if (!license.isOneOf(['basic', 'standard', 'gold', 'platinum', 'enterprise', 'trial'])) { return { message: 'License not supported', statusCode: 401, diff --git a/x-pack/plugins/features/common/feature.ts b/x-pack/plugins/features/common/feature.ts index 592ac654655d88..423fe1eb997040 100644 --- a/x-pack/plugins/features/common/feature.ts +++ b/x-pack/plugins/features/common/feature.ts @@ -43,7 +43,7 @@ export interface Feature< * This does not restrict access to your feature based on license. * Its only purpose is to inform the space and roles UIs on which features to display. */ - validLicenses?: Array<'basic' | 'standard' | 'gold' | 'platinum'>; + validLicenses?: Array<'basic' | 'standard' | 'gold' | 'platinum' | 'enterprise'>; /** * An optional EUI Icon to be used when displaying your feature. diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index 8926bd766be32e..7732686db5ee14 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -50,7 +50,9 @@ const schema = Joi.object({ .required(), name: Joi.string().required(), excludeFromBasePrivileges: Joi.boolean(), - validLicenses: Joi.array().items(Joi.string().valid('basic', 'standard', 'gold', 'platinum')), + validLicenses: Joi.array().items( + Joi.string().valid('basic', 'standard', 'gold', 'platinum', 'enterprise') + ), icon: Joi.string(), description: Joi.string(), navLinkId: Joi.string().regex(uiCapabilitiesRegex), diff --git a/x-pack/plugins/licensing/common/license.test.ts b/x-pack/plugins/licensing/common/license.test.ts index 884327acd778cc..8035a92952e107 100644 --- a/x-pack/plugins/licensing/common/license.test.ts +++ b/x-pack/plugins/licensing/common/license.test.ts @@ -12,6 +12,7 @@ describe('License', () => { const basicLicense = licenseMock.create(); const basicExpiredLicense = licenseMock.create({ license: { status: 'expired' } }); const goldLicense = licenseMock.create({ license: { type: 'gold' } }); + const enterpriseLicense = licenseMock.create({ license: { type: 'enterprise' } }); const errorMessage = 'unavailable'; const errorLicense = new License({ error: errorMessage, signature: '' }); @@ -52,6 +53,7 @@ describe('License', () => { it('isBasic', () => { expect(basicLicense.isBasic).toBe(true); expect(goldLicense.isBasic).toBe(false); + expect(enterpriseLicense.isBasic).toBe(false); expect(errorLicense.isBasic).toBe(false); expect(unavailableLicense.isBasic).toBe(false); }); @@ -59,6 +61,7 @@ describe('License', () => { it('isNotBasic', () => { expect(basicLicense.isNotBasic).toBe(false); expect(goldLicense.isNotBasic).toBe(true); + expect(enterpriseLicense.isNotBasic).toBe(true); expect(errorLicense.isNotBasic).toBe(false); expect(unavailableLicense.isNotBasic).toBe(false); }); @@ -106,6 +109,9 @@ describe('License', () => { expect(unavailableLicense.check('ccr', 'basic').state).toBe(LICENSE_CHECK_STATE.Unavailable); expect(unavailableLicense.check('ccr', 'gold').state).toBe(LICENSE_CHECK_STATE.Unavailable); + + expect(enterpriseLicense.check('ccr', 'gold').state).toBe(LICENSE_CHECK_STATE.Valid); + expect(enterpriseLicense.check('ccr', 'enterprise').state).toBe(LICENSE_CHECK_STATE.Valid); }); it('throws in case of unknown license type', () => { diff --git a/x-pack/plugins/licensing/common/types.ts b/x-pack/plugins/licensing/common/types.ts index 840f90e083d5ee..c4b9f4ebad19d2 100644 --- a/x-pack/plugins/licensing/common/types.ts +++ b/x-pack/plugins/licensing/common/types.ts @@ -16,7 +16,8 @@ export enum LICENSE_TYPE { standard = 20, gold = 30, platinum = 40, - trial = 50, + enterprise = 50, + trial = 60, } /** @public */ diff --git a/x-pack/plugins/security/server/licensing/license_service.test.ts b/x-pack/plugins/security/server/licensing/license_service.test.ts index d5d33c07985fd8..aa1e420bf4f6cc 100644 --- a/x-pack/plugins/security/server/licensing/license_service.test.ts +++ b/x-pack/plugins/security/server/licensing/license_service.test.ts @@ -82,11 +82,15 @@ describe('license features', function() { }); }); - it('should allow to login, allow RBAC and document level security if license is platinum or trial.', () => { + it('should allow to login, allow RBAC and document level security if license >= platinum', () => { const mockRawLicense = getMockRawLicense({ isAvailable: true }); mockRawLicense.isOneOf.mockImplementation(licenses => { const licenseArray = [licenses].flat(); - return licenseArray.includes('trial') || licenseArray.includes('platinum'); + return ( + licenseArray.includes('trial') || + licenseArray.includes('platinum') || + licenseArray.includes('enterprise') + ); }); mockRawLicense.getFeature.mockReturnValue({ isEnabled: true, isAvailable: true }); diff --git a/x-pack/plugins/security/server/licensing/license_service.ts b/x-pack/plugins/security/server/licensing/license_service.ts index 58c445de9319de..e9e2791efbd171 100644 --- a/x-pack/plugins/security/server/licensing/license_service.ts +++ b/x-pack/plugins/security/server/licensing/license_service.ts @@ -69,14 +69,14 @@ export class SecurityLicenseService { }; } - const isLicensePlatinumOrTrial = rawLicense.isOneOf(['platinum', 'trial']); + const isLicensePlatinumOrBetter = rawLicense.isOneOf(['platinum', 'enterprise', 'trial']); return { showLogin: true, allowLogin: true, showLinks: true, // Only platinum and trial licenses are compliant with field- and document-level security. - allowRoleDocumentLevelSecurity: isLicensePlatinumOrTrial, - allowRoleFieldLevelSecurity: isLicensePlatinumOrTrial, + allowRoleDocumentLevelSecurity: isLicensePlatinumOrBetter, + allowRoleFieldLevelSecurity: isLicensePlatinumOrBetter, allowRbac: true, }; }, From 2b6ef5c2bb1c14b3fdb1b2bc1b2cad06221d561b Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Tue, 17 Dec 2019 15:16:40 +0000 Subject: [PATCH 08/60] Moves Task manager's interval under a generic schedule field (#52727) This moves the interval field under a generic schedule object field in preparation for the introduction of richer scheduling options (such as cron). It includes a migration for existing tasks, and we've ensured no existing Task Type Definitions exist in Kibana that rely on Interval. This includes support for the deprecated interval field (which gets mapped to schedule) but that support will be removed in 8.0.0, as it's a breaking change. --- x-pack/legacy/plugins/task_manager/README.md | 6 +- .../lib/correct_deprecated_fields.test.ts | 100 ++++++++++++++++++ .../lib/correct_deprecated_fields.ts | 27 +++++ .../legacy/plugins/task_manager/mappings.json | 8 +- .../legacy/plugins/task_manager/migrations.ts | 20 ++++ .../mark_available_tasks_as_claimed.test.ts | 10 +- .../mark_available_tasks_as_claimed.ts | 4 +- x-pack/legacy/plugins/task_manager/task.ts | 27 ++++- .../plugins/task_manager/task_manager.test.ts | 2 +- .../plugins/task_manager/task_manager.ts | 10 +- .../plugins/task_manager/task_runner.test.ts | 34 +++--- .../plugins/task_manager/task_runner.ts | 15 ++- .../plugins/task_manager/task_store.test.ts | 36 +++---- .../legacy/plugins/task_manager/task_store.ts | 6 +- .../plugins/task_manager/init_routes.js | 4 +- .../task_manager/task_manager_integration.js | 33 ++++-- 16 files changed, 271 insertions(+), 71 deletions(-) create mode 100644 x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.test.ts create mode 100644 x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.ts diff --git a/x-pack/legacy/plugins/task_manager/README.md b/x-pack/legacy/plugins/task_manager/README.md index 9ca873e77fe688..3afcb758260c01 100644 --- a/x-pack/legacy/plugins/task_manager/README.md +++ b/x-pack/legacy/plugins/task_manager/README.md @@ -163,8 +163,8 @@ The data stored for a task instance looks something like this: runAt: "2020-07-24T17:34:35.272Z", // Indicates that this is a recurring task. We currently only support - // minute syntax `5m` or second syntax `10s`. - interval: '5m', + // interval syntax with either minutes such as `5m` or seconds `10s`. + schedule: { interval: '5m' }, // How many times this task has been unsuccesfully attempted, // this will be reset to 0 if the task ever succesfully completes. @@ -233,7 +233,7 @@ const taskManager = server.plugins.task_manager; const task = await taskManager.schedule({ taskType, runAt, - interval, + schedule, params, scope: ['my-fanci-app'], }); diff --git a/x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.test.ts b/x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.test.ts new file mode 100644 index 00000000000000..408e8d36d3491e --- /dev/null +++ b/x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.test.ts @@ -0,0 +1,100 @@ +/* + * 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 { ensureDeprecatedFieldsAreCorrected } from './correct_deprecated_fields'; +import { mockLogger } from '../test_utils'; + +describe('ensureDeprecatedFieldsAreCorrected', () => { + test('doesnt change tasks without any schedule fields', async () => { + expect( + ensureDeprecatedFieldsAreCorrected( + { + id: 'my-foo-id', + taskType: 'foo', + params: {}, + state: {}, + }, + mockLogger() + ) + ).toEqual({ + id: 'my-foo-id', + taskType: 'foo', + params: {}, + state: {}, + }); + }); + test('doesnt change tasks with the schedule field', async () => { + expect( + ensureDeprecatedFieldsAreCorrected( + { + id: 'my-foo-id', + taskType: 'foo', + schedule: { interval: '10m' }, + params: {}, + state: {}, + }, + mockLogger() + ) + ).toEqual({ + id: 'my-foo-id', + taskType: 'foo', + schedule: { interval: '10m' }, + params: {}, + state: {}, + }); + }); + test('corrects tasks with the deprecated inteval field', async () => { + expect( + ensureDeprecatedFieldsAreCorrected( + { + id: 'my-foo-id', + taskType: 'foo', + interval: '10m', + params: {}, + state: {}, + }, + mockLogger() + ) + ).toEqual({ + id: 'my-foo-id', + taskType: 'foo', + schedule: { interval: '10m' }, + params: {}, + state: {}, + }); + }); + test('logs a warning when a deprecated inteval is corrected on a task', async () => { + const logger = mockLogger(); + ensureDeprecatedFieldsAreCorrected( + { + taskType: 'foo', + interval: '10m', + params: {}, + state: {}, + }, + logger + ); + expect(logger.warn).toHaveBeenCalledWith( + `Task of type "foo" has been scheduled with the deprecated 'interval' field which is due to be removed in a future release` + ); + }); + test('logs a warning when a deprecated inteval is corrected on a task with an id', async () => { + const logger = mockLogger(); + ensureDeprecatedFieldsAreCorrected( + { + id: 'my-foo-id', + taskType: 'foo', + interval: '10m', + params: {}, + state: {}, + }, + logger + ); + expect(logger.warn).toHaveBeenCalledWith( + `Task "my-foo-id" of type "foo" has been scheduled with the deprecated 'interval' field which is due to be removed in a future release` + ); + }); +}); diff --git a/x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.ts b/x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.ts new file mode 100644 index 00000000000000..2de95cbb8c2fa5 --- /dev/null +++ b/x-pack/legacy/plugins/task_manager/lib/correct_deprecated_fields.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. + */ + +import { TaskInstance, TaskInstanceWithDeprecatedFields } from '../task'; +import { Logger } from '../types'; + +export function ensureDeprecatedFieldsAreCorrected( + { id, taskType, interval, schedule, ...taskInstance }: TaskInstanceWithDeprecatedFields, + logger: Logger +): TaskInstance { + if (interval) { + logger.warn( + `Task${ + id ? ` "${id}"` : '' + } of type "${taskType}" has been scheduled with the deprecated 'interval' field which is due to be removed in a future release` + ); + } + return { + id, + taskType, + ...taskInstance, + schedule: schedule || (interval ? { interval } : undefined), + }; +} diff --git a/x-pack/legacy/plugins/task_manager/mappings.json b/x-pack/legacy/plugins/task_manager/mappings.json index 96653a4de1b316..1728c8f1c552bd 100644 --- a/x-pack/legacy/plugins/task_manager/mappings.json +++ b/x-pack/legacy/plugins/task_manager/mappings.json @@ -16,8 +16,12 @@ "retryAt": { "type": "date" }, - "interval": { - "type": "text" + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } }, "attempts": { "type": "integer" diff --git a/x-pack/legacy/plugins/task_manager/migrations.ts b/x-pack/legacy/plugins/task_manager/migrations.ts index 65ca38d0b447dd..2853be0c4d5b2c 100644 --- a/x-pack/legacy/plugins/task_manager/migrations.ts +++ b/x-pack/legacy/plugins/task_manager/migrations.ts @@ -15,5 +15,25 @@ export const migrations = { ...doc, updated_at: new Date().toISOString(), }), + '7.6.0': moveIntervalIntoSchedule, }, }; + +function moveIntervalIntoSchedule({ + attributes: { interval, ...attributes }, + ...doc +}: SavedObject) { + return { + ...doc, + attributes: { + ...attributes, + ...(interval + ? { + schedule: { + interval, + }, + } + : {}), + }, + }; +} diff --git a/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.test.ts b/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.test.ts index b8ea7d2db832e7..93a8187b673be1 100644 --- a/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.test.ts +++ b/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.test.ts @@ -18,7 +18,7 @@ import { updateFields, IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt, - RecuringTaskWithInterval, + TaskWithSchedule, taskWithLessThanMaxAttempts, SortByRunAtAndRetryAt, } from './mark_available_tasks_as_claimed'; @@ -50,9 +50,9 @@ describe('mark_available_tasks_as_claimed', () => { // Either a task with idle status and runAt <= now or // status running or claiming with a retryAt <= now. shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt), - // Either task has an interval or the attempts < the maximum configured + // Either task has an schedule or the attempts < the maximum configured shouldBeOneOf( - RecuringTaskWithInterval, + TaskWithSchedule, ...Object.entries(definitions).map(([type, { maxAttempts }]) => taskWithLessThanMaxAttempts(type, maxAttempts || defaultMaxAttempts) ) @@ -100,11 +100,11 @@ describe('mark_available_tasks_as_claimed', () => { ], }, }, - // Either task has an interval or the attempts < the maximum configured + // Either task has an recurring schedule or the attempts < the maximum configured { bool: { should: [ - { exists: { field: 'task.interval' } }, + { exists: { field: 'task.schedule' } }, { bool: { must: [ diff --git a/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.ts b/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.ts index 1da45509988854..6691b31a546bc2 100644 --- a/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.ts +++ b/x-pack/legacy/plugins/task_manager/queries/mark_available_tasks_as_claimed.ts @@ -14,7 +14,9 @@ import { RangeBoolClause, } from './query_clauses'; -export const RecuringTaskWithInterval: ExistsBoolClause = { exists: { field: 'task.interval' } }; +export const TaskWithSchedule: ExistsBoolClause = { + exists: { field: 'task.schedule' }, +}; export function taskWithLessThanMaxAttempts( type: string, maxAttempts: number diff --git a/x-pack/legacy/plugins/task_manager/task.ts b/x-pack/legacy/plugins/task_manager/task.ts index 2bde8a9a765442..48e87582ce3fe6 100644 --- a/x-pack/legacy/plugins/task_manager/task.ts +++ b/x-pack/legacy/plugins/task_manager/task.ts @@ -133,7 +133,7 @@ export interface TaskDefinition { * function can return `true`, `false` or a Date. True will tell task manager * to retry using default delay logic. False will tell task manager to stop retrying * this task. Date will suggest when to the task manager the task should retry. - * This function isn't used for interval type tasks, those retry at the next interval. + * This function isn't used for recurring tasks, those retry as per their configured recurring schedule. */ getRetry?: (attempts: number, error: object) => boolean | Date; @@ -176,6 +176,13 @@ export enum TaskLifecycleResult { export type TaskLifecycle = TaskStatus | TaskLifecycleResult; +export interface IntervalSchedule { + /** + * An interval in minutes (e.g. '5m'). If specified, this is a recurring task. + * */ + interval: string; +} + /* * A task instance represents all of the data required to store, fetch, * and execute a task. @@ -220,9 +227,11 @@ export interface TaskInstance { runAt?: Date; /** - * An interval in minutes (e.g. '5m'). If specified, this is a recurring task. + * A TaskSchedule string, which specifies this as a recurring task. + * + * Currently, this supports a single format: an interval in minutes or seconds (e.g. '5m', '30s'). */ - interval?: string; + schedule?: IntervalSchedule; /** * A task-specific set of parameters, used by the task's run function to tailor @@ -254,6 +263,18 @@ export interface TaskInstance { ownerId?: string | null; } +/** + * Support for the depracated interval field, this should be removed in version 8.0.0 + * and marked as a breaking change, ideally nutil then all usage of `interval` will be + * replaced with use of `schedule` + */ +export interface TaskInstanceWithDeprecatedFields extends TaskInstance { + /** + * An interval in minutes (e.g. '5m'). If specified, this is a recurring task. + * */ + interval?: string; +} + /** * A task instance that has an id. */ diff --git a/x-pack/legacy/plugins/task_manager/task_manager.test.ts b/x-pack/legacy/plugins/task_manager/task_manager.test.ts index 588dbe8b6d19c8..e70ee108f275ca 100644 --- a/x-pack/legacy/plugins/task_manager/task_manager.test.ts +++ b/x-pack/legacy/plugins/task_manager/task_manager.test.ts @@ -491,7 +491,7 @@ describe('TaskManager', () => { conflicts: 'proceed', }, body: - '{"query":{"bool":{"must":[{"term":{"type":"task"}},{"bool":{"must":[{"bool":{"should":[{"bool":{"must":[{"term":{"task.status":"idle"}},{"range":{"task.runAt":{"lte":"now"}}}]}},{"bool":{"must":[{"bool":{"should":[{"term":{"task.status":"running"}},{"term":{"task.status":"claiming"}}]}},{"range":{"task.retryAt":{"lte":"now"}}}]}}]}},{"bool":{"should":[{"exists":{"field":"task.interval"}},{"bool":{"must":[{"term":{"task.taskType":"vis_telemetry"}},{"range":{"task.attempts":{"lt":3}}}]}},{"bool":{"must":[{"term":{"task.taskType":"lens_telemetry"}},{"range":{"task.attempts":{"lt":3}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.server-log"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.slack"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.email"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.index"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.pagerduty"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.webhook"}},{"range":{"task.attempts":{"lt":1}}}]}}]}}]}}]}},"sort":{"_script":{"type":"number","order":"asc","script":{"lang":"expression","source":"doc[\'task.retryAt\'].value || doc[\'task.runAt\'].value"}}},"seq_no_primary_term":true,"script":{"source":"ctx._source.task.ownerId=params.ownerId; ctx._source.task.status=params.status; ctx._source.task.retryAt=params.retryAt;","lang":"painless","params":{"ownerId":"kibana:5b2de169-2785-441b-ae8c-186a1936b17d","retryAt":"2019-10-31T13:35:43.579Z","status":"claiming"}}}', + '{"query":{"bool":{"must":[{"term":{"type":"task"}},{"bool":{"must":[{"bool":{"should":[{"bool":{"must":[{"term":{"task.status":"idle"}},{"range":{"task.runAt":{"lte":"now"}}}]}},{"bool":{"must":[{"bool":{"should":[{"term":{"task.status":"running"}},{"term":{"task.status":"claiming"}}]}},{"range":{"task.retryAt":{"lte":"now"}}}]}}]}},{"bool":{"should":[{"exists":{"field":"task.schedule"}},{"bool":{"must":[{"term":{"task.taskType":"vis_telemetry"}},{"range":{"task.attempts":{"lt":3}}}]}},{"bool":{"must":[{"term":{"task.taskType":"lens_telemetry"}},{"range":{"task.attempts":{"lt":3}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.server-log"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.slack"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.email"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.index"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.pagerduty"}},{"range":{"task.attempts":{"lt":1}}}]}},{"bool":{"must":[{"term":{"task.taskType":"actions:.webhook"}},{"range":{"task.attempts":{"lt":1}}}]}}]}}]}}]}},"sort":{"_script":{"type":"number","order":"asc","script":{"lang":"expression","source":"doc[\'task.retryAt\'].value || doc[\'task.runAt\'].value"}}},"seq_no_primary_term":true,"script":{"source":"ctx._source.task.ownerId=params.ownerId; ctx._source.task.status=params.status; ctx._source.task.retryAt=params.retryAt;","lang":"painless","params":{"ownerId":"kibana:5b2de169-2785-441b-ae8c-186a1936b17d","retryAt":"2019-10-31T13:35:43.579Z","status":"claiming"}}}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"cannot execute [inline] scripts"}],"type":"search_phase_execution_exception","reason":"all shards failed","phase":"query","grouped":true,"failed_shards":[{"shard":0,"index":".kibana_task_manager_1","node":"24A4QbjHSK6prvtopAKLKw","reason":{"type":"illegal_argument_exception","reason":"cannot execute [inline] scripts"}}],"caused_by":{"type":"illegal_argument_exception","reason":"cannot execute [inline] scripts","caused_by":{"type":"illegal_argument_exception","reason":"cannot execute [inline] scripts"}}},"status":400}', diff --git a/x-pack/legacy/plugins/task_manager/task_manager.ts b/x-pack/legacy/plugins/task_manager/task_manager.ts index 20563f0daa9b77..b7abeb248d1435 100644 --- a/x-pack/legacy/plugins/task_manager/task_manager.ts +++ b/x-pack/legacy/plugins/task_manager/task_manager.ts @@ -37,7 +37,7 @@ import { ConcreteTaskInstance, RunContext, TaskInstanceWithId, - TaskInstance, + TaskInstanceWithDeprecatedFields, TaskLifecycle, TaskLifecycleResult, TaskStatus, @@ -53,6 +53,7 @@ import { ClaimOwnershipResult, } from './task_store'; import { identifyEsError } from './lib/identify_es_error'; +import { ensureDeprecatedFieldsAreCorrected } from './lib/correct_deprecated_fields'; const VERSION_CONFLICT_STATUS = 409; @@ -267,11 +268,14 @@ export class TaskManager { * @param task - The task being scheduled. * @returns {Promise} */ - public async schedule(taskInstance: TaskInstance, options?: any): Promise { + public async schedule( + taskInstance: TaskInstanceWithDeprecatedFields, + options?: any + ): Promise { await this.waitUntilStarted(); const { taskInstance: modifiedTask } = await this.middleware.beforeSave({ ...options, - taskInstance, + taskInstance: ensureDeprecatedFieldsAreCorrected(taskInstance, this.logger), }); const result = await this.store.schedule(modifiedTask); this.attemptToRun(); diff --git a/x-pack/legacy/plugins/task_manager/task_runner.test.ts b/x-pack/legacy/plugins/task_manager/task_runner.test.ts index c45077c963862d..f3f9b9a88c68ca 100644 --- a/x-pack/legacy/plugins/task_manager/task_runner.test.ts +++ b/x-pack/legacy/plugins/task_manager/task_runner.test.ts @@ -89,10 +89,10 @@ describe('TaskManagerRunner', () => { expect(instance.state).toEqual({ hey: 'there' }); }); - test('reschedules tasks that have an interval', async () => { + test('reschedules tasks that have an schedule', async () => { const { runner, store } = testOpts({ instance: { - interval: '10m', + schedule: { interval: '10m' }, status: TaskStatus.Running, startedAt: new Date(), }, @@ -136,11 +136,11 @@ describe('TaskManagerRunner', () => { sinon.assert.calledWithMatch(store.update, { runAt }); }); - test('tasks that return runAt override interval', async () => { + test('tasks that return runAt override the schedule', async () => { const runAt = minutesFromNow(_.random(5)); const { runner, store } = testOpts({ instance: { - interval: '20m', + schedule: { interval: '20m' }, }, definitions: { bar: { @@ -164,7 +164,7 @@ describe('TaskManagerRunner', () => { const { runner, store } = testOpts({ instance: { id, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -240,7 +240,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -369,7 +369,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: '1m', + schedule: { interval: '1m' }, startedAt: new Date(), }, definitions: { @@ -405,7 +405,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -439,7 +439,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -471,7 +471,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -506,7 +506,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -541,7 +541,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -573,7 +573,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: '1m', + schedule: { interval: '1m' }, startedAt: new Date(), }, definitions: { @@ -604,7 +604,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: undefined, + schedule: undefined, }, definitions: { bar: { @@ -636,7 +636,7 @@ describe('TaskManagerRunner', () => { instance: { id, attempts: initialAttempts, - interval: `${intervalSeconds}s`, + schedule: { interval: `${intervalSeconds}s` }, startedAt: new Date(), }, definitions: { @@ -752,7 +752,7 @@ describe('TaskManagerRunner', () => { onTaskEvent, instance: { id, - interval: '1m', + schedule: { interval: '1m' }, }, definitions: { bar: { @@ -803,7 +803,7 @@ describe('TaskManagerRunner', () => { onTaskEvent, instance: { id, - interval: '1m', + schedule: { interval: '1m' }, startedAt: new Date(), }, definitions: { diff --git a/x-pack/legacy/plugins/task_manager/task_runner.ts b/x-pack/legacy/plugins/task_manager/task_runner.ts index 4384f1cbbf5c02..56ab49bdc629ea 100644 --- a/x-pack/legacy/plugins/task_manager/task_runner.ts +++ b/x-pack/legacy/plugins/task_manager/task_runner.ts @@ -205,7 +205,7 @@ export class TaskManagerRunner implements TaskRunner { status: TaskStatus.Running, startedAt: now, attempts, - retryAt: this.instance.interval + retryAt: this.instance.schedule ? intervalFromNow(this.definition.timeout)! : this.getRetryDelay({ attempts, @@ -273,7 +273,7 @@ export class TaskManagerRunner implements TaskRunner { } private shouldTryToScheduleRetry(): boolean { - if (this.instance.interval) { + if (this.instance.schedule) { return true; } @@ -287,8 +287,8 @@ export class TaskManagerRunner implements TaskRunner { if (this.shouldTryToScheduleRetry()) { const { runAt, state, error } = failureResult; // if we're retrying, keep the number of attempts - const { interval, attempts } = this.instance; - if (runAt || interval) { + const { schedule, attempts } = this.instance; + if (runAt || schedule) { return asOk({ state, attempts, runAt }); } else { // when result.error is truthy, then we're retrying because it failed @@ -312,10 +312,9 @@ export class TaskManagerRunner implements TaskRunner { const fieldUpdates = flow( // if running the task has failed ,try to correct by scheduling a retry in the near future mapErr(this.rescheduleFailedRun), - // if retrying is possible (new runAt) or this is simply an interval - // based task - reschedule + // if retrying is possible (new runAt) or this is an recurring task - reschedule mapOk(({ runAt, state, attempts = 0 }: Partial) => { - const { startedAt, interval } = this.instance; + const { startedAt, schedule: { interval = undefined } = {} } = this.instance; return asOk({ runAt: runAt || intervalFromDate(startedAt!, interval)!, state, @@ -359,7 +358,7 @@ export class TaskManagerRunner implements TaskRunner { await eitherAsync( result, async ({ runAt }: SuccessfulRunResult) => { - if (runAt || this.instance.interval) { + if (runAt || this.instance.schedule) { await this.processResultForRecurringTask(result); } else { await this.processResultWhenDone(); diff --git a/x-pack/legacy/plugins/task_manager/task_store.test.ts b/x-pack/legacy/plugins/task_manager/task_store.test.ts index b8c8ad154f1c34..bbce3143e80119 100644 --- a/x-pack/legacy/plugins/task_manager/task_store.test.ts +++ b/x-pack/legacy/plugins/task_manager/task_store.test.ts @@ -103,7 +103,7 @@ describe('TaskStore', () => { 'task', { attempts: 0, - interval: undefined, + schedule: undefined, params: '{"hello":"world"}', retryAt: null, runAt: '2019-02-12T21:01:22.479Z', @@ -124,7 +124,7 @@ describe('TaskStore', () => { expect(result).toEqual({ id: 'testid', attempts: 0, - interval: undefined, + schedule: undefined, params: { hello: 'world' }, retryAt: null, runAt: mockedDate, @@ -276,7 +276,7 @@ describe('TaskStore', () => { task: { runAt, taskType: 'foo', - interval: undefined, + schedule: undefined, attempts: 0, status: 'idle', params: '{ "hello": "world" }', @@ -294,7 +294,7 @@ describe('TaskStore', () => { task: { runAt, taskType: 'bar', - interval: '5m', + schedule: { interval: '5m' }, attempts: 2, status: 'running', params: '{ "shazm": 1 }', @@ -312,7 +312,7 @@ describe('TaskStore', () => { { attempts: 0, id: 'aaa', - interval: undefined, + schedule: undefined, params: { hello: 'world' }, runAt, scheduledAt: mockedDate, @@ -327,7 +327,7 @@ describe('TaskStore', () => { { attempts: 2, id: 'bbb', - interval: '5m', + schedule: { interval: '5m' }, params: { shazm: 1 }, runAt, scheduledAt: mockedDate, @@ -481,7 +481,7 @@ describe('TaskStore', () => { { bool: { should: [ - { exists: { field: 'task.interval' } }, + { exists: { field: 'task.schedule' } }, { bool: { must: [ @@ -599,7 +599,7 @@ describe('TaskStore', () => { { bool: { should: [ - { exists: { field: 'task.interval' } }, + { exists: { field: 'task.schedule' } }, { bool: { must: [ @@ -734,7 +734,7 @@ if (doc['task.runAt'].size()!=0) { task: { runAt, taskType: 'foo', - interval: undefined, + schedule: undefined, attempts: 0, status: 'idle', params: '{ "hello": "world" }', @@ -755,7 +755,7 @@ if (doc['task.runAt'].size()!=0) { task: { runAt, taskType: 'bar', - interval: '5m', + schedule: { interval: '5m' }, attempts: 2, status: 'running', params: '{ "shazm": 1 }', @@ -805,7 +805,7 @@ if (doc['task.runAt'].size()!=0) { { attempts: 0, id: 'aaa', - interval: undefined, + schedule: undefined, params: { hello: 'world' }, runAt, scope: ['reporting'], @@ -818,7 +818,7 @@ if (doc['task.runAt'].size()!=0) { { attempts: 2, id: 'bbb', - interval: '5m', + schedule: { interval: '5m' }, params: { shazm: 1 }, runAt, scope: ['reporting', 'ceo'], @@ -878,7 +878,7 @@ if (doc['task.runAt'].size()!=0) { task.id, { attempts: task.attempts, - interval: undefined, + schedule: undefined, params: JSON.stringify(task.params), retryAt: null, runAt: task.runAt.toISOString(), @@ -896,7 +896,7 @@ if (doc['task.runAt'].size()!=0) { expect(result).toEqual({ ...task, - interval: undefined, + schedule: undefined, retryAt: null, scope: undefined, startedAt: null, @@ -1074,7 +1074,7 @@ if (doc['task.runAt'].size()!=0) { task: { runAt, taskType: 'foo', - interval: undefined, + schedule: undefined, attempts: 0, status: 'idle', params: '{ "hello": "world" }', @@ -1098,7 +1098,7 @@ if (doc['task.runAt'].size()!=0) { task: { runAt, taskType: 'bar', - interval: '5m', + schedule: { interval: '5m' }, attempts: 2, status: 'running', params: '{ "shazm": 1 }', @@ -1151,7 +1151,7 @@ if (doc['task.runAt'].size()!=0) { id: 'aaa', runAt, taskType: 'foo', - interval: undefined, + schedule: undefined, attempts: 0, status: 'idle' as TaskStatus, params: { hello: 'world' }, @@ -1208,7 +1208,7 @@ if (doc['task.runAt'].size()!=0) { id: 'bbb', runAt, taskType: 'bar', - interval: '5m', + schedule: { interval: '5m' }, attempts: 2, status: 'running' as TaskStatus, params: { shazm: 1 }, diff --git a/x-pack/legacy/plugins/task_manager/task_store.ts b/x-pack/legacy/plugins/task_manager/task_store.ts index 727587f714a14b..096a8774c8488b 100644 --- a/x-pack/legacy/plugins/task_manager/task_store.ts +++ b/x-pack/legacy/plugins/task_manager/task_store.ts @@ -50,7 +50,7 @@ import { updateFields, IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt, - RecuringTaskWithInterval, + TaskWithSchedule, taskWithLessThanMaxAttempts, SortByRunAtAndRetryAt, taskWithIDsAndRunnableStatus, @@ -249,9 +249,9 @@ export class TaskStore { // Either a task with idle status and runAt <= now or // status running or claiming with a retryAt <= now. shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt), - // Either task has an interval or the attempts < the maximum configured + // Either task has a schedule or the attempts < the maximum configured shouldBeOneOf( - RecuringTaskWithInterval, + TaskWithSchedule, ...Object.entries(this.definitions).map(([type, { maxAttempts }]) => taskWithLessThanMaxAttempts(type, maxAttempts || this.maxAttempts) ) diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js b/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js index 5a45f2a58eac46..3330d08dfd0d2b 100644 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js +++ b/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js @@ -34,6 +34,9 @@ export function initRoutes(server, taskTestingEvents) { payload: Joi.object({ task: Joi.object({ taskType: Joi.string().required(), + schedule: Joi.object({ + interval: Joi.string(), + }).optional(), interval: Joi.string().optional(), params: Joi.object().required(), state: Joi.object().optional(), @@ -91,7 +94,6 @@ export function initRoutes(server, taskTestingEvents) { payload: Joi.object({ task: Joi.object({ taskType: Joi.string().required(), - interval: Joi.string().optional(), params: Joi.object().required(), state: Joi.object().optional(), id: Joi.string().optional(), diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js index 3c7ca375ff27e5..486a93aba76dfc 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js @@ -123,7 +123,7 @@ export default function({ getService }) { const scheduledTask = await scheduleTask({ taskType: 'sampleTask', - interval: '30m', + schedule: { interval: '30m' }, params: { historyItem }, }); log.debug(`Task created: ${scheduledTask.id}`); @@ -228,6 +228,27 @@ export default function({ getService }) { const interval = _.random(5, 200); const intervalMilliseconds = interval * 60000; + const originalTask = await scheduleTask({ + taskType: 'sampleTask', + schedule: { interval: `${interval}m` }, + params: {}, + }); + + await retry.try(async () => { + expect((await historyDocs()).length).to.eql(1); + + const [task] = (await currentTasks()).docs; + expect(task.attempts).to.eql(0); + expect(task.state.count).to.eql(1); + + expectReschedule(Date.parse(originalTask.runAt), task, intervalMilliseconds); + }); + }); + + it('should support the deprecated interval field', async () => { + const interval = _.random(5, 200); + const intervalMilliseconds = interval * 60000; + const originalTask = await scheduleTask({ taskType: 'sampleTask', interval: `${interval}m`, @@ -248,7 +269,7 @@ export default function({ getService }) { it('should return a task run result when asked to run a task now', async () => { const originalTask = await scheduleTask({ taskType: 'sampleTask', - interval: `30m`, + schedule: { interval: `30m` }, params: {}, }); @@ -291,7 +312,7 @@ export default function({ getService }) { it('should return a task run error result when running a task now fails', async () => { const originalTask = await scheduleTask({ taskType: 'sampleTask', - interval: `30m`, + schedule: { interval: `30m` }, params: { failWith: 'error on run now', failOn: 3 }, }); @@ -355,7 +376,7 @@ export default function({ getService }) { it('should return a task run error result when trying to run a task now which is already running', async () => { const longRunningTask = await scheduleTask({ taskType: 'sampleTask', - interval: '30m', + schedule: { interval: '30m' }, params: { waitForParams: true, }, @@ -447,13 +468,13 @@ export default function({ getService }) { */ const fastTask = await scheduleTask({ taskType: 'sampleTask', - interval: `1s`, + schedule: { interval: `1s` }, params: {}, }); const longRunningTask = await scheduleTask({ taskType: 'sampleTask', - interval: `1s`, + schedule: { interval: `1s` }, params: { waitForEvent: 'rescheduleHasHappened', }, From d391764b76f57439be7493d741c3f55349ebe7d6 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Tue, 17 Dec 2019 12:01:30 -0600 Subject: [PATCH 09/60] [APM] License prompt for service map (#52668) Display a link to platinum license upgrade on the service map. Also add `useKibanaUrl` and `useLicense` hooks. Make the `LicenseContext` (which is used in a couple class components and on page load) use the license observable from the NP plugin. Add missing export of `useObservable` to kibana_react. --- src/plugins/kibana_react/public/index.ts | 2 +- .../ServiceIntegrations/index.tsx | 4 +- .../app/ServiceMap/PlatinumLicensePrompt.tsx | 66 +++++++++++++++++++ .../components/app/ServiceMap/index.tsx | 15 +++-- .../shared/charts/TransactionCharts/index.tsx | 2 +- .../public/context/LicenseContext/index.tsx | 34 ++++------ .../plugins/apm/public/hooks/useKibanaUrl.ts | 19 ++++++ .../plugins/apm/public/hooks/useLicense.ts | 12 ++++ .../apm/public/new-platform/plugin.tsx | 32 ++++----- .../plugins/apm/public/services/rest/xpack.ts | 45 ------------- 10 files changed, 144 insertions(+), 87 deletions(-) create mode 100644 x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx create mode 100644 x-pack/legacy/plugins/apm/public/hooks/useKibanaUrl.ts create mode 100644 x-pack/legacy/plugins/apm/public/hooks/useLicense.ts delete mode 100644 x-pack/legacy/plugins/apm/public/services/rest/xpack.ts diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts index 81ef707ed0eba3..258b0e94ef9558 100644 --- a/src/plugins/kibana_react/public/index.ts +++ b/src/plugins/kibana_react/public/index.ts @@ -25,4 +25,4 @@ export * from './overlays'; export * from './ui_settings'; export * from './field_icon'; export * from './table_list_view'; -export { toMountPoint, useShallowCompareEffect } from './util'; +export { toMountPoint, useObservable, useShallowCompareEffect } from './util'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx index 4158bb877e4595..91483b4b52d90e 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx @@ -148,7 +148,9 @@ export class ServiceIntegrations extends React.Component { panels={[ { id: 0, - items: this.getPanelItems(license.features.ml?.is_available) + items: this.getPanelItems( + license?.getFeature('ml').isAvailable + ) } ]} /> diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx new file mode 100644 index 00000000000000..c5771995daa24e --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/PlatinumLicensePrompt.tsx @@ -0,0 +1,66 @@ +/* + * 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 React from 'react'; +import { + EuiEmptyPrompt, + EuiButton, + EuiPanel, + EuiFlexGroup, + EuiFlexItem +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useKibanaUrl } from '../../../hooks/useKibanaUrl'; + +export function PlatinumLicensePrompt() { + // Set the height to give it some top margin + const style = { height: '60vh' }; + + const licensePageUrl = useKibanaUrl( + '/app/kibana', + '/management/elasticsearch/license_management/home' + ); + + return ( + + + + + {i18n.translate( + 'xpack.apm.serviceMap.licensePromptButtonText', + { + defaultMessage: 'Start 30-day Platinum trial' + } + )} + + ]} + body={ +

+ {i18n.translate('xpack.apm.serviceMap.licensePromptBody', { + defaultMessage: + "In order to access Service Maps, you must be subscribed to an Elastic Platinum license. With it, you'll have the ability to visualize your entire application stack along with your APM data." + })} +

+ } + title={ +

+ {i18n.translate('xpack.apm.serviceMap.licensePromptTitle', { + defaultMessage: 'Service maps is available in Platinum.' + })} +

+ } + /> +
+
+
+ ); +} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx index 9b0668028c42f1..16a91116ae762b 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx @@ -4,12 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; import theme from '@elastic/eui/dist/eui_theme_light.json'; -import { useUrlParams } from '../../../hooks/useUrlParams'; +import React from 'react'; import { useFetcher } from '../../../hooks/useFetcher'; -import { Cytoscape } from './Cytoscape'; +import { useLicense } from '../../../hooks/useLicense'; +import { useUrlParams } from '../../../hooks/useUrlParams'; import { Controls } from './Controls'; +import { Cytoscape } from './Cytoscape'; +import { PlatinumLicensePrompt } from './PlatinumLicensePrompt'; interface ServiceMapProps { serviceName?: string; @@ -53,8 +55,11 @@ export function ServiceMap({ serviceName }: ServiceMapProps) { ); const elements = Array.isArray(data) ? data : []; + const license = useLicense(); + const isValidPlatinumLicense = + license?.isActive && license?.type === 'platinum'; - return ( + return isValidPlatinumLicense ? ( + ) : ( + ); } diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx index 97794bf66687b5..b0555da705a30e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx @@ -170,7 +170,7 @@ export class TransactionCharts extends Component { {license => - this.renderMLHeader(license.features.ml?.is_available) + this.renderMLHeader(license?.getFeature('ml').isAvailable) } diff --git a/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx b/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx index 4bb246a2a745ba..714e4c89856787 100644 --- a/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx +++ b/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx @@ -3,33 +3,27 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import React from 'react'; -import { FETCH_STATUS, useFetcher } from '../../hooks/useFetcher'; -import { loadLicense, LicenseApiResponse } from '../../services/rest/xpack'; -import { InvalidLicenseNotification } from './InvalidLicenseNotification'; +import { useObservable } from '../../../../../../../src/plugins/kibana_react/public'; +import { ILicense } from '../../../../../../plugins/licensing/public'; import { useApmPluginContext } from '../../hooks/useApmPluginContext'; +import { InvalidLicenseNotification } from './InvalidLicenseNotification'; -const initialLicense: LicenseApiResponse = { - features: {}, - license: { - is_active: false - } -}; -export const LicenseContext = React.createContext(initialLicense); +export const LicenseContext = React.createContext( + undefined +); -export const LicenseProvider: React.FC = ({ children }) => { - const { http } = useApmPluginContext().core; - const { data = initialLicense, status } = useFetcher( - () => loadLicense(http), - [http] - ); - const hasValidLicense = data.license.is_active; +export function LicenseProvider({ children }: { children: React.ReactChild }) { + const { license$ } = useApmPluginContext().plugins.licensing; + const license = useObservable(license$); + const hasInvalidLicense = !license?.isActive; // if license is invalid show an error message - if (status === FETCH_STATUS.SUCCESS && !hasValidLicense) { + if (hasInvalidLicense) { return ; } // render rest of application and pass down license via context - return ; -}; + return ; +} diff --git a/x-pack/legacy/plugins/apm/public/hooks/useKibanaUrl.ts b/x-pack/legacy/plugins/apm/public/hooks/useKibanaUrl.ts new file mode 100644 index 00000000000000..0b1c416040a2f1 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/hooks/useKibanaUrl.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 url from 'url'; +import { useApmPluginContext } from './useApmPluginContext'; + +export function useKibanaUrl( + /** The path to the plugin */ path: string, + /** The hash path */ hash: string +) { + const { core } = useApmPluginContext(); + return url.format({ + pathname: core.http.basePath.prepend(path), + hash + }); +} diff --git a/x-pack/legacy/plugins/apm/public/hooks/useLicense.ts b/x-pack/legacy/plugins/apm/public/hooks/useLicense.ts new file mode 100644 index 00000000000000..ca828e49706a82 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/hooks/useLicense.ts @@ -0,0 +1,12 @@ +/* + * 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 { useContext } from 'react'; +import { LicenseContext } from '../context/LicenseContext'; + +export function useLicense() { + return useContext(LicenseContext); +} diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx index 64784617442efa..002f6af7fe6cc2 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -6,35 +6,36 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { Router, Route, Switch } from 'react-router-dom'; +import { Route, Router, Switch } from 'react-router-dom'; import styled from 'styled-components'; import { metadata } from 'ui/metadata'; -import { HomePublicPluginSetup } from '../../../../../../src/plugins/home/public'; import { + CoreSetup, CoreStart, + PackageInfo, Plugin, - CoreSetup, - PluginInitializerContext, - PackageInfo + PluginInitializerContext } from '../../../../../../src/core/public'; import { DataPublicPluginSetup } from '../../../../../../src/plugins/data/public'; -import { history } from '../utils/history'; -import { LocationProvider } from '../context/LocationContext'; -import { UrlParamsProvider } from '../context/UrlParamsContext'; -import { px, unit, units } from '../style/variables'; -import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; -import { LicenseProvider } from '../context/LicenseContext'; -import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; +import { HomePublicPluginSetup } from '../../../../../../src/plugins/home/public'; +import { LicensingPluginSetup } from '../../../../../plugins/licensing/public'; import { routes } from '../components/app/Main/route_config'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; +import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; +import { ApmPluginContext } from '../context/ApmPluginContext'; +import { LicenseProvider } from '../context/LicenseContext'; +import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; +import { LocationProvider } from '../context/LocationContext'; import { MatchedRouteProvider } from '../context/MatchedRouteContext'; +import { UrlParamsProvider } from '../context/UrlParamsContext'; import { createStaticIndexPattern } from '../services/rest/index_pattern'; -import { setHelpExtension } from './setHelpExtension'; -import { setReadonlyBadge } from './updateBadge'; +import { px, unit, units } from '../style/variables'; +import { history } from '../utils/history'; import { featureCatalogueEntry } from './featureCatalogueEntry'; import { getConfigFromInjectedMetadata } from './getConfigFromInjectedMetadata'; +import { setHelpExtension } from './setHelpExtension'; import { toggleAppLinkInNav } from './toggleAppLinkInNav'; -import { ApmPluginContext } from '../context/ApmPluginContext'; +import { setReadonlyBadge } from './updateBadge'; export const REACT_APP_ROOT_ID = 'react-apm-root'; @@ -64,6 +65,7 @@ export type ApmPluginStart = void; export interface ApmPluginSetupDeps { data: DataPublicPluginSetup; home: HomePublicPluginSetup; + licensing: LicensingPluginSetup; } export interface ConfigSchema { diff --git a/x-pack/legacy/plugins/apm/public/services/rest/xpack.ts b/x-pack/legacy/plugins/apm/public/services/rest/xpack.ts deleted file mode 100644 index 95e283cd67709d..00000000000000 --- a/x-pack/legacy/plugins/apm/public/services/rest/xpack.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 { HttpServiceBase } from 'kibana/public'; -import { callApi } from './callApi'; - -export interface LicenseApiResponse { - license: { - is_active: boolean; - }; - features: { - beats_management?: Record; - graph?: Record; - grokdebugger?: Record; - index_management?: Record; - logstash?: Record; - ml?: { - is_available: boolean; - license_type: number; - has_expired: boolean; - enable_links: boolean; - show_links: boolean; - }; - reporting?: Record; - rollup?: Record; - searchprofiler?: Record; - security?: Record; - spaces?: Record; - tilemap?: Record; - watcher?: { - is_available: boolean; - enable_links: boolean; - show_links: boolean; - }; - }; -} - -export async function loadLicense(http: HttpServiceBase) { - return callApi(http, { - pathname: `/api/xpack/v1/info` - }); -} From 28e05e79ecb735f379cdb6299bd7abee492391bf Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Tue, 17 Dec 2019 13:09:26 -0500 Subject: [PATCH 10/60] [SIEM] [Detection Engine] adds created_at and updated_at timestamps to rules (#53137) * adds created_at and updated_at timestamps to rules * fix missing update to tests * save created_at and updated_at in rule in signals index * requires created_at and updated_at in rule --- .../routes/__mocks__/request_responses.ts | 2 ++ .../routes/rules/create_rules_route.ts | 4 ++++ .../routes/rules/utils.test.ts | 20 +++++++++++++++++++ .../detection_engine/routes/rules/utils.ts | 2 ++ .../detection_engine/rules/create_rules.ts | 2 ++ .../detection_engine/rules/update_rules.ts | 1 + .../signals/__mocks__/es_results.ts | 2 ++ .../signals/build_bulk_body.test.ts | 8 ++++++++ .../signals/build_rule.test.ts | 6 ++++++ .../detection_engine/signals/build_rule.ts | 2 ++ .../signals/build_signal.test.ts | 4 ++++ .../signals/signal_rule_alert_type.ts | 2 ++ .../siem/server/lib/detection_engine/types.ts | 13 +++++++++++- 13 files changed, 67 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index d9dd7bb1ff7d0e..6358a9b89c2a41 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -175,6 +175,8 @@ export const getResult = (): RuleAlertType => ({ tags: [`${INTERNAL_RULE_ID_KEY}:rule-1`], alertTypeId: 'siem.signals', params: { + createdAt: '2019-12-13T16:40:33.400Z', + updatedAt: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', ruleId: 'rule-1', index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts index 0dc213e9e2173f..8780a0c1c9d873 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -33,6 +33,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute = }, async handler(request: RulesRequest, headers) { const { + created_at: createdAt, description, enabled, false_positives: falsePositives, @@ -55,6 +56,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute = threats, to, type, + updated_at: updatedAt, references, } = request.payload; const alertsClient = isFunction(request.getAlertsClient) ? request.getAlertsClient() : null; @@ -87,6 +89,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute = const createdRule = await createRules({ alertsClient, actionsClient, + createdAt, description, enabled, falsePositives, @@ -109,6 +112,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute = to, type, threats, + updatedAt, references, }); return transformOrError(createdRule); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index a2312ce25e72a9..d92c35e5ca0b22 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -23,6 +23,8 @@ describe('utils', () => { const rule = transformAlertToRule(fullRule); expect(rule).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: true, false_positives: [], @@ -69,6 +71,8 @@ describe('utils', () => { const { from, language, ...omitData } = transformAlertToRule(fullRule); expect(omitData).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: true, false_positives: [], @@ -114,6 +118,8 @@ describe('utils', () => { const rule = transformAlertToRule(fullRule); expect(rule).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: true, false_positives: [], @@ -160,6 +166,8 @@ describe('utils', () => { const rule = transformAlertToRule(fullRule); expect(rule).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: true, false_positives: [], @@ -207,6 +215,8 @@ describe('utils', () => { const { from, enabled, ...omitData } = transformAlertToRule(fullRule); expect(omitData).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', false_positives: [], id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', @@ -250,6 +260,8 @@ describe('utils', () => { const ruleWithEnabledFalse = transformAlertToRule(fullRule); expect(ruleWithEnabledFalse).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: false, from: 'now-6m', @@ -297,6 +309,8 @@ describe('utils', () => { const ruleWithEnabledFalse = transformAlertToRule(fullRule); expect(ruleWithEnabledFalse).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: true, from: 'now-6m', @@ -343,6 +357,8 @@ describe('utils', () => { fullRule.tags = ['tag 1', 'tag 2', `${INTERNAL_IDENTIFIER}_some_other_value`]; const rule = transformAlertToRule(fullRule); expect(rule).toEqual({ + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', description: 'Detecting root and admin users', enabled: true, @@ -442,6 +458,8 @@ describe('utils', () => { data: [ { created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: true, false_positives: [], @@ -496,6 +514,8 @@ describe('utils', () => { const output = transformOrError(getResult()); expect(output).toEqual({ created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', description: 'Detecting root and admin users', enabled: true, false_positives: [], diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index ff06b63a034b89..fce709d1174351 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -34,6 +34,8 @@ export const transformTags = (tags: string[]): string[] => { // those on the export export const transformAlertToRule = (alert: RuleAlertType): Partial => { return pickBy((value: unknown) => value != null, { + created_at: alert.params.createdAt, + updated_at: alert.params.updatedAt, created_by: alert.createdBy, description: alert.params.description, enabled: alert.enabled, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index c4c31190e1e83e..fbdc56dec1a696 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -41,6 +41,7 @@ export const createRules = async ({ tags: addRuleIdToTags(tags, ruleId), alertTypeId: SIGNALS_ID, params: { + createdAt: new Date().toISOString(), description, ruleId, index, @@ -59,6 +60,7 @@ export const createRules = async ({ threats, to, type, + updatedAt: new Date().toISOString(), references, }, interval, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index b37e9f6cb8538f..12df579ee4c546 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -103,6 +103,7 @@ export const updateRules = async ({ threats, to, type, + updatedAt: new Date().toISOString(), references, } ); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index 47a4dafa2d17f6..dde8cc4739e518 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -32,6 +32,8 @@ export const sampleRuleAlertParams = ( savedId: undefined, meta: undefined, threats: undefined, + updatedAt: '2019-12-17T15:04:25.343Z', + createdAt: '2019-12-17T15:04:37.105Z', }); export const sampleDocNoSortId = (someUuid: string = sampleIdGuid): SignalSourceHit => ({ diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts index e10158a0b879ef..7d08d6c1d73f02 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -69,6 +69,8 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + created_at: fakeSignalSourceHit.signal.rule?.created_at, + updated_at: fakeSignalSourceHit.signal.rule?.updated_at, }, }, }); @@ -142,6 +144,8 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + created_at: fakeSignalSourceHit.signal.rule?.created_at, + updated_at: fakeSignalSourceHit.signal.rule?.updated_at, }, }, }); @@ -213,6 +217,8 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + created_at: fakeSignalSourceHit.signal.rule?.created_at, + updated_at: fakeSignalSourceHit.signal.rule?.updated_at, }, }, }); @@ -277,6 +283,8 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + updated_at: fakeSignalSourceHit.signal.rule?.updated_at, + created_at: fakeSignalSourceHit.signal.rule?.created_at, }, }, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts index c12c6fd333f560..e5214640232840 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts @@ -59,6 +59,8 @@ describe('buildRule', () => { to: 'now', type: 'query', updated_by: 'elastic', + updated_at: rule.updated_at, + created_at: rule.created_at, filters: [ { query: 'host.name: Rebecca', @@ -110,6 +112,8 @@ describe('buildRule', () => { to: 'now', type: 'query', updated_by: 'elastic', + updated_at: rule.updated_at, + created_at: rule.created_at, }; expect(rule).toEqual(expected); }); @@ -150,6 +154,8 @@ describe('buildRule', () => { to: 'now', type: 'query', updated_by: 'elastic', + updated_at: rule.updated_at, + created_at: rule.created_at, }; expect(rule).toEqual(expected); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts index 64ec989208b6a0..05b1da5fc43bed 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts @@ -55,5 +55,7 @@ export const buildRule = ({ created_by: createdBy, updated_by: updatedBy, threats: ruleParams.threats, + created_at: ruleParams.createdAt, + updated_at: ruleParams.updatedAt, }); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.test.ts index 1c024d0496743b..debc619fbf8b21 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_signal.test.ts @@ -51,6 +51,8 @@ describe('buildSignal', () => { tags: ['some fake tag 1', 'some fake tag 2'], to: 'now', type: 'query', + updated_at: signal.rule.updated_at, + created_at: signal.rule.created_at, }, }; expect(signal).toEqual(expected); @@ -104,6 +106,8 @@ describe('buildSignal', () => { tags: ['some fake tag 1', 'some fake tag 2'], to: 'now', type: 'query', + updated_at: signal.rule.updated_at, + created_at: signal.rule.created_at, }, }; expect(signal).toEqual(expected); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 37467e405dd8e9..03768c41b52dd8 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -31,6 +31,7 @@ export const signalRulesAlertType = ({ actionGroups: ['default'], validate: { params: schema.object({ + createdAt: schema.string(), description: schema.string(), falsePositives: schema.arrayOf(schema.string(), { defaultValue: [] }), from: schema.string(), @@ -49,6 +50,7 @@ export const signalRulesAlertType = ({ threats: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))), to: schema.string(), type: schema.string(), + updatedAt: schema.string(), references: schema.arrayOf(schema.string(), { defaultValue: [] }), }), }, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index bb616554042f4f..f2178390686a10 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -21,6 +21,7 @@ export interface ThreatParams { } export interface RuleAlertParams { + createdAt: string; description: string; enabled: boolean; falsePositives: string[]; @@ -44,13 +45,21 @@ export interface RuleAlertParams { to: string; threats: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; + updatedAt: string; } export type RuleTypeParams = Omit; export type RuleAlertParamsRest = Omit< RuleAlertParams, - 'ruleId' | 'falsePositives' | 'maxSignals' | 'savedId' | 'riskScore' | 'outputIndex' + | 'ruleId' + | 'falsePositives' + | 'maxSignals' + | 'savedId' + | 'riskScore' + | 'outputIndex' + | 'updatedAt' + | 'createdAt' > & { rule_id: RuleAlertParams['ruleId']; false_positives: RuleAlertParams['falsePositives']; @@ -58,6 +67,8 @@ export type RuleAlertParamsRest = Omit< max_signals: RuleAlertParams['maxSignals']; risk_score: RuleAlertParams['riskScore']; output_index: RuleAlertParams['outputIndex']; + created_at: RuleAlertParams['createdAt']; + updated_at: RuleAlertParams['updatedAt']; }; export type OutputRuleAlertRest = RuleAlertParamsRest & { From 8b7aaa4849eabaed3788cf94fc652d71f80feb53 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 10:41:07 -0700 Subject: [PATCH 11/60] Revert "Update webpack related packages (#53082)" This reverts commit 8b36eb46ea4ec68cd5a6c5fc51b2d09fb5851bd3. --- package.json | 18 +- .../package.json | 4 +- packages/kbn-interpreter/package.json | 14 +- packages/kbn-pm/package.json | 4 +- packages/kbn-ui-framework/package.json | 16 +- .../canvas/.storybook/webpack.config.js | 5 +- .../shareable_runtime/webpack.config.js | 7 +- x-pack/package.json | 10 +- yarn.lock | 428 +++++++++--------- 9 files changed, 261 insertions(+), 245 deletions(-) diff --git a/package.json b/package.json index 9ac3c89e14c8e4..ff7feb2464b1d5 100644 --- a/package.json +++ b/package.json @@ -152,12 +152,12 @@ "cache-loader": "^4.1.0", "chalk": "^2.4.2", "check-disk-space": "^2.1.0", - "chokidar": "3.3.0", + "chokidar": "3.2.1", "color": "1.0.3", "commander": "3.0.2", "compare-versions": "3.5.1", "core-js": "^3.5.0", - "css-loader": "3.3.2", + "css-loader": "2.1.1", "custom-event-polyfill": "^0.3.0", "d3": "3.5.17", "d3-cloud": "1.2.5", @@ -170,7 +170,7 @@ "execa": "^3.4.0", "expiry-js": "0.1.7", "fast-deep-equal": "^3.1.1", - "file-loader": "5.0.2", + "file-loader": "4.2.0", "font-awesome": "4.7.0", "getos": "^3.1.1", "glob": "^7.1.2", @@ -221,7 +221,7 @@ "proxy-from-env": "1.0.0", "pug": "^2.0.4", "querystring-browser": "1.0.4", - "raw-loader": "4.0.0", + "raw-loader": "3.1.0", "react": "^16.12.0", "react-color": "^2.13.8", "react-dom": "^16.12.0", @@ -248,10 +248,10 @@ "script-loader": "0.7.2", "semver": "^5.5.0", "style-it": "^2.1.3", - "style-loader": "1.0.1", + "style-loader": "0.23.1", "symbol-observable": "^1.2.0", "tar": "4.4.13", - "terser-webpack-plugin": "^2.3.0", + "terser-webpack-plugin": "^2.1.2", "thread-loader": "^2.1.3", "tinygradient": "0.4.3", "tinymath": "1.2.1", @@ -259,16 +259,16 @@ "tslib": "^1.9.3", "type-detect": "^4.0.8", "ui-select": "0.19.8", - "url-loader": "3.0.0", + "url-loader": "2.2.0", "uuid": "3.3.2", - "val-loader": "^2.0.2", + "val-loader": "^1.1.1", "validate-npm-package-name": "2.2.2", "vega-lib": "4.3.0", "vega-lite": "^2.6.0", "vega-schema-url-parser": "1.0.0", "vega-tooltip": "^0.12.0", "vision": "^5.3.3", - "webpack": "4.41.2", + "webpack": "4.41.0", "webpack-merge": "4.2.2", "whatwg-fetch": "^3.0.0", "wrapper-webpack-plugin": "^2.1.0", diff --git a/packages/kbn-eslint-import-resolver-kibana/package.json b/packages/kbn-eslint-import-resolver-kibana/package.json index e6d185a9b5c3a4..9fae27011767e1 100755 --- a/packages/kbn-eslint-import-resolver-kibana/package.json +++ b/packages/kbn-eslint-import-resolver-kibana/package.json @@ -12,10 +12,10 @@ "dependencies": { "debug": "^2.6.9", "eslint-import-resolver-node": "0.3.2", - "eslint-import-resolver-webpack": "0.12.0", + "eslint-import-resolver-webpack": "0.11.1", "glob-all": "^3.1.0", "lru-cache": "^4.1.5", "resolve": "^1.7.1", - "webpack": "^4.41.2" + "webpack": "^4.41.0" } } diff --git a/packages/kbn-interpreter/package.json b/packages/kbn-interpreter/package.json index 26b8026ed381c2..2e80276f59f91e 100644 --- a/packages/kbn-interpreter/package.json +++ b/packages/kbn-interpreter/package.json @@ -22,16 +22,16 @@ "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", "babel-loader": "^8.0.6", - "copy-webpack-plugin": "^5.1.1", - "css-loader": "3.3.2", + "copy-webpack-plugin": "^5.0.4", + "css-loader": "2.1.1", "del": "^5.1.0", "getopts": "^2.2.4", "pegjs": "0.10.0", - "sass-loader": "^8.0.0", - "style-loader": "1.0.1", + "sass-loader": "^7.3.1", + "style-loader": "0.23.1", "supports-color": "^7.0.0", - "url-loader": "3.0.0", - "webpack": "4.41.2", - "webpack-cli": "^3.3.10" + "url-loader": "2.2.0", + "webpack": "4.41.0", + "webpack-cli": "^3.3.9" } } diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index 92b495a111b617..e36c078790eccd 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -60,8 +60,8 @@ "tempy": "^0.3.0", "typescript": "3.7.2", "unlazy-loader": "^0.1.3", - "webpack": "^4.41.2", - "webpack-cli": "^3.3.10", + "webpack": "^4.41.0", + "webpack-cli": "^3.3.9", "wrap-ansi": "^3.0.1", "write-pkg": "^4.0.0" }, diff --git a/packages/kbn-ui-framework/package.json b/packages/kbn-ui-framework/package.json index e3a46811684b4f..a4f23dd19da769 100644 --- a/packages/kbn-ui-framework/package.json +++ b/packages/kbn-ui-framework/package.json @@ -37,11 +37,11 @@ "babel-loader": "^8.0.6", "brace": "0.11.1", "chalk": "^2.4.2", - "chokidar": "3.3.0", + "chokidar": "3.2.1", "core-js": "^3.5.0", - "css-loader": "^3.3.2", + "css-loader": "^2.1.1", "expose-loader": "^0.7.5", - "file-loader": "^5.0.2", + "file-loader": "^4.2.0", "grunt": "1.0.4", "grunt-babel": "^8.0.0", "grunt-contrib-clean": "^1.1.0", @@ -56,7 +56,7 @@ "node-sass": "^4.9.4", "postcss": "^7.0.5", "postcss-loader": "^3.0.0", - "raw-loader": "^4.0.0", + "raw-loader": "^3.1.0", "react-dom": "^16.12.0", "react-redux": "^5.1.2", "react-router": "^3.2.0", @@ -64,11 +64,11 @@ "redux": "3.7.2", "redux-thunk": "2.2.0", "regenerator-runtime": "^0.13.3", - "sass-loader": "^8.0.0", + "sass-loader": "^7.3.1", "sinon": "^7.4.2", - "style-loader": "^1.0.1", - "webpack": "^4.41.2", - "webpack-dev-server": "^3.9.0", + "style-loader": "^0.23.1", + "webpack": "^4.41.0", + "webpack-dev-server": "^3.8.2", "yeoman-generator": "1.1.1", "yo": "2.0.6" } diff --git a/x-pack/legacy/plugins/canvas/.storybook/webpack.config.js b/x-pack/legacy/plugins/canvas/.storybook/webpack.config.js index 61dbd07cfc5683..662078585422f3 100644 --- a/x-pack/legacy/plugins/canvas/.storybook/webpack.config.js +++ b/x-pack/legacy/plugins/canvas/.storybook/webpack.config.js @@ -83,9 +83,8 @@ module.exports = async ({ config }) => { loader: 'css-loader', options: { importLoaders: 2, - modules: { - localIdentName: '[name]__[local]___[hash:base64:5]', - }, + modules: true, + localIdentName: '[name]__[local]___[hash:base64:5]', }, }, { diff --git a/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js b/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js index dad5415f6768f3..c711f9510a10b4 100644 --- a/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js +++ b/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js @@ -99,11 +99,10 @@ module.exports = { { loader: 'css-loader', options: { - localsConvention: 'camelCaseOnly', + modules: true, + localIdentName: '[name]__[local]___[hash:base64:5]', + camelCase: true, sourceMap: !isProd, - modules: { - localIdentName: '[name]__[local]___[hash:base64:5]', - }, }, }, { diff --git a/x-pack/package.json b/x-pack/package.json index 00c90153134aa8..ac6d46ba38f425 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -26,7 +26,7 @@ "**/@types/node": "10.12.27" }, "devDependencies": { - "@cypress/webpack-preprocessor": "^4.1.1", + "@cypress/webpack-preprocessor": "^4.1.0", "@kbn/dev-utils": "1.0.0", "@kbn/es": "1.0.0", "@kbn/expect": "1.0.0", @@ -115,7 +115,7 @@ "chance": "1.0.18", "cheerio": "0.22.0", "commander": "3.0.2", - "copy-webpack-plugin": "^5.1.1", + "copy-webpack-plugin": "^5.0.4", "cypress": "^3.6.1", "cypress-multi-reporters": "^1.2.3", "enzyme": "^3.10.0", @@ -155,7 +155,7 @@ "react-docgen-typescript-loader": "^3.1.1", "react-test-renderer": "^16.12.0", "rxjs-marbles": "^5.0.3", - "sass-loader": "^8.0.0", + "sass-loader": "^7.3.1", "sass-resources-loader": "^2.0.1", "simple-git": "1.129.0", "sinon": "^7.4.2", @@ -290,7 +290,7 @@ "proper-lockfile": "^3.2.0", "puid": "1.0.7", "puppeteer-core": "^1.19.0", - "raw-loader": "4.0.0", + "raw-loader": "3.1.0", "react": "^16.12.0", "react-apollo": "^2.1.4", "react-beautiful-dnd": "^8.0.7", @@ -340,7 +340,7 @@ "uuid": "3.3.2", "venn.js": "0.2.20", "vscode-languageserver": "^5.2.1", - "webpack": "4.41.2", + "webpack": "4.33.0", "wellknown": "^0.5.0", "xml2js": "^0.4.22", "xregexp": "4.2.4" diff --git a/yarn.lock b/yarn.lock index 2025ceb0142cc4..968adcac381957 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1866,13 +1866,13 @@ date-fns "^1.27.2" figures "^1.7.0" -"@cypress/webpack-preprocessor@^4.1.1": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-4.1.1.tgz#3c0b5b8de6eaac605dac3b1f1c3f5916c1c6eaea" - integrity sha512-SfzDqOvWBSlfGRm8ak/XHUXAnndwHU2qJIRr1LIC7j2UqWcZoJ+286CuNloJbkwfyEAO6tQggLd4E/WHUAcKZQ== +"@cypress/webpack-preprocessor@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-4.1.0.tgz#8c4debc0b1abf045b62524d1996dd9aeaf7e86a8" + integrity sha512-LbxsdYVpHGoC2fMOdW0aQvuvVRD7aZx8p8DrP53HISpl7bD1PqLGWKzhHn7cGG24UHycBJrbaEeKEosW29W1dg== dependencies: - bluebird "3.7.1" - debug "4.1.1" + bluebird "3.5.0" + debug "3.1.0" optionalDependencies: "@babel/core" "^7.0.1" "@babel/preset-env" "^7.0.0" @@ -5320,6 +5320,11 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" +acorn-dynamic-import@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" + integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== + acorn-globals@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" @@ -5394,7 +5399,7 @@ acorn@^6.0.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== -acorn@^6.2.1: +acorn@^6.0.5, acorn@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== @@ -6536,7 +6541,7 @@ async@^2.0.0, async@^2.1.4: dependencies: lodash "^4.14.0" -async@^2.6.2, async@^2.6.3: +async@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== @@ -7411,11 +7416,6 @@ bluebird@3.5.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== -bluebird@3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" - integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== - bluebird@^3.3.0, bluebird@^3.3.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -7937,7 +7937,27 @@ cac@^4.3.4: string-width "^2.1.1" text-table "^0.2.0" -cacache@^12.0.2, cacache@^12.0.3: +cacache@^11.3.3: + version "11.3.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc" + integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cacache@^12.0.2: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -7958,7 +7978,7 @@ cacache@^12.0.2, cacache@^12.0.3: unique-filename "^1.1.1" y18n "^4.0.0" -cacache@^13.0.1: +cacache@^13.0.0: version "13.0.1" resolved "https://registry.yarnpkg.com/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" integrity sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w== @@ -8163,6 +8183,11 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== +camelcase@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.2.0.tgz#e7522abda5ed94cc0489e1b8466610e88404cf45" + integrity sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ== + camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -8495,10 +8520,10 @@ chokidar@2.1.2, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4: optionalDependencies: fsevents "^1.2.7" -chokidar@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" - integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== +chokidar@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.2.1.tgz#4634772a1924512d990d4505957bf3a510611387" + integrity sha512-/j5PPkb5Feyps9e+jo07jUZGvkB5Aj953NrI4s8xSVScrAo/RHeILrtdb4uzR7N6aaFFxxJ+gt8mA8HfNpw76w== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -8506,9 +8531,9 @@ chokidar@3.3.0: is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.2.0" + readdirp "~3.1.3" optionalDependencies: - fsevents "~2.1.1" + fsevents "~2.1.0" chokidar@^2.0.0, chokidar@^2.1.2, chokidar@^2.1.8: version "2.1.8" @@ -8544,7 +8569,7 @@ chroma-js@^1.4.1: resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-1.4.1.tgz#eb2d9c4d1ff24616be84b35119f4d26f8205f134" integrity sha512-jTwQiT859RTFN/vIf7s+Vl/Z2LcMrvMv3WUFmd/4u76AdlFC0NTNgqEEFPcRiHmAswPsMiQEDZLM8vX8qXpZNQ== -chrome-trace-event@^1.0.2: +chrome-trace-event@^1.0.0, chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== @@ -9487,12 +9512,12 @@ copy-to-clipboard@^3.2.0: dependencies: toggle-selection "^1.0.6" -copy-webpack-plugin@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88" - integrity sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg== +copy-webpack-plugin@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.0.4.tgz#c78126f604e24f194c6ec2f43a64e232b5d43655" + integrity sha512-YBuYGpSzoCHSSDGyHy6VJ7SHojKp6WHT4D7ItcQFNAYx2hrwkMe56e97xfVR0/ovDuMTrMffXUiltvQljtAGeg== dependencies: - cacache "^12.0.3" + cacache "^11.3.3" find-cache-dir "^2.1.0" glob-parent "^3.1.0" globby "^7.1.1" @@ -9500,9 +9525,9 @@ copy-webpack-plugin@^5.1.1: loader-utils "^1.2.3" minimatch "^3.0.4" normalize-path "^3.0.0" - p-limit "^2.2.1" + p-limit "^2.2.0" schema-utils "^1.0.0" - serialize-javascript "^2.1.2" + serialize-javascript "^1.7.0" webpack-log "^2.0.0" core-js-compat@^3.1.1: @@ -9885,23 +9910,22 @@ css-in-js-utils@^2.0.0: hyphenate-style-name "^1.0.2" isobject "^3.0.1" -css-loader@3.3.2, css-loader@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.3.2.tgz#41b2086528aa4fbf8c0692e874bc14f081129b21" - integrity sha512-4XSiURS+YEK2fQhmSaM1onnUm0VKWNf6WWBYjkp9YbSDGCBTVZ5XOM6Gkxo8tLgQlzkZOBJvk9trHlDk4gjEYg== +css-loader@2.1.1, css-loader@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" + integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== dependencies: - camelcase "^5.3.1" - cssesc "^3.0.0" - icss-utils "^4.1.1" + camelcase "^5.2.0" + icss-utils "^4.1.0" loader-utils "^1.2.3" normalize-path "^3.0.0" - postcss "^7.0.23" + postcss "^7.0.14" postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.1.1" - postcss-modules-values "^3.0.0" - postcss-value-parser "^4.0.2" - schema-utils "^2.6.0" + postcss-modules-local-by-default "^2.0.6" + postcss-modules-scope "^2.1.0" + postcss-modules-values "^2.0.0" + postcss-value-parser "^3.3.0" + schema-utils "^1.0.0" css-loader@^3.0.0: version "3.2.0" @@ -10495,7 +10519,7 @@ debug@3.1.0, debug@=3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debug@3.2.6, debug@3.X, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: +debug@3.2.6, debug@3.X, debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -10509,7 +10533,7 @@ debug@4.1.0: dependencies: ms "^2.1.1" -debug@4.1.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -11657,9 +11681,9 @@ enhanced-resolve@4.1.0, enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: memory-fs "^0.4.0" tapable "^1.0.0" -enhanced-resolve@^0.9.1: +enhanced-resolve@~0.9.0: version "0.9.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4= dependencies: graceful-fs "^4.1.2" @@ -12063,21 +12087,21 @@ eslint-import-resolver-node@0.3.2, eslint-import-resolver-node@^0.3.2: debug "^2.6.9" resolve "^1.5.0" -eslint-import-resolver-webpack@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.0.tgz#61b9879ff39441ed83cc2e304624506fa584b17e" - integrity sha512-S0hJUrbcTsVjPQRa8bdNQrv/sc45bGwhtoJk3Ru/1qZWnR4oArGKHYe61xT03iHZSo9K/xL63rTMiayW5+NGMQ== +eslint-import-resolver-webpack@0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.11.1.tgz#fcf1fd57a775f51e18f442915f85dd6ba45d2f26" + integrity sha512-eK3zR7xVQR/MaoBWwGuD+CULYVuqe5QFlDukman71aI6IboCGzggDUohHNfu1ZeBnbHcUHJc0ywWoXUBNB6qdg== dependencies: array-find "^1.0.0" - debug "^2.6.9" - enhanced-resolve "^0.9.1" + debug "^2.6.8" + enhanced-resolve "~0.9.0" find-root "^1.1.0" - has "^1.0.3" - interpret "^1.2.0" - lodash "^4.17.15" + has "^1.0.1" + interpret "^1.0.0" + lodash "^4.17.4" node-libs-browser "^1.0.0 || ^2.0.0" - resolve "^1.13.1" - semver "^5.7.1" + resolve "^1.10.0" + semver "^5.3.0" eslint-module-utils@2.5.0, eslint-module-utils@^2.4.1: version "2.5.0" @@ -13162,13 +13186,13 @@ file-exists-dazinatorfork@^1.0.2: resolved "https://registry.yarnpkg.com/file-exists-dazinatorfork/-/file-exists-dazinatorfork-1.0.2.tgz#cd8d0d85f63e39dc81eceb0b687c44a2cca95c47" integrity sha512-r70c72ln2YHzQINNfxDp02hAhbGkt1HffZ+Du8oetWDLjDtFja/Lm10lUaSh9e+wD+7VDvPee0b0C9SAy8pWZg== -file-loader@5.0.2, file-loader@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-5.0.2.tgz#7f3d8b4ac85a5e8df61338cfec95d7405f971caa" - integrity sha512-QMiQ+WBkGLejKe81HU8SZ9PovsU/5uaLo0JdTCEXOYv7i7jfAjHZi1tcwp9tSASJPOmmHZtbdCervFmXMH/Dcg== +file-loader@4.2.0, file-loader@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.2.0.tgz#5fb124d2369d7075d70a9a5abecd12e60a95215e" + integrity sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ== dependencies: loader-utils "^1.2.3" - schema-utils "^2.5.0" + schema-utils "^2.0.0" file-loader@^3.0.1: version "3.0.1" @@ -13355,15 +13379,6 @@ find-cache-dir@^3.0.0: make-dir "^3.0.0" pkg-dir "^4.1.0" -find-cache-dir@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.2.0.tgz#e7fe44c1abc1299f516146e563108fd1006c1874" - integrity sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.0" - pkg-dir "^4.1.0" - find-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" @@ -13882,10 +13897,10 @@ fsevents@^1.2.7: nan "^2.9.2" node-pre-gyp "^0.10.0" -fsevents@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" - integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== +fsevents@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.0.tgz#ce1a5f9ac71c6d75278b0c5bd236d7dfece4cbaa" + integrity sha512-+iXhW3LuDQsno8dOIrCIT/CBjeBWuP7PXe8w9shnj9Lebny/Gx1ZjVBYwexLz36Ri2jKuXMNpV6CYNh8lHHgrQ== fstream@^1.0.0: version "1.0.11" @@ -15989,6 +16004,11 @@ iconv-lite@^0.5.0: dependencies: safer-buffer ">= 2.1.2 < 3" +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= + icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" @@ -15996,6 +16016,13 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" +icss-utils@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.0.tgz#339dbbffb9f8729a243b701e1c29d4cc58c52f0e" + integrity sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ== + dependencies: + postcss "^7.0.14" + idx@^2.5.6: version "2.5.6" resolved "https://registry.yarnpkg.com/idx/-/idx-2.5.6.tgz#1f824595070100ae9ad585c86db08dc74f83a59d" @@ -18914,16 +18941,16 @@ load-source-map@^1.0.0: semver "^5.3.0" source-map "^0.5.6" +loader-runner@^2.3.0, loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + loader-runner@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.1.tgz#026f12fe7c3115992896ac02ba022ba92971b979" integrity sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw== -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - loader-utils@1.2.3, loader-utils@^1.0.4, loader-utils@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" @@ -18933,7 +18960,7 @@ loader-utils@1.2.3, loader-utils@^1.0.4, loader-utils@^1.2.3: emojis-list "^2.0.0" json5 "^1.0.1" -loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0: +loader-utils@^1.0.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= @@ -19845,7 +19872,7 @@ memory-fs@^0.2.0: resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA= -memory-fs@^0.4.0, memory-fs@^0.4.1: +memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= @@ -19949,7 +19976,7 @@ microevent.ts@~0.1.1: resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== -micromatch@3.1.10, micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@3.1.10, micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -20934,7 +20961,7 @@ node-jose@1.1.0: util "^0.11.0" vm-browserify "0.0.4" -node-libs-browser@^2.2.1: +node-libs-browser@^2.0.0, node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== @@ -21864,13 +21891,6 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" - integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== - dependencies: - p-try "^2.0.0" - p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -22690,14 +22710,14 @@ popper.js@^1.14.4: resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e" integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ== -portfinder@^1.0.25: - version "1.0.25" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" - integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== +portfinder@^1.0.24: + version "1.0.24" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.24.tgz#11efbc6865f12f37624b6531ead1d809ed965cfa" + integrity sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg== dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.1" + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" posix-character-classes@^0.1.0: version "0.1.1" @@ -22736,6 +22756,15 @@ postcss-modules-extract-imports@^2.0.0: dependencies: postcss "^7.0.5" +postcss-modules-local-by-default@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" + integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + postcss-value-parser "^3.3.1" + postcss-modules-local-by-default@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" @@ -22754,13 +22783,13 @@ postcss-modules-scope@^2.1.0: postcss "^7.0.6" postcss-selector-parser "^6.0.0" -postcss-modules-scope@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba" - integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ== +postcss-modules-values@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" + integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== dependencies: + icss-replace-symbols "^1.1.0" postcss "^7.0.6" - postcss-selector-parser "^6.0.0" postcss-modules-values@^3.0.0: version "3.0.0" @@ -22797,6 +22826,11 @@ postcss-url@^8.0.0: postcss "^7.0.2" xxhashjs "^0.2.1" +postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + postcss-value-parser@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d" @@ -22834,15 +22868,6 @@ postcss@^7.0.16: source-map "^0.6.1" supports-color "^6.1.0" -postcss@^7.0.23: - version "7.0.24" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.24.tgz#972c3c5be431b32e40caefe6c81b5a19117704c2" - integrity sha512-Xl0XvdNWg+CblAXzNvbSOUvgJXwSjmbAKORqyw9V2AlHrm1js2gFw9y3jibBAhpKZi8b5JzJCVh/FyzPsTtgTA== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - potpack@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.1.tgz#d1b1afd89e4c8f7762865ec30bd112ab767e2ebf" @@ -23568,13 +23593,13 @@ raw-body@~1.1.0: bytes "1" string_decoder "0.10" -raw-loader@4.0.0, raw-loader@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.0.tgz#d639c40fb9d72b5c7f8abc1fb2ddb25b29d3d540" - integrity sha512-iINUOYvl1cGEmfoaLjnZXt4bKfT2LJnZZib5N/LLyAphC+Dd11vNP9CNVb38j+SAJpFI1uo8j9frmih53ASy7Q== +raw-loader@3.1.0, raw-loader@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-3.1.0.tgz#5e9d399a5a222cc0de18f42c3bc5e49677532b3f" + integrity sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA== dependencies: - loader-utils "^1.2.3" - schema-utils "^2.5.0" + loader-utils "^1.1.0" + schema-utils "^2.0.1" raw-loader@^2.0.0: version "2.0.0" @@ -24622,10 +24647,10 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" - integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== +readdirp@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.3.tgz#d6e011ed5b9240a92f08651eeb40f7942ceb6cc1" + integrity sha512-ZOsfTGkjO2kqeR5Mzr5RYDbTGYneSkdNKX2fOX2P5jF7vMrd/GNnIAUtDldeHHumHUCQ3V05YfWUdxMPAsRu9Q== dependencies: picomatch "^2.0.4" @@ -25512,13 +25537,6 @@ resolve@^1.12.0, resolve@^1.4.0: dependencies: path-parse "^1.0.6" -resolve@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" - integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== - dependencies: - path-parse "^1.0.6" - resolve@^1.5.0, resolve@^1.7.1: version "1.7.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" @@ -25919,15 +25937,15 @@ sass-lint@^1.12.1: path-is-absolute "^1.0.0" util "^0.10.3" -sass-loader@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.0.tgz#e7b07a3e357f965e6b03dd45b016b0a9746af797" - integrity sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w== +sass-loader@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.3.1.tgz#a5bf68a04bcea1c13ff842d747150f7ab7d0d23f" + integrity sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA== dependencies: clone-deep "^4.0.1" - loader-utils "^1.2.3" - neo-async "^2.6.1" - schema-utils "^2.1.0" + loader-utils "^1.0.1" + neo-async "^2.5.0" + pify "^4.0.1" semver "^6.3.0" sass-lookup@^3.0.0: @@ -25982,7 +26000,7 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" -schema-utils@^0.4.0: +schema-utils@^0.4.0, schema-utils@^0.4.5: version "0.4.7" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== @@ -26007,14 +26025,6 @@ schema-utils@^2.0.0, schema-utils@^2.0.1: ajv "^6.1.0" ajv-keywords "^3.1.0" -schema-utils@^2.1.0, schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f" - integrity sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg== - dependencies: - ajv "^6.10.2" - ajv-keywords "^3.4.1" - schema-utils@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.4.1.tgz#e89ade5d056dc8bcaca377574bb4a9c4e1b8be56" @@ -26145,11 +26155,6 @@ semver@^5.5.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== -semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - semver@^6.0.0: version "6.1.2" resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.2.tgz#079960381376a3db62eb2edc8a3bfb10c7cfe318" @@ -26216,7 +26221,7 @@ sentence-case@^2.1.0: no-case "^2.2.0" upper-case-first "^1.1.2" -serialize-javascript@^1.7.0, serialize-javascript@^2.1.1, serialize-javascript@^2.1.2: +serialize-javascript@^1.7.0, serialize-javascript@^2.1.0, serialize-javascript@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.1.tgz#952907a04a3e3a75af7f73d92d15e233862048b2" integrity sha512-MPLPRpD4FNqWq9tTIjYG5LesFouDhdyH0EPY3gVK4DRD5+g4aDqdNSzLIwceulo3Yj+PL1bPh6laE5+H6LTcrQ== @@ -27544,15 +27549,7 @@ style-it@^2.1.3: dependencies: react-lib-adler32 "^1.0.3" -style-loader@1.0.1, style-loader@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.1.tgz#aec6d4c61d0ed8d0a442faed741d4dfc6573888a" - integrity sha512-CnpEkSR1C+REjudiTWCv4+ssP7SCiuaQZJTZDWBRwTJoS90mdqkB8uOGMHKgVeUzpaU7IfLWoyQbvvs5Joj3Xw== - dependencies: - loader-utils "^1.2.3" - schema-utils "^2.0.1" - -style-loader@^0.23.1: +style-loader@0.23.1, style-loader@^0.23.1: version "0.23.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== @@ -28030,7 +28027,7 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -terser-webpack-plugin@^1.2.4, terser-webpack-plugin@^1.4.1: +terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.2.4, terser-webpack-plugin@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== @@ -28045,18 +28042,18 @@ terser-webpack-plugin@^1.2.4, terser-webpack-plugin@^1.4.1: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser-webpack-plugin@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.0.tgz#00fd8f792a330dc572e2e2b468fd7cb5ffd7ea51" - integrity sha512-yez0HdpDf/iQVYGf+e/o8ZYWLb1g9d1nRRi5FIOZ4KfXbfSPT259UoqxPiSLhCnr0mlDoh+bucpYQSFbU0cEsQ== +terser-webpack-plugin@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.1.2.tgz#2b9b8147a6f18918348200800cf9560c50f701bb" + integrity sha512-MF/C4KABwqYOfRDi87f7gG07GP7Wj/kyiX938UxIGIO6l5mkh8XJL7xtS0hX/CRdVQaZI7ThGUPZbznrCjsGpg== dependencies: - cacache "^13.0.1" - find-cache-dir "^3.1.0" + cacache "^13.0.0" + find-cache-dir "^3.0.0" jest-worker "^24.9.0" - schema-utils "^2.6.1" - serialize-javascript "^2.1.2" + schema-utils "^2.4.1" + serialize-javascript "^2.1.0" source-map "^0.6.1" - terser "^4.4.2" + terser "^4.3.4" webpack-sources "^1.4.3" terser@^4.1.2: @@ -28068,10 +28065,10 @@ terser@^4.1.2: source-map "~0.6.1" source-map-support "~0.5.12" -terser@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.2.tgz#448fffad0245f4c8a277ce89788b458bfd7706e8" - integrity sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ== +terser@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.4.tgz#ad91bade95619e3434685d69efa621a5af5f877d" + integrity sha512-Kcrn3RiW8NtHBP0ssOAzwa2MsIRQ8lJWiBG/K7JgqPlomA3mtb2DEmp4/hrUA+Jujx+WZ02zqd7GYD+QRBB/2Q== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -29664,16 +29661,7 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-loader@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-3.0.0.tgz#9f1f11b371acf6e51ed15a50db635e02eec18368" - integrity sha512-a84JJbIA5xTFTWyjjcPdnsu+41o/SNE8SpXMdUvXs6Q+LuhCD9E2+0VCiuDWqgo3GGXVlFHzArDmBpj9PgWn4A== - dependencies: - loader-utils "^1.2.3" - mime "^2.4.4" - schema-utils "^2.5.0" - -url-loader@^2.0.1: +url-loader@2.2.0, url-loader@^2.0.1: version "2.2.0" resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.2.0.tgz#af321aece1fd0d683adc8aaeb27829f29c75b46e" integrity sha512-G8nk3np8ZAnwhHXas1JxJEwJyQdqFXAKJehfgZ/XrC48volFBRtO+FIKtF2u0Ma3bw+4vnDVjHPAQYlF9p2vsw== @@ -29897,13 +29885,13 @@ v8flags@^3.0.1: dependencies: homedir-polyfill "^1.0.1" -val-loader@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/val-loader/-/val-loader-2.0.2.tgz#12cda9a55b3e9c0305763c03f872ea0951861df2" - integrity sha512-Wzce0uHkvt/gjCas7uW6Q0BeU2FxUv9KPw/n4WXYo/9pkBZhmtNpi2FgXmq2LhEpu52kHAifFhJrTgjCMmWAwQ== +val-loader@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/val-loader/-/val-loader-1.1.1.tgz#32ba8ed5c3607504134977251db2966499e15ef7" + integrity sha512-JLqLXJWCVLXTxbUeHhLpWkgl3+X3U8Bl0vY7rTFZgFSbLJaEtAxuD2ixy/cM8w/gzC7sS3NE5IDSzClDt332sw== dependencies: - loader-utils "^1.2.3" - schema-utils "^2.5.0" + loader-utils "^1.0.0" + schema-utils "^0.4.5" valid-url@1.0.9: version "1.0.9" @@ -30591,7 +30579,7 @@ warning@^4.0.2: dependencies: loose-envify "^1.0.0" -watchpack@^1.6.0: +watchpack@^1.5.0, watchpack@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== @@ -30631,10 +30619,10 @@ webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-cli@^3.3.10: - version "3.3.10" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" - integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg== +webpack-cli@^3.3.9: + version "3.3.9" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.9.tgz#79c27e71f94b7fe324d594ab64a8e396b9daa91a" + integrity sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A== dependencies: chalk "2.4.2" cross-spawn "6.0.5" @@ -30669,10 +30657,10 @@ webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" -webpack-dev-server@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz#27c3b5d0f6b6677c4304465ac817623c8b27b89c" - integrity sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw== +webpack-dev-server@^3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.2.tgz#3292427bf6510da9a3ac2d500b924a4197667ff9" + integrity sha512-0xxogS7n5jHDQWy0WST0q6Ykp7UGj4YvWh+HVN71JoE7BwPxMZrwgraBvmdEMbDVMBzF0u+mEzn8TQzBm5NYJQ== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -30692,7 +30680,7 @@ webpack-dev-server@^3.9.0: loglevel "^1.6.4" opn "^5.5.0" p-retry "^3.0.1" - portfinder "^1.0.25" + portfinder "^1.0.24" schema-utils "^1.0.0" selfsigned "^1.10.7" semver "^6.3.0" @@ -30751,7 +30739,7 @@ webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: +webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -30759,10 +30747,40 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@4.41.2, webpack@^4.41.2: - version "4.41.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.2.tgz#c34ec76daa3a8468c9b61a50336d8e3303dce74e" - integrity sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A== +webpack@4.33.0: + version "4.33.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.33.0.tgz#c30fc4307db432e5c5e3333aaa7c16a15a3b277e" + integrity sha512-ggWMb0B2QUuYso6FPZKUohOgfm+Z0sVFs8WwWuSH1IAvkWs428VDNmOlAxvHGTB9Dm/qOB/qtE5cRx5y01clxw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.0.5" + acorn-dynamic-import "^4.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^1.0.0" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + +webpack@4.41.0, webpack@^4.41.0: + version "4.41.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.0.tgz#db6a254bde671769f7c14e90a1a55e73602fc70b" + integrity sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" From 77479020e052121d9f44de451161b7e93c06cad9 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 10:42:22 -0700 Subject: [PATCH 12/60] Revert "Update supertest related packages (#53081)" This reverts commit 5eed8b4eb9457b6f6de60a42bfd3e68113abaf7c. --- package.json | 4 +- .../test_suites/core_plugins/ui_settings.ts | 2 +- x-pack/package.json | 4 +- yarn.lock | 43 +++++++++++-------- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index ff7feb2464b1d5..157c306bec07e7 100644 --- a/package.json +++ b/package.json @@ -356,7 +356,7 @@ "@types/sinon": "^7.0.13", "@types/strip-ansi": "^3.0.0", "@types/styled-components": "^4.4.1", - "@types/supertest": "^2.0.8", + "@types/supertest": "^2.0.5", "@types/supertest-as-promised": "^2.0.38", "@types/testing-library__react": "^9.1.2", "@types/testing-library__react-hooks": "^3.1.0", @@ -456,7 +456,7 @@ "simple-git": "1.129.0", "sinon": "^7.4.2", "strip-ansi": "^3.0.1", - "supertest": "^4.0.2", + "supertest": "^3.1.0", "supertest-as-promised": "^4.0.2", "tree-kill": "^1.2.1", "typescript": "3.7.2", diff --git a/test/plugin_functional/test_suites/core_plugins/ui_settings.ts b/test/plugin_functional/test_suites/core_plugins/ui_settings.ts index 205dbc548725ac..2b4227ee798e3f 100644 --- a/test/plugin_functional/test_suites/core_plugins/ui_settings.ts +++ b/test/plugin_functional/test_suites/core_plugins/ui_settings.ts @@ -46,7 +46,7 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider await supertest .get('/api/ui-settings-plugin') .expect(200) - .expect({ uiSettingsValue: '2' }); + .expect({ uiSettingsValue: 2 }); }); }); } diff --git a/x-pack/package.json b/x-pack/package.json index ac6d46ba38f425..6413508976094d 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -99,7 +99,7 @@ "@types/redux-actions": "^2.2.1", "@types/sinon": "^7.0.13", "@types/styled-components": "^4.4.1", - "@types/supertest": "^2.0.8", + "@types/supertest": "^2.0.5", "@types/tar-fs": "^1.16.1", "@types/tinycolor2": "^1.4.1", "@types/uuid": "^3.4.4", @@ -160,7 +160,7 @@ "simple-git": "1.129.0", "sinon": "^7.4.2", "string-replace-loader": "^2.2.0", - "supertest": "^4.0.2", + "supertest": "^3.1.0", "supertest-as-promised": "^4.0.2", "tmp": "0.1.0", "tree-kill": "^1.2.1", diff --git a/yarn.lock b/yarn.lock index 968adcac381957..6b0259f52e3314 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4814,13 +4814,20 @@ "@types/superagent" "*" "@types/supertest" "*" -"@types/supertest@*", "@types/supertest@^2.0.8": +"@types/supertest@*": version "2.0.8" resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.8.tgz#23801236e2b85204ed771a8e7c40febba7da2bda" integrity sha512-wcax7/ip4XSSJRLbNzEIUVy2xjcBIZZAuSd2vtltQfRK7kxhx5WMHbLHkYdxN3wuQCrwpYrg86/9byDjPXoGMA== dependencies: "@types/superagent" "*" +"@types/supertest@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.5.tgz#18d082a667eaed22759be98f4923e0061ae70c62" + integrity sha512-orl732spRnz4+Bqwk1OnXkJUX2YhiGvMUyfn8VTGXqMZSk6jrMhBq7IuoSXMyBrpsCV5eSddPiC3S0iIafYxsQ== + dependencies: + "@types/superagent" "*" + "@types/tar-fs@^1.16.1": version "1.16.1" resolved "https://registry.yarnpkg.com/@types/tar-fs/-/tar-fs-1.16.1.tgz#6e3fba276c173e365ae91e55f7b797a0e64298e5" @@ -13709,10 +13716,10 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" -formidable@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" - integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== +formidable@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.1.1.tgz#96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9" + integrity sha1-lriIb3w8NQi5Mta9cMTTqI818ak= formsy-react@^1.1.5: version "1.1.5" @@ -19966,7 +19973,7 @@ merge@^1.2.0: resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== -methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: +methods@^1.1.1, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= @@ -27621,21 +27628,21 @@ suffix@^0.1.0: resolved "https://registry.yarnpkg.com/suffix/-/suffix-0.1.0.tgz#3e46966de56af17600385e58db8ec659dd797907" integrity sha1-PkaWbeVq8XYAOF5Y247GWd15eQc= -superagent@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" - integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== +superagent@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.2.tgz#e4a11b9d047f7d3efeb3bbe536d9ec0021d16403" + integrity sha512-gVH4QfYHcY3P0f/BZzavLreHW3T1v7hG9B+hpMQotGQqurOvhv87GcMCd6LWySmBuf+BDR44TQd0aISjVHLeNQ== dependencies: component-emitter "^1.2.0" cookiejar "^2.1.0" debug "^3.1.0" extend "^3.0.0" form-data "^2.3.1" - formidable "^1.2.0" + formidable "^1.1.1" methods "^1.1.1" mime "^1.4.1" qs "^6.5.1" - readable-stream "^2.3.5" + readable-stream "^2.0.5" supercluster@^6.0.1: version "6.0.1" @@ -27652,13 +27659,13 @@ supertest-as-promised@^4.0.2: bluebird "^3.3.1" methods "^1.1.1" -supertest@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" - integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== +supertest@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-3.1.0.tgz#f9ebaf488e60f2176021ec580bdd23ad269e7bc6" + integrity sha512-O44AMnmJqx294uJQjfUmEyYOg7d9mylNFsMw/Wkz4evKd1njyPrtCN+U6ZIC7sKtfEVQhfTqFFijlXx8KP/Czw== dependencies: - methods "^1.1.2" - superagent "^3.8.3" + methods "~1.1.2" + superagent "3.8.2" supports-color@5.5.0, supports-color@^5.0.0, supports-color@^5.4.0, supports-color@^5.5.0: version "5.5.0" From a926e3419d87e8e20a7617246ed9a6feeaac91c9 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:03:14 -0700 Subject: [PATCH 13/60] Revert "Update babel related packages (#52754)" This reverts commit 9a115f078fd5680c2b5b39e3d0ba1ac81fe45556. --- package.json | 14 +- packages/elastic-datemath/package.json | 4 +- packages/kbn-analytics/package.json | 2 +- packages/kbn-babel-code-parser/package.json | 6 +- packages/kbn-babel-preset/package.json | 16 +- packages/kbn-i18n/package.json | 4 +- packages/kbn-interpreter/package.json | 8 +- packages/kbn-plugin-helpers/package.json | 2 +- packages/kbn-pm/dist/index.js | 1096 +++---------------- packages/kbn-pm/package.json | 8 +- packages/kbn-test/package.json | 2 +- packages/kbn-ui-framework/package.json | 4 +- x-pack/package.json | 6 +- yarn.lock | 175 ++- 14 files changed, 240 insertions(+), 1107 deletions(-) diff --git a/package.json b/package.json index 157c306bec07e7..b240a33cd84444 100644 --- a/package.json +++ b/package.json @@ -110,8 +110,8 @@ ] }, "dependencies": { - "@babel/core": "^7.7.5", - "@babel/register": "^7.7.4", + "@babel/core": "^7.5.5", + "@babel/register": "^7.7.0", "@elastic/charts": "^14.0.0", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "1.0.5", @@ -156,7 +156,7 @@ "color": "1.0.3", "commander": "3.0.2", "compare-versions": "3.5.1", - "core-js": "^3.5.0", + "core-js": "^3.2.1", "css-loader": "2.1.1", "custom-event-polyfill": "^0.3.0", "d3": "3.5.17", @@ -275,9 +275,9 @@ "yauzl": "2.10.0" }, "devDependencies": { - "@babel/parser": "^7.7.5", - "@babel/plugin-syntax-dynamic-import": "^7.7.4", - "@babel/types": "^7.7.4", + "@babel/parser": "^7.5.5", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/types": "^7.5.5", "@elastic/elasticsearch": "^7.4.0", "@elastic/eslint-config-kibana": "0.15.0", "@elastic/eslint-plugin-eui": "0.0.2", @@ -298,7 +298,7 @@ "@testing-library/react-hooks": "^3.2.1", "@types/angular": "^1.6.56", "@types/angular-mocks": "^1.7.0", - "@types/babel__core": "^7.1.3", + "@types/babel__core": "^7.1.2", "@types/bluebird": "^3.1.1", "@types/boom": "^7.2.0", "@types/chance": "^1.0.0", diff --git a/packages/elastic-datemath/package.json b/packages/elastic-datemath/package.json index e41744311e3be6..57873d28d372de 100644 --- a/packages/elastic-datemath/package.json +++ b/packages/elastic-datemath/package.json @@ -11,8 +11,8 @@ "kbn:watch": "yarn build --watch" }, "devDependencies": { - "@babel/cli": "^7.7.5", - "@babel/preset-env": "^7.7.6", + "@babel/cli": "^7.5.5", + "@babel/preset-env": "^7.5.5", "babel-plugin-add-module-exports": "^1.0.2", "moment": "^2.24.0" }, diff --git a/packages/kbn-analytics/package.json b/packages/kbn-analytics/package.json index 73f19690d4c7b4..9eefa16aaca017 100644 --- a/packages/kbn-analytics/package.json +++ b/packages/kbn-analytics/package.json @@ -14,7 +14,7 @@ "kbn:watch": "node scripts/build --source-maps --watch" }, "devDependencies": { - "@babel/cli": "^7.7.5", + "@babel/cli": "^7.5.5", "@kbn/dev-utils": "1.0.0", "@kbn/babel-preset": "1.0.0", "typescript": "3.7.2" diff --git a/packages/kbn-babel-code-parser/package.json b/packages/kbn-babel-code-parser/package.json index 8c7d51da791a5f..a9d373d33ab38e 100755 --- a/packages/kbn-babel-code-parser/package.json +++ b/packages/kbn-babel-code-parser/package.json @@ -15,12 +15,12 @@ "kbn:watch": "yarn build --watch" }, "devDependencies": { - "@babel/cli": "^7.7.5" + "@babel/cli": "^7.5.5" }, "dependencies": { "@kbn/babel-preset": "1.0.0", - "@babel/parser": "^7.7.5", - "@babel/traverse": "^7.7.4", + "@babel/parser": "^7.5.5", + "@babel/traverse": "^7.5.5", "lodash": "^4.17.15" } } diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json index d617c287b4f890..0acafbae59afd3 100644 --- a/packages/kbn-babel-preset/package.json +++ b/packages/kbn-babel-preset/package.json @@ -4,17 +4,17 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.7.4", - "@babel/plugin-proposal-optional-chaining": "^7.7.5", - "@babel/plugin-syntax-dynamic-import": "^7.7.4", - "@babel/plugin-transform-modules-commonjs": "^7.7.5", - "@babel/preset-env": "^7.7.6", + "@babel/plugin-proposal-class-properties": "^7.5.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4", + "@babel/plugin-proposal-optional-chaining": "^7.6.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.5.0", + "@babel/preset-env": "^7.5.5", "@babel/preset-react": "^7.7.4", "@babel/preset-typescript": "^7.7.4", "babel-plugin-add-module-exports": "^1.0.2", - "babel-plugin-filter-imports": "^4.0.0", + "babel-plugin-filter-imports": "^3.0.0", "babel-plugin-styled-components": "^1.10.6", - "babel-plugin-transform-define": "^2.0.0" + "babel-plugin-transform-define": "^1.3.1" } } diff --git a/packages/kbn-i18n/package.json b/packages/kbn-i18n/package.json index a3f5009f30dba6..bbc5126da1dce0 100644 --- a/packages/kbn-i18n/package.json +++ b/packages/kbn-i18n/package.json @@ -12,8 +12,8 @@ "kbn:watch": "node scripts/build --watch --source-maps" }, "devDependencies": { - "@babel/cli": "^7.7.5", - "@babel/core": "^7.7.5", + "@babel/cli": "^7.5.5", + "@babel/core": "^7.5.5", "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", "@types/intl-relativeformat": "^2.1.0", diff --git a/packages/kbn-interpreter/package.json b/packages/kbn-interpreter/package.json index 2e80276f59f91e..27ef70d8718569 100644 --- a/packages/kbn-interpreter/package.json +++ b/packages/kbn-interpreter/package.json @@ -9,16 +9,16 @@ "kbn:watch": "node scripts/build --dev --watch" }, "dependencies": { - "@babel/runtime": "^7.7.6", + "@babel/runtime": "^7.5.5", "@kbn/i18n": "1.0.0", "lodash": "npm:@elastic/lodash@3.10.1-kibana3", "lodash.clone": "^4.5.0", "uuid": "3.3.2" }, "devDependencies": { - "@babel/cli": "^7.7.5", - "@babel/core": "^7.7.5", - "@babel/plugin-transform-runtime": "^7.7.6", + "@babel/cli": "^7.5.5", + "@babel/core": "^7.5.5", + "@babel/plugin-transform-runtime": "^7.5.5", "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", "babel-loader": "^8.0.6", diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index 68454a9ce8c1d6..20e2c6a7e58de6 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -13,7 +13,7 @@ "@kbn/babel-preset": "1.0.0" }, "dependencies": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.5.5", "argv-split": "^2.0.1", "commander": "^3.0.0", "del": "^5.1.0", diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index a5638b50629ecf..72c3457ff16892 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -8023,7 +8023,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(120); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } @@ -19088,7 +19088,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } @@ -23296,10 +23296,11 @@ const CleanCommand = { const originalCwd = process.cwd(); try { - for (const { - pattern, - cwd - } of toDelete) { + for (const _ref of toDelete) { + const { + pattern, + cwd + } = _ref; process.chdir(cwd); const promise = del__WEBPACK_IMPORTED_MODULE_1___default()(pattern); ora__WEBPACK_IMPORTED_MODULE_2___default.a.promise(promise, Object(path__WEBPACK_IMPORTED_MODULE_3__["relative"])(originalCwd, Object(path__WEBPACK_IMPORTED_MODULE_3__["join"])(cwd, String(pattern)))); @@ -45552,7 +45553,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(485); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); -/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(697); +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(692); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); /* @@ -45732,8 +45733,8 @@ const EventEmitter = __webpack_require__(46); const path = __webpack_require__(16); const arrify = __webpack_require__(487); const globby = __webpack_require__(488); -const cpFile = __webpack_require__(687); -const CpyError = __webpack_require__(695); +const cpFile = __webpack_require__(682); +const CpyError = __webpack_require__(690); const preprocessSrcPath = (srcPath, options) => options.cwd ? path.resolve(options.cwd, srcPath) : srcPath; @@ -45862,8 +45863,8 @@ const fs = __webpack_require__(23); const arrayUnion = __webpack_require__(489); const glob = __webpack_require__(37); const fastGlob = __webpack_require__(491); -const dirGlob = __webpack_require__(680); -const gitignore = __webpack_require__(683); +const dirGlob = __webpack_require__(675); +const gitignore = __webpack_require__(678); const DEFAULT_FILTER = () => false; @@ -46114,11 +46115,11 @@ module.exports.generateTasks = pkg.generateTasks; Object.defineProperty(exports, "__esModule", { value: true }); var optionsManager = __webpack_require__(493); var taskManager = __webpack_require__(494); -var reader_async_1 = __webpack_require__(651); -var reader_stream_1 = __webpack_require__(675); -var reader_sync_1 = __webpack_require__(676); -var arrayUtils = __webpack_require__(678); -var streamUtils = __webpack_require__(679); +var reader_async_1 = __webpack_require__(646); +var reader_stream_1 = __webpack_require__(670); +var reader_sync_1 = __webpack_require__(671); +var arrayUtils = __webpack_require__(673); +var streamUtils = __webpack_require__(674); /** * Synchronous API. */ @@ -46758,9 +46759,9 @@ var extend = __webpack_require__(612); */ var compilers = __webpack_require__(615); -var parsers = __webpack_require__(647); -var cache = __webpack_require__(648); -var utils = __webpack_require__(649); +var parsers = __webpack_require__(642); +var cache = __webpack_require__(643); +var utils = __webpack_require__(644); var MAX_LENGTH = 1024 * 64; /** @@ -65299,9 +65300,9 @@ var toRegex = __webpack_require__(502); */ var compilers = __webpack_require__(632); -var parsers = __webpack_require__(643); -var Extglob = __webpack_require__(646); -var utils = __webpack_require__(645); +var parsers = __webpack_require__(638); +var Extglob = __webpack_require__(641); +var utils = __webpack_require__(640); var MAX_LENGTH = 1024 * 64; /** @@ -65811,7 +65812,7 @@ var parsers = __webpack_require__(636); * Module dependencies */ -var debug = __webpack_require__(638)('expand-brackets'); +var debug = __webpack_require__(574)('expand-brackets'); var extend = __webpack_require__(511); var Snapdragon = __webpack_require__(541); var toRegex = __webpack_require__(502); @@ -66405,839 +66406,12 @@ exports.createRegex = function(pattern, include) { /* 638 */ /***/ (function(module, exports, __webpack_require__) { -/** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ - -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(639); -} else { - module.exports = __webpack_require__(642); -} - - -/***/ }), -/* 639 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(640); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; - } - - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - - -/***/ }), -/* 640 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = __webpack_require__(641); - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - -exports.formatters = {}; - -/** - * Previous log timestamp. - */ - -var prevTime; - -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - return debug; -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - - -/***/ }), -/* 641 */ -/***/ (function(module, exports) { - -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - - -/***/ }), -/* 642 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Module dependencies. - */ - -var tty = __webpack_require__(579); -var util = __webpack_require__(29); - -/** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(640); -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ - -exports.colors = [6, 2, 3, 4, 5, 1]; - -/** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ - -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); - - obj[prop] = val; - return obj; -}, {}); - -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; - -if (1 !== fd && 2 !== fd) { - util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() -} - -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); -} - -/** - * Map %o to `util.inspect()`, all on a single line. - */ - -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; - -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ - -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts); -}; - -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; - - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} - -/** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ - -function log() { - return stream.write(util.format.apply(util, arguments) + '\n'); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - return process.env.DEBUG; -} - -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = __webpack_require__(23); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = __webpack_require__(580); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; -} - -/** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - -function init (debug) { - debug.inspectOpts = {}; - - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} - -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); - - -/***/ }), -/* 643 */ -/***/ (function(module, exports, __webpack_require__) { - "use strict"; var brackets = __webpack_require__(633); -var define = __webpack_require__(644); -var utils = __webpack_require__(645); +var define = __webpack_require__(639); +var utils = __webpack_require__(640); /** * Characters to use in text regex (we want to "not" match @@ -67392,7 +66566,7 @@ module.exports = parsers; /***/ }), -/* 644 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67430,7 +66604,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 645 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67506,7 +66680,7 @@ utils.createRegex = function(str) { /***/ }), -/* 646 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67517,7 +66691,7 @@ utils.createRegex = function(str) { */ var Snapdragon = __webpack_require__(541); -var define = __webpack_require__(644); +var define = __webpack_require__(639); var extend = __webpack_require__(511); /** @@ -67525,7 +66699,7 @@ var extend = __webpack_require__(511); */ var compilers = __webpack_require__(632); -var parsers = __webpack_require__(643); +var parsers = __webpack_require__(638); /** * Customize Snapdragon parser and renderer @@ -67591,7 +66765,7 @@ module.exports = Extglob; /***/ }), -/* 647 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67681,14 +66855,14 @@ function textRegex(pattern) { /***/ }), -/* 648 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { module.exports = new (__webpack_require__(624))(); /***/ }), -/* 649 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67706,7 +66880,7 @@ utils.define = __webpack_require__(611); utils.diff = __webpack_require__(628); utils.extend = __webpack_require__(612); utils.pick = __webpack_require__(629); -utils.typeOf = __webpack_require__(650); +utils.typeOf = __webpack_require__(645); utils.unique = __webpack_require__(514); /** @@ -68004,7 +67178,7 @@ utils.unixify = function(options) { /***/ }), -/* 650 */ +/* 645 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -68139,7 +67313,7 @@ function isBuffer(val) { /***/ }), -/* 651 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68158,9 +67332,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(652); -var reader_1 = __webpack_require__(665); -var fs_stream_1 = __webpack_require__(669); +var readdir = __webpack_require__(647); +var reader_1 = __webpack_require__(660); +var fs_stream_1 = __webpack_require__(664); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -68221,15 +67395,15 @@ exports.default = ReaderAsync; /***/ }), -/* 652 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(653); -const readdirAsync = __webpack_require__(661); -const readdirStream = __webpack_require__(664); +const readdirSync = __webpack_require__(648); +const readdirAsync = __webpack_require__(656); +const readdirStream = __webpack_require__(659); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -68313,7 +67487,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 653 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68321,11 +67495,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(654); +const DirectoryReader = __webpack_require__(649); let syncFacade = { - fs: __webpack_require__(659), - forEach: __webpack_require__(660), + fs: __webpack_require__(654), + forEach: __webpack_require__(655), sync: true }; @@ -68354,7 +67528,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 654 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68363,9 +67537,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(28).Readable; const EventEmitter = __webpack_require__(46).EventEmitter; const path = __webpack_require__(16); -const normalizeOptions = __webpack_require__(655); -const stat = __webpack_require__(657); -const call = __webpack_require__(658); +const normalizeOptions = __webpack_require__(650); +const stat = __webpack_require__(652); +const call = __webpack_require__(653); /** * Asynchronously reads the contents of a directory and streams the results @@ -68741,14 +67915,14 @@ module.exports = DirectoryReader; /***/ }), -/* 655 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(656); +const globToRegExp = __webpack_require__(651); module.exports = normalizeOptions; @@ -68925,7 +68099,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 656 */ +/* 651 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -69062,13 +68236,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 657 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(658); +const call = __webpack_require__(653); module.exports = stat; @@ -69143,7 +68317,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 658 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69204,14 +68378,14 @@ function callOnce (fn) { /***/ }), -/* 659 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const call = __webpack_require__(658); +const call = __webpack_require__(653); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -69275,7 +68449,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 660 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69304,7 +68478,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 661 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69312,12 +68486,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(662); -const DirectoryReader = __webpack_require__(654); +const maybe = __webpack_require__(657); +const DirectoryReader = __webpack_require__(649); let asyncFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(663), + forEach: __webpack_require__(658), async: true }; @@ -69359,7 +68533,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 662 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69386,7 +68560,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 663 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69422,7 +68596,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 664 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69430,11 +68604,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(654); +const DirectoryReader = __webpack_require__(649); let streamFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(663), + forEach: __webpack_require__(658), async: true }; @@ -69454,16 +68628,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 665 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var deep_1 = __webpack_require__(666); -var entry_1 = __webpack_require__(668); -var pathUtil = __webpack_require__(667); +var deep_1 = __webpack_require__(661); +var entry_1 = __webpack_require__(663); +var pathUtil = __webpack_require__(662); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -69529,13 +68703,13 @@ exports.default = Reader; /***/ }), -/* 666 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(667); +var pathUtils = __webpack_require__(662); var patternUtils = __webpack_require__(495); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { @@ -69619,7 +68793,7 @@ exports.default = DeepFilter; /***/ }), -/* 667 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69650,13 +68824,13 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 668 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(667); +var pathUtils = __webpack_require__(662); var patternUtils = __webpack_require__(495); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { @@ -69742,7 +68916,7 @@ exports.default = EntryFilter; /***/ }), -/* 669 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69762,8 +68936,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(28); -var fsStat = __webpack_require__(670); -var fs_1 = __webpack_require__(674); +var fsStat = __webpack_require__(665); +var fs_1 = __webpack_require__(669); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -69813,14 +68987,14 @@ exports.default = FileSystemStream; /***/ }), -/* 670 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(671); -const statProvider = __webpack_require__(673); +const optionsManager = __webpack_require__(666); +const statProvider = __webpack_require__(668); /** * Asynchronous API. */ @@ -69851,13 +69025,13 @@ exports.statSync = statSync; /***/ }), -/* 671 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(672); +const fsAdapter = __webpack_require__(667); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -69870,7 +69044,7 @@ exports.prepare = prepare; /***/ }), -/* 672 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69893,7 +69067,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 673 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69945,7 +69119,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 674 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69976,7 +69150,7 @@ exports.default = FileSystem; /***/ }), -/* 675 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69996,9 +69170,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(28); -var readdir = __webpack_require__(652); -var reader_1 = __webpack_require__(665); -var fs_stream_1 = __webpack_require__(669); +var readdir = __webpack_require__(647); +var reader_1 = __webpack_require__(660); +var fs_stream_1 = __webpack_require__(664); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -70066,7 +69240,7 @@ exports.default = ReaderStream; /***/ }), -/* 676 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70085,9 +69259,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(652); -var reader_1 = __webpack_require__(665); -var fs_sync_1 = __webpack_require__(677); +var readdir = __webpack_require__(647); +var reader_1 = __webpack_require__(660); +var fs_sync_1 = __webpack_require__(672); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -70147,7 +69321,7 @@ exports.default = ReaderSync; /***/ }), -/* 677 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70166,8 +69340,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(670); -var fs_1 = __webpack_require__(674); +var fsStat = __webpack_require__(665); +var fs_1 = __webpack_require__(669); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -70213,7 +69387,7 @@ exports.default = FileSystemSync; /***/ }), -/* 678 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70229,7 +69403,7 @@ exports.flatten = flatten; /***/ }), -/* 679 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70250,13 +69424,13 @@ exports.merge = merge; /***/ }), -/* 680 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(681); +const pathType = __webpack_require__(676); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -70322,13 +69496,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 681 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(682); +const pify = __webpack_require__(677); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -70371,7 +69545,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 682 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70462,7 +69636,7 @@ module.exports = (obj, opts) => { /***/ }), -/* 683 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70470,9 +69644,9 @@ module.exports = (obj, opts) => { const fs = __webpack_require__(23); const path = __webpack_require__(16); const fastGlob = __webpack_require__(491); -const gitIgnore = __webpack_require__(684); -const pify = __webpack_require__(685); -const slash = __webpack_require__(686); +const gitIgnore = __webpack_require__(679); +const pify = __webpack_require__(680); +const slash = __webpack_require__(681); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -70570,7 +69744,7 @@ module.exports.sync = options => { /***/ }), -/* 684 */ +/* 679 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -71039,7 +70213,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 685 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71114,7 +70288,7 @@ module.exports = (input, options) => { /***/ }), -/* 686 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71132,17 +70306,17 @@ module.exports = input => { /***/ }), -/* 687 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const {constants: fsConstants} = __webpack_require__(23); -const {Buffer} = __webpack_require__(688); -const CpFileError = __webpack_require__(690); -const fs = __webpack_require__(692); -const ProgressEmitter = __webpack_require__(694); +const {Buffer} = __webpack_require__(683); +const CpFileError = __webpack_require__(685); +const fs = __webpack_require__(687); +const ProgressEmitter = __webpack_require__(689); const cpFile = (source, destination, options) => { if (!source || !destination) { @@ -71296,11 +70470,11 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 688 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { /* eslint-disable node/no-deprecated-api */ -var buffer = __webpack_require__(689) +var buffer = __webpack_require__(684) var Buffer = buffer.Buffer // alternative to using Object.keys for old browsers @@ -71364,18 +70538,18 @@ SafeBuffer.allocUnsafeSlow = function (size) { /***/ }), -/* 689 */ +/* 684 */ /***/ (function(module, exports) { module.exports = require("buffer"); /***/ }), -/* 690 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(691); +const NestedError = __webpack_require__(686); class CpFileError extends NestedError { constructor(message, nested) { @@ -71389,7 +70563,7 @@ module.exports = CpFileError; /***/ }), -/* 691 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(44); @@ -71443,15 +70617,15 @@ module.exports = NestedError; /***/ }), -/* 692 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(22); const makeDir = __webpack_require__(115); -const pify = __webpack_require__(693); -const CpFileError = __webpack_require__(690); +const pify = __webpack_require__(688); +const CpFileError = __webpack_require__(685); const fsP = pify(fs); @@ -71596,7 +70770,7 @@ if (fs.copyFileSync) { /***/ }), -/* 693 */ +/* 688 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71671,7 +70845,7 @@ module.exports = (input, options) => { /***/ }), -/* 694 */ +/* 689 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71712,12 +70886,12 @@ module.exports = ProgressEmitter; /***/ }), -/* 695 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(696); +const NestedError = __webpack_require__(691); class CpyError extends NestedError { constructor(message, nested) { @@ -71731,7 +70905,7 @@ module.exports = CpyError; /***/ }), -/* 696 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -71787,7 +70961,7 @@ module.exports = NestedError; /***/ }), -/* 697 */ +/* 692 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index e36c078790eccd..032bae75a35fa5 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -10,10 +10,10 @@ "prettier": "prettier --write './src/**/*.ts'" }, "devDependencies": { - "@babel/core": "^7.7.5", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-proposal-object-rest-spread": "^7.7.4", - "@babel/preset-env": "^7.7.6", + "@babel/core": "^7.5.5", + "@babel/plugin-proposal-class-properties": "^7.5.5", + "@babel/plugin-proposal-object-rest-spread": "^7.5.5", + "@babel/preset-env": "^7.5.5", "@babel/preset-typescript": "^7.7.4", "@types/cmd-shim": "^2.0.0", "@types/cpy": "^5.1.0", diff --git a/packages/kbn-test/package.json b/packages/kbn-test/package.json index ac35c583ec7470..0cc54fa2a64c41 100644 --- a/packages/kbn-test/package.json +++ b/packages/kbn-test/package.json @@ -10,7 +10,7 @@ "kbn:watch": "yarn build --watch" }, "devDependencies": { - "@babel/cli": "^7.7.5", + "@babel/cli": "^7.5.5", "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", "@types/parse-link-header": "^1.0.0", diff --git a/packages/kbn-ui-framework/package.json b/packages/kbn-ui-framework/package.json index a4f23dd19da769..b4d9d3dfee03f6 100644 --- a/packages/kbn-ui-framework/package.json +++ b/packages/kbn-ui-framework/package.json @@ -30,7 +30,7 @@ "enzyme-adapter-react-16": "^1.9.1" }, "devDependencies": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.5.5", "@elastic/eui": "0.0.55", "@kbn/babel-preset": "1.0.0", "autoprefixer": "9.6.1", @@ -38,7 +38,7 @@ "brace": "0.11.1", "chalk": "^2.4.2", "chokidar": "3.2.1", - "core-js": "^3.5.0", + "core-js": "^3.2.1", "css-loader": "^2.1.1", "expose-loader": "^0.7.5", "file-loader": "^4.2.0", diff --git a/x-pack/package.json b/x-pack/package.json index 6413508976094d..2230bc4857cbe7 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -172,9 +172,9 @@ "yargs": "4.8.1" }, "dependencies": { - "@babel/core": "^7.7.5", - "@babel/register": "^7.7.4", - "@babel/runtime": "^7.7.6", + "@babel/core": "^7.5.5", + "@babel/register": "^7.7.0", + "@babel/runtime": "^7.5.5", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "1.0.5", "@elastic/eui": "17.0.0", diff --git a/yarn.lock b/yarn.lock index 6b0259f52e3314..6b69ccfcf8d2b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,21 +2,22 @@ # yarn lockfile v1 -"@babel/cli@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.7.5.tgz#25702cc65418efc06989af3727897b9f4c8690b6" - integrity sha512-y2YrMGXM3NUyu1Myg0pxg+Lx6g8XhEyvLHYNRwTBV6fDek3H7Io6b7N/LXscLs4HWn4HxMdy7f2rM1rTMp2mFg== +"@babel/cli@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.5.5.tgz#bdb6d9169e93e241a08f5f7b0265195bf38ef5ec" + integrity sha512-UHI+7pHv/tk9g6WXQKYz+kmXTI77YtuY3vqC59KIqcoWEjsJJSG6rAxKaLsgj3LDyadsPrCB929gVOKM6Hui0w== dependencies: - commander "^4.0.1" + commander "^2.8.1" convert-source-map "^1.1.0" fs-readdir-recursive "^1.1.0" glob "^7.0.0" lodash "^4.17.13" - make-dir "^2.1.0" + mkdirp "^0.5.1" + output-file-sync "^2.0.0" slash "^2.0.0" source-map "^0.5.0" optionalDependencies: - chokidar "^2.1.8" + chokidar "^2.0.4" "@babel/code-frame@7.5.5", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": version "7.5.5" @@ -25,7 +26,7 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@7.5.5", "@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.4.3": +"@babel/core@7.5.5", "@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.4.3", "@babel/core@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.5.tgz#17b2686ef0d6bc58f963dddd68ab669755582c30" integrity sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg== @@ -65,26 +66,6 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.5.tgz#ae1323cd035b5160293307f50647e83f8ba62f7e" - integrity sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.4" - "@babel/helpers" "^7.7.4" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - "@babel/generator@^7.0.0", "@babel/generator@^7.4.0", "@babel/generator@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.5.tgz#873a7f936a3c89491b43536d12245b626664e3cf" @@ -490,15 +471,6 @@ "@babel/traverse" "^7.6.0" "@babel/types" "^7.6.0" -"@babel/helpers@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302" - integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg== - dependencies: - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/highlight@^7.0.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" @@ -528,7 +500,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81" integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A== -"@babel/parser@^7.7.4", "@babel/parser@^7.7.5": +"@babel/parser@^7.7.4": version "7.7.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71" integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig== @@ -551,7 +523,7 @@ "@babel/helper-remap-async-to-generator" "^7.7.4" "@babel/plugin-syntax-async-generators" "^7.7.4" -"@babel/plugin-proposal-class-properties@7.5.5": +"@babel/plugin-proposal-class-properties@7.5.5", "@babel/plugin-proposal-class-properties@^7.5.1", "@babel/plugin-proposal-class-properties@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz#a974cfae1e37c3110e71f3c6a2e48b8e71958cd4" integrity sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A== @@ -559,7 +531,7 @@ "@babel/helper-create-class-features-plugin" "^7.5.5" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-proposal-class-properties@^7.7.0", "@babel/plugin-proposal-class-properties@^7.7.4": +"@babel/plugin-proposal-class-properties@^7.7.0": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.4.tgz#2f964f0cb18b948450362742e33e15211e77c2ba" integrity sha512-EcuXeV4Hv1X3+Q1TsuOmyyxeTRiSqurGJ26+I/FW1WbymmRRapVORm6x1Zl3iDIHyRxEs+VXWp6qnlcfcJSbbw== @@ -608,13 +580,13 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.7.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.7.4.tgz#7db302c83bc30caa89e38fee935635ef6bd11c28" - integrity sha512-TbYHmr1Gl1UC7Vo2HVuj/Naci5BEGNZ0AJhzqD2Vpr6QPFWpUmBRLrIDjedzx7/CShq0bRDS2gI4FIs77VHLVQ== +"@babel/plugin-proposal-nullish-coalescing-operator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.4.4.tgz#41c360d59481d88e0ce3a3f837df10121a769b39" + integrity sha512-Amph7Epui1Dh/xxUxS2+K22/MUi6+6JVTvy3P58tja3B6yKTSjwwx0/d83rF7551D6PVSSoplQb8GCwqec7HRw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.7.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.2.0" "@babel/plugin-proposal-object-rest-spread@7.5.5", "@babel/plugin-proposal-object-rest-spread@^7.5.5": version "7.5.5" @@ -648,13 +620,13 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" -"@babel/plugin-proposal-optional-chaining@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.7.5.tgz#f0835f044cef85b31071a924010a2a390add11d4" - integrity sha512-sOwFqT8JSchtJeDD+CjmWCaiFoLxY4Ps7NjvwHC/U7l4e9i5pTRNt8nDMIFSOUL+ncFbYSwruHM8WknYItWdXw== +"@babel/plugin-proposal-optional-chaining@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.6.0.tgz#e9bf1f9b9ba10c77c033082da75f068389041af8" + integrity sha512-kj4gkZ6qUggkprRq3Uh5KP8XnE1MdIO0J7MhdDX8+rAbB6dJ2UrensGIS+0NPZAaaJ1Vr0PN6oLUgXMU1uMcSg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-chaining" "^7.7.4" + "@babel/plugin-syntax-optional-chaining" "^7.2.0" "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.4.4" @@ -743,10 +715,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-nullish-coalescing-operator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.7.4.tgz#e53b751d0c3061b1ba3089242524b65a7a9da12b" - integrity sha512-XKh/yIRPiQTOeBg0QJjEus5qiSKucKAiApNtO1psqG7D17xmE+X2i5ZqBEuSvo0HRuyPaKaSN/Gy+Ha9KFQolw== +"@babel/plugin-syntax-nullish-coalescing-operator@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.2.0.tgz#f75083dfd5ade73e783db729bbd87e7b9efb7624" + integrity sha512-lRCEaKE+LTxDQtgbYajI04ddt6WW0WJq57xqkAZ+s11h4YgfRHhVA/Y2VhfPzzFD4qeLHWg32DMp9HooY4Kqlg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -778,10 +750,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-optional-chaining@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.7.4.tgz#c91fdde6de85d2eb8906daea7b21944c3610c901" - integrity sha512-2MqYD5WjZSbJdUagnJvIdSfkb/ucOC9/1fRJxm7GAxY6YQLWlUvkfxoNbUPcPLHJyetKUDQ4+yyuUyAoc0HriA== +"@babel/plugin-syntax-optional-chaining@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.2.0.tgz#a59d6ae8c167e7608eaa443fda9fa8fa6bf21dff" + integrity sha512-HtGCtvp5Uq/jH/WNUPkK6b7rufnCPLLlDAFN7cmACoIjaOOiXxUt3SswU5loHqrhtqTsa/WoLQ1OQ1AGuZqaWA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1325,7 +1297,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-runtime@7.5.5": +"@babel/plugin-transform-runtime@7.5.5", "@babel/plugin-transform-runtime@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.5.5.tgz#a6331afbfc59189d2135b2e09474457a8e3d28bc" integrity sha512-6Xmeidsun5rkwnGfMOp6/z9nSzWpHFNVr2Jx7kwoq4mVatQfQx5S56drBgEHF+XQbKOdIaOiMIINvp/kAwMN+w== @@ -1335,16 +1307,6 @@ resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-runtime@^7.7.6": - version "7.7.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.6.tgz#4f2b548c88922fb98ec1c242afd4733ee3e12f61" - integrity sha512-tajQY+YmXR7JjTwRvwL4HePqoL3DYxpYXIHKVvrOIvJmeHe2y1w4tz5qz9ObUDC9m76rCzIMPyn4eERuwA4a4A== - dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - resolve "^1.8.1" - semver "^5.5.1" - "@babel/plugin-transform-shorthand-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" @@ -1454,7 +1416,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/preset-env@7.5.5", "@babel/preset-env@^7.4.3": +"@babel/preset-env@7.5.5", "@babel/preset-env@^7.4.3", "@babel/preset-env@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.5.tgz#bc470b53acaa48df4b8db24a570d6da1fef53c9a" integrity sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A== @@ -1566,7 +1528,7 @@ js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/preset-env@^7.7.1", "@babel/preset-env@^7.7.6": +"@babel/preset-env@^7.7.1": version "7.7.6" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.6.tgz#39ac600427bbb94eec6b27953f1dfa1d64d457b2" integrity sha512-k5hO17iF/Q7tR9Jv8PdNBZWYW6RofxhnxKjBMc0nG4JTaWvOTiPoO/RLFwAKcA4FpmuBFm6jkoqaRJLGi0zdaQ== @@ -1669,10 +1631,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-typescript" "^7.7.4" -"@babel/register@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.7.4.tgz#45a4956471a9df3b012b747f5781cc084ee8f128" - integrity sha512-/fmONZqL6ZMl9KJUYajetCrID6m0xmL4odX7v+Xvoxcv0DdbP/oO0TWIeLUCHqczQ6L6njDMqmqHFy2cp3FFsA== +"@babel/register@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.7.0.tgz#4e23ecf840296ef79c605baaa5c89e1a2426314b" + integrity sha512-HV3GJzTvSoyOMWGYn2TAh6uL6g+gqKTgEZ99Q3+X9UURT1VPT/WcU46R61XftIc5rXytcOHZ4Z0doDlsjPomIg== dependencies: find-cache-dir "^2.0.0" lodash "^4.17.13" @@ -1718,7 +1680,7 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2": version "7.7.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f" integrity sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw== @@ -1839,7 +1801,7 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@babel/types@^7.7.2", "@babel/types@^7.7.4": +"@babel/types@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== @@ -3783,10 +3745,10 @@ "@types/babel__template" "*" "@types/babel__traverse" "*" -"@types/babel__core@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30" - integrity sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA== +"@types/babel__core@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f" + integrity sha512-cfCCrFmiGY/yq0NuKNxIQvZFy9kY/1immpSpTngOnyIbD4+eJOG5mxphhHDv3CHL9GltO4GcKr54kGBg3RNdbg== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -6809,13 +6771,13 @@ babel-plugin-emotion@^10.0.22, babel-plugin-emotion@^10.0.23: find-root "^1.1.0" source-map "^0.5.7" -babel-plugin-filter-imports@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-4.0.0.tgz#068f8da15236a96a9602c36dc6f4a6eeca70a4f4" - integrity sha512-jDLlxI8QnfKd7PtieH6pl4tZJzymzfCDCPGdTq/grgbiYAikwDPp/oL0IlFJn0HQjLpcLkyYhPKkUVneRESw5w== +babel-plugin-filter-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-3.0.0.tgz#a849683837ad29960da17492fb32789ab6b09a11" + integrity sha512-p/chjzVTgCxUqyLM0q/pfWVZS7IJTwGQMwNg0LOvuQpKiTftQgZDtkGB8XvETnUw19rRcL7bJCTopSwibTN2tA== dependencies: - "@babel/types" "^7.7.2" - lodash "^4.17.15" + "@babel/types" "^7.4.0" + lodash "^4.17.11" babel-plugin-istanbul@^5.1.0: version "5.1.1" @@ -6968,10 +6930,10 @@ babel-plugin-syntax-jsx@^6.18.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= -babel-plugin-transform-define@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-2.0.0.tgz#79c3536635f899aabaf830b194b25519465675a4" - integrity sha512-0dv5RNRUlUKxGYIIErl01lpvi8b7W2R04Qcl1mCj70ahwZcgiklfXnFlh4FGnRh6aayCfSZKdhiMryVzcq5Dmg== +babel-plugin-transform-define@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.1.tgz#b21b7bad3b84cf8e3f07cdc8c660b99cbbc01213" + integrity sha512-JXZ1xE9jIbKCGYZ4wbSMPSI5mdS4DRLi5+SkTHgZqWn5YIf/EucykkzUsPmzJlpkX8fsMVdLnA5vt/LvT97Zbg== dependencies: lodash "^4.17.11" traverse "0.6.6" @@ -8221,9 +8183,9 @@ caniuse-lite@^1.0.30000984: integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw== caniuse-lite@^1.0.30001015: - version "1.0.30001015" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz#15a7ddf66aba786a71d99626bc8f2b91c6f0f5f0" - integrity sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ== + version "1.0.30001016" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz#16ea48d7d6e8caf3cad3295c2d746fe38c4e7f66" + integrity sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA== capture-exit@^2.0.0: version "2.0.0" @@ -9128,11 +9090,6 @@ commander@^3.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.0.tgz#0641ea00838c7a964627f04cddc336a2deddd60a" integrity sha512-pl3QrGOBa9RZaslQiqnnKX2J068wcQw7j9AIaBQ9/JEp5RY6je4jKTImg0Bd+rpoONSe7GUFSgkxLeo17m3Pow== -commander@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.0.1.tgz#b67622721785993182e807f4883633e6401ba53c" - integrity sha512-IPF4ouhCP+qdlcmCedhxX4xiGBPyigb8v5NeUp+0LyhwLgxMqyp3S0vl7TAPfS/hiP7FC3caI/PB9lTmP8r1NA== - commander@~2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" @@ -9444,13 +9401,6 @@ convert-source-map@^1.5.1, convert-source-map@^1.6.0: dependencies: safe-buffer "~5.1.1" -convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - convex-hull@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/convex-hull/-/convex-hull-1.0.3.tgz#20a3aa6ce87f4adea2ff7d17971c9fc1c67e1fff" @@ -9574,12 +9524,12 @@ core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.1, core-js@^2.5.3, resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== -core-js@^3.0.1, core-js@^3.0.4: +core-js@^3.0.1, core-js@^3.0.4, core-js@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.2.1.tgz#cd41f38534da6cc59f7db050fe67307de9868b09" integrity sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw== -core-js@^3.4.1, core-js@^3.5.0: +core-js@^3.4.1: version "3.5.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.5.0.tgz#66df8e49be4bd775e6f952a9d083b756ad41c1ed" integrity sha512-Ifh3kj78gzQ7NAoJXeTu+XwzDld0QRIwjBLRqAMhuLhP3d2Av5wmgE9ycfnvK6NAEjTkQ1sDPeoEZAWO3Hx1Uw== @@ -21828,6 +21778,15 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +output-file-sync@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-2.0.1.tgz#f53118282f5f553c2799541792b723a4c71430c0" + integrity sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ== + dependencies: + graceful-fs "^4.1.11" + is-plain-obj "^1.1.0" + mkdirp "^0.5.1" + p-any@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-any/-/p-any-1.1.0.tgz#1d03835c7eed1e34b8e539c47b7b60d0d015d4e1" From ccdd84a00dc86fdb569457e747d03b9f2877f0e8 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:25:28 -0700 Subject: [PATCH 14/60] Revert "Update dependency execa to ^3.4.0 (#53072)" This reverts commit ad6a07583b4958e8fa8b412be91dc1cebb28ebad. --- package.json | 2 +- packages/kbn-dev-utils/package.json | 2 +- packages/kbn-es/package.json | 2 +- packages/kbn-plugin-generator/package.json | 2 +- packages/kbn-plugin-helpers/package.json | 2 +- packages/kbn-pm/dist/index.js | 4 ++-- packages/kbn-pm/package.json | 2 +- x-pack/package.json | 2 +- yarn.lock | 8 ++++---- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index b240a33cd84444..07f25b8c4335b2 100644 --- a/package.json +++ b/package.json @@ -167,7 +167,7 @@ "elasticsearch": "^16.5.0", "elasticsearch-browser": "^16.5.0", "encode-uri-query": "1.0.1", - "execa": "^3.4.0", + "execa": "^3.2.0", "expiry-js": "0.1.7", "fast-deep-equal": "^3.1.1", "file-loader": "4.2.0", diff --git a/packages/kbn-dev-utils/package.json b/packages/kbn-dev-utils/package.json index 89b358c5b0b3e7..09753afeb120f4 100644 --- a/packages/kbn-dev-utils/package.json +++ b/packages/kbn-dev-utils/package.json @@ -12,7 +12,7 @@ "dependencies": { "chalk": "^2.4.2", "dedent": "^0.7.0", - "execa": "^3.4.0", + "execa": "^3.2.0", "exit-hook": "^2.2.0", "getopts": "^2.2.5", "moment": "^2.24.0", diff --git a/packages/kbn-es/package.json b/packages/kbn-es/package.json index adc81e3a6cc367..ccc396b5522e29 100644 --- a/packages/kbn-es/package.json +++ b/packages/kbn-es/package.json @@ -11,7 +11,7 @@ "chalk": "^2.4.2", "dedent": "^0.7.0", "del": "^5.1.0", - "execa": "^3.4.0", + "execa": "^3.2.0", "getopts": "^2.2.4", "glob": "^7.1.2", "node-fetch": "^2.6.0", diff --git a/packages/kbn-plugin-generator/package.json b/packages/kbn-plugin-generator/package.json index 8dafa361994178..ac98a0e675fb18 100644 --- a/packages/kbn-plugin-generator/package.json +++ b/packages/kbn-plugin-generator/package.json @@ -6,7 +6,7 @@ "dependencies": { "chalk": "^2.4.2", "dedent": "^0.7.0", - "execa": "^3.4.0", + "execa": "^3.2.0", "getopts": "^2.2.4", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index 20e2c6a7e58de6..68af0aa791c8e0 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -17,7 +17,7 @@ "argv-split": "^2.0.1", "commander": "^3.0.0", "del": "^5.1.0", - "execa": "^3.4.0", + "execa": "^3.2.0", "globby": "^8.0.1", "gulp-babel": "^8.0.0", "gulp-rename": "1.4.0", diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 72c3457ff16892..aea85c13d7f325 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -19198,8 +19198,8 @@ const handleArgs = (file, args, options = {}) => { reject: true, cleanup: true, all: false, - windowsHide: true, - ...options + ...options, + windowsHide: true }; options.env = getEnv(options); diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index 032bae75a35fa5..ead454410a8b3e 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -40,7 +40,7 @@ "cpy": "^7.3.0", "dedent": "^0.7.0", "del": "^5.1.0", - "execa": "^3.4.0", + "execa": "^3.2.0", "getopts": "^2.2.4", "glob": "^7.1.2", "globby": "^8.0.1", diff --git a/x-pack/package.json b/x-pack/package.json index 2230bc4857cbe7..a1c58bd5afa5a8 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -122,7 +122,7 @@ "enzyme-adapter-react-16": "^1.15.1", "enzyme-adapter-utils": "^1.12.1", "enzyme-to-json": "^3.4.3", - "execa": "^3.4.0", + "execa": "^3.2.0", "fancy-log": "^1.3.2", "fetch-mock": "^7.3.9", "graphql-code-generator": "^0.18.2", diff --git a/yarn.lock b/yarn.lock index 6b69ccfcf8d2b9..fa891f2e186ab5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12553,10 +12553,10 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" - integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== +execa@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-3.2.0.tgz#18326b79c7ab7fbd6610fd900c1b9e95fa48f90a" + integrity sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw== dependencies: cross-spawn "^7.0.0" get-stream "^5.0.0" From 1b5e385a7a281f4e26d4557557fea43ebf05aa22 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:27:04 -0700 Subject: [PATCH 15/60] Revert "Update storybook related packages to ^5.2.8 (#52687)" This reverts commit f8fd5b5defa67783bd0be32cf1333f3a46adfb45. --- x-pack/package.json | 12 +- yarn.lock | 854 ++++++++------------------------------------ 2 files changed, 150 insertions(+), 716 deletions(-) diff --git a/x-pack/package.json b/x-pack/package.json index a1c58bd5afa5a8..675040ee9fe1ba 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -35,13 +35,13 @@ "@kbn/test": "1.0.0", "@kbn/utility-types": "1.0.0", "@mattapperson/slapshot": "1.4.0", - "@storybook/addon-actions": "^5.2.8", + "@storybook/addon-actions": "^5.2.6", "@storybook/addon-console": "^1.2.1", - "@storybook/addon-info": "^5.2.8", - "@storybook/addon-knobs": "^5.2.8", - "@storybook/addon-storyshots": "^5.2.8", - "@storybook/react": "^5.2.8", - "@storybook/theming": "^5.2.8", + "@storybook/addon-info": "^5.2.6", + "@storybook/addon-knobs": "^5.2.6", + "@storybook/addon-storyshots": "^5.2.6", + "@storybook/react": "^5.2.6", + "@storybook/theming": "^5.2.6", "@testing-library/react": "^9.3.2", "@testing-library/jest-dom": "4.2.0", "@types/angular": "^1.6.56", diff --git a/yarn.lock b/yarn.lock index fa891f2e186ab5..4d33241f2ef6fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -114,13 +114,6 @@ dependencies: "@babel/types" "^7.0.0" -"@babel/helper-annotate-as-pure@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz#bb3faf1e74b74bd547e867e48f551fa6b098b6ce" - integrity sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og== - dependencies: - "@babel/types" "^7.7.4" - "@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" @@ -129,14 +122,6 @@ "@babel/helper-explode-assignable-expression" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz#5f73f2b28580e224b5b9bd03146a4015d6217f5f" - integrity sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/helper-builder-react-jsx@^7.3.0": version "7.3.0" resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz#a1ac95a5d2b3e88ae5e54846bf462eeb81b318a4" @@ -162,15 +147,6 @@ "@babel/traverse" "^7.4.4" "@babel/types" "^7.4.4" -"@babel/helper-call-delegate@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz#621b83e596722b50c0066f9dc37d3232e461b801" - integrity sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA== - dependencies: - "@babel/helper-hoist-variables" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/helper-create-class-features-plugin@^7.4.4", "@babel/helper-create-class-features-plugin@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.5.tgz#401f302c8ddbc0edd36f7c6b2887d8fa1122e5a4" @@ -195,14 +171,6 @@ "@babel/helper-replace-supers" "^7.7.4" "@babel/helper-split-export-declaration" "^7.7.4" -"@babel/helper-create-regexp-features-plugin@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz#6d5762359fd34f4da1500e4cff9955b5299aaf59" - integrity sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A== - dependencies: - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.6.0" - "@babel/helper-define-map@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz#3dec32c2046f37e09b28c93eb0b103fd2a25d369" @@ -212,15 +180,6 @@ "@babel/types" "^7.5.5" lodash "^4.17.13" -"@babel/helper-define-map@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz#2841bf92eb8bd9c906851546fe6b9d45e162f176" - integrity sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg== - dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/types" "^7.7.4" - lodash "^4.17.13" - "@babel/helper-explode-assignable-expression@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" @@ -229,14 +188,6 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-explode-assignable-expression@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz#fa700878e008d85dc51ba43e9fb835cddfe05c84" - integrity sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg== - dependencies: - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/helper-function-name@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" @@ -276,13 +227,6 @@ dependencies: "@babel/types" "^7.4.4" -"@babel/helper-hoist-variables@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz#612384e3d823fdfaaf9fce31550fe5d4db0f3d12" - integrity sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ== - dependencies: - "@babel/types" "^7.7.4" - "@babel/helper-member-expression-to-functions@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590" @@ -304,13 +248,6 @@ dependencies: "@babel/types" "^7.0.0" -"@babel/helper-module-imports@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz#e5a92529f8888bf319a6376abfbd1cebc491ad91" - integrity sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ== - dependencies: - "@babel/types" "^7.7.4" - "@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz#f84ff8a09038dcbca1fd4355661a500937165b4a" @@ -323,18 +260,6 @@ "@babel/types" "^7.5.5" lodash "^4.17.13" -"@babel/helper-module-transforms@^7.7.4", "@babel/helper-module-transforms@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz#d044da7ffd91ec967db25cd6748f704b6b244835" - integrity sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw== - dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-simple-access" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" - lodash "^4.17.13" - "@babel/helper-optimise-call-expression@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" @@ -372,17 +297,6 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-remap-async-to-generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz#c68c2407350d9af0e061ed6726afb4fff16d0234" - integrity sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-wrap-function" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/helper-replace-supers@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2" @@ -411,14 +325,6 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-simple-access@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz#a169a0adb1b5f418cfc19f22586b2ebf58a9a294" - integrity sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A== - dependencies: - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/helper-split-export-declaration@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" @@ -443,16 +349,6 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" -"@babel/helper-wrap-function@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" - integrity sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg== - dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/helpers@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.5.tgz#63908d2a73942229d1e6685bc2a0e730dde3b75e" @@ -514,16 +410,7 @@ "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-syntax-async-generators" "^7.2.0" -"@babel/plugin-proposal-async-generator-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz#0351c5ac0a9e927845fffd5b82af476947b7ce6d" - integrity sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" - "@babel/plugin-syntax-async-generators" "^7.7.4" - -"@babel/plugin-proposal-class-properties@7.5.5", "@babel/plugin-proposal-class-properties@^7.5.1", "@babel/plugin-proposal-class-properties@^7.5.5": +"@babel/plugin-proposal-class-properties@7.5.5", "@babel/plugin-proposal-class-properties@^7.3.3", "@babel/plugin-proposal-class-properties@^7.5.1", "@babel/plugin-proposal-class-properties@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz#a974cfae1e37c3110e71f3c6a2e48b8e71958cd4" integrity sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A== @@ -531,14 +418,6 @@ "@babel/helper-create-class-features-plugin" "^7.5.5" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-proposal-class-properties@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.4.tgz#2f964f0cb18b948450362742e33e15211e77c2ba" - integrity sha512-EcuXeV4Hv1X3+Q1TsuOmyyxeTRiSqurGJ26+I/FW1WbymmRRapVORm6x1Zl3iDIHyRxEs+VXWp6qnlcfcJSbbw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-decorators@7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.4.tgz#de9b2a1a8ab0196f378e2a82f10b6e2a36f21cc0" @@ -556,14 +435,6 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-dynamic-import" "^7.2.0" -"@babel/plugin-proposal-dynamic-import@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz#dde64a7f127691758cbfed6cf70de0fa5879d52d" - integrity sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.7.4" - "@babel/plugin-proposal-json-strings@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" @@ -572,14 +443,6 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.2.0" -"@babel/plugin-proposal-json-strings@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz#7700a6bfda771d8dc81973249eac416c6b4c697d" - integrity sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.7.4" - "@babel/plugin-proposal-nullish-coalescing-operator@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.4.4.tgz#41c360d59481d88e0ce3a3f837df10121a769b39" @@ -588,7 +451,7 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@7.5.5", "@babel/plugin-proposal-object-rest-spread@^7.5.5": +"@babel/plugin-proposal-object-rest-spread@7.5.5", "@babel/plugin-proposal-object-rest-spread@^7.3.2", "@babel/plugin-proposal-object-rest-spread@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58" integrity sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw== @@ -596,14 +459,6 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.6.2", "@babel/plugin-proposal-object-rest-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz#cc57849894a5c774214178c8ab64f6334ec8af71" - integrity sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.7.4" - "@babel/plugin-proposal-optional-catch-binding@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" @@ -612,14 +467,6 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" -"@babel/plugin-proposal-optional-catch-binding@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz#ec21e8aeb09ec6711bc0a39ca49520abee1de379" - integrity sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" - "@babel/plugin-proposal-optional-chaining@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.6.0.tgz#e9bf1f9b9ba10c77c033082da75f068389041af8" @@ -637,14 +484,6 @@ "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" -"@babel/plugin-proposal-unicode-property-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz#7c239ccaf09470dbe1d453d50057460e84517ebb" - integrity sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-async-generators@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" @@ -652,13 +491,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-async-generators@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz#331aaf310a10c80c44a66b238b6e49132bd3c889" - integrity sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-decorators@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz#c50b1b957dcc69e4b1127b65e1c33eef61570c1b" @@ -673,13 +505,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-dynamic-import@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec" - integrity sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-flow@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c" @@ -694,13 +519,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-json-strings@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" - integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-jsx@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz#0b85a3b4bc7cdf4cc4b8bf236335b907ca22e7c7" @@ -729,13 +547,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-object-rest-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" - integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" @@ -743,13 +554,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-optional-catch-binding@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz#a3e38f59f4b6233867b4a92dcb0ee05b2c334aa6" - integrity sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-chaining@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.2.0.tgz#a59d6ae8c167e7608eaa443fda9fa8fa6bf21dff" @@ -757,13 +561,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-top-level-await@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz#bd7d8fa7b9fee793a36e4027fd6dd1aa32f946da" - integrity sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript@^7.2.0": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" @@ -785,13 +582,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-arrow-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" - integrity sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-async-to-generator@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" @@ -801,15 +591,6 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-remap-async-to-generator" "^7.1.0" -"@babel/plugin-transform-async-to-generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz#694cbeae6d613a34ef0292713fa42fb45c4470ba" - integrity sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg== - dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" - "@babel/plugin-transform-block-scoped-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" @@ -817,13 +598,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-block-scoped-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz#d0d9d5c269c78eaea76227ace214b8d01e4d837b" - integrity sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-block-scoping@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.5.5.tgz#a35f395e5402822f10d2119f6f8e045e3639a2ce" @@ -840,14 +614,6 @@ "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.13" -"@babel/plugin-transform-block-scoping@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz#200aad0dcd6bb80372f94d9e628ea062c58bf224" - integrity sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.13" - "@babel/plugin-transform-classes@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz#d094299d9bd680a14a2a0edae38305ad60fb4de9" @@ -862,20 +628,6 @@ "@babel/helper-split-export-declaration" "^7.4.4" globals "^11.1.0" -"@babel/plugin-transform-classes@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz#c92c14be0a1399e15df72667067a8f510c9400ec" - integrity sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-define-map" "^7.7.4" - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-optimise-call-expression" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - globals "^11.1.0" - "@babel/plugin-transform-computed-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" @@ -883,13 +635,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-computed-properties@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz#e856c1628d3238ffe12d668eb42559f79a81910d" - integrity sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-destructuring@7.5.0", "@babel/plugin-transform-destructuring@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a" @@ -904,13 +649,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-destructuring@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz#2b713729e5054a1135097b6a67da1b6fe8789267" - integrity sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" @@ -920,14 +658,6 @@ "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" -"@babel/plugin-transform-dotall-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz#f7ccda61118c5b7a2599a72d5e3210884a021e96" - integrity sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-duplicate-keys@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" @@ -935,13 +665,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-duplicate-keys@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz#3d21731a42e3f598a73835299dd0169c3b90ac91" - integrity sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" @@ -950,14 +673,6 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-exponentiation-operator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz#dd30c0191e3a1ba19bcc7e389bdfddc0729d5db9" - integrity sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-flow-strip-types@7.4.4", "@babel/plugin-transform-flow-strip-types@^7.0.0": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.4.tgz#d267a081f49a8705fc9146de0768c6b58dccd8f7" @@ -973,13 +688,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-for-of@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" - integrity sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-function-name@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" @@ -988,14 +696,6 @@ "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-function-name@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz#75a6d3303d50db638ff8b5385d12451c865025b1" - integrity sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g== - dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-literals@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" @@ -1003,13 +703,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz#27fe87d2b5017a2a5a34d1c41a6b9f6a6262643e" - integrity sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-member-expression-literals@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d" @@ -1017,13 +710,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-member-expression-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz#aee127f2f3339fc34ce5e3055d7ffbf7aa26f19a" - integrity sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-modules-amd@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" @@ -1033,15 +719,6 @@ "@babel/helper-plugin-utils" "^7.0.0" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-amd@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz#39e0fb717224b59475b306402bb8eedab01e729c" - integrity sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ== - dependencies: - "@babel/helper-module-transforms" "^7.7.5" - "@babel/helper-plugin-utils" "^7.0.0" - babel-plugin-dynamic-import-node "^2.3.0" - "@babel/plugin-transform-modules-commonjs@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74" @@ -1062,16 +739,6 @@ "@babel/helper-simple-access" "^7.1.0" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-commonjs@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz#1d27f5eb0bcf7543e774950e5b2fa782e637b345" - integrity sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q== - dependencies: - "@babel/helper-module-transforms" "^7.7.5" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.7.4" - babel-plugin-dynamic-import-node "^2.3.0" - "@babel/plugin-transform-modules-systemjs@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249" @@ -1081,15 +748,6 @@ "@babel/helper-plugin-utils" "^7.0.0" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-systemjs@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz#cd98152339d3e763dfe838b7d4273edaf520bb30" - integrity sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw== - dependencies: - "@babel/helper-hoist-variables" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - babel-plugin-dynamic-import-node "^2.3.0" - "@babel/plugin-transform-modules-umd@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" @@ -1098,14 +756,6 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-modules-umd@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz#1027c355a118de0aae9fee00ad7813c584d9061f" - integrity sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw== - dependencies: - "@babel/helper-module-transforms" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-named-capturing-groups-regex@^7.4.5": version "7.4.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz#9d269fd28a370258199b4294736813a60bbdd106" @@ -1120,13 +770,6 @@ dependencies: regexp-tree "^0.1.13" -"@babel/plugin-transform-named-capturing-groups-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz#fb3bcc4ee4198e7385805007373d6b6f42c98220" - integrity sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/plugin-transform-new-target@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" @@ -1134,13 +777,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-new-target@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz#4a0753d2d60639437be07b592a9e58ee00720167" - integrity sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-object-super@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9" @@ -1149,14 +785,6 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.5.5" -"@babel/plugin-transform-object-super@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz#48488937a2d586c0148451bf51af9d7dda567262" - integrity sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" - "@babel/plugin-transform-parameters@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" @@ -1166,15 +794,6 @@ "@babel/helper-get-function-arity" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-parameters@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz#da4555c97f39b51ac089d31c7380f03bca4075ce" - integrity sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw== - dependencies: - "@babel/helper-call-delegate" "^7.7.4" - "@babel/helper-get-function-arity" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-property-literals@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905" @@ -1182,14 +801,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-property-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz#2388d6505ef89b266103f450f9167e6bd73f98c2" - integrity sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-react-constant-elements@^7.0.0": +"@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.5.0.tgz#4d6ae4033bc38f8a65dfca2b6235c44522a422fc" integrity sha512-c5Ba8cpybZFp1Izkf2sWGuNjOxoQ32tFgBvvYvwGhi4+9f6vGiSK9Gex4uVuO/Va6YJFu41aAh1MzMjUWkp0IQ== @@ -1197,14 +809,6 @@ "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-react-constant-elements@^7.6.3": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.7.4.tgz#499cf732a21ffd62cc4b0016e27c3906097f8982" - integrity sha512-U6XkHZ8RnmeEb8jBUOpeo6oFka5RhLgxAVvK4/fBbwoYlsHQYLb8I37ymTPDVsrWjqb94+hueuWQA/1OAA4rAQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-react-display-name@7.2.0", "@babel/plugin-transform-react-display-name@^7.0.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz#ebfaed87834ce8dc4279609a4f0c324c156e3eb0" @@ -1276,13 +880,6 @@ dependencies: regenerator-transform "^0.14.0" -"@babel/plugin-transform-regenerator@^7.7.5": - version "7.7.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz#3a8757ee1a2780f390e89f246065ecf59c26fce9" - integrity sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw== - dependencies: - regenerator-transform "^0.14.0" - "@babel/plugin-transform-reserved-words@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" @@ -1290,13 +887,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-reserved-words@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz#6a7cf123ad175bb5c69aec8f6f0770387ed3f1eb" - integrity sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-runtime@7.5.5", "@babel/plugin-transform-runtime@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.5.5.tgz#a6331afbfc59189d2135b2e09474457a8e3d28bc" @@ -1314,13 +904,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-shorthand-properties@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz#74a0a9b2f6d67a684c6fbfd5f0458eb7ba99891e" - integrity sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-spread@^7.2.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" @@ -1328,13 +911,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz#aa673b356fe6b7e70d69b6e33a17fef641008578" - integrity sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-sticky-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" @@ -1343,14 +919,6 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" -"@babel/plugin-transform-sticky-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz#ffb68c05090c30732076b1285dc1401b404a123c" - integrity sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" - "@babel/plugin-transform-template-literals@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" @@ -1359,14 +927,6 @@ "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-template-literals@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz#1eb6411736dd3fe87dbd20cc6668e5121c17d604" - integrity sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typeof-symbol@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" @@ -1374,13 +934,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-typeof-symbol@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz#3174626214f2d6de322882e498a38e8371b2140e" - integrity sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typescript@^7.3.2": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.5.5.tgz#6d862766f09b2da1cb1f7d505fe2aedab6b7d4b8" @@ -1408,15 +961,7 @@ "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" -"@babel/plugin-transform-unicode-regex@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz#a3c0f65b117c4c81c5b6484f2a5e7b95346b83ae" - integrity sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/preset-env@7.5.5", "@babel/preset-env@^7.4.3", "@babel/preset-env@^7.5.5": +"@babel/preset-env@7.5.5", "@babel/preset-env@^7.4.3", "@babel/preset-env@^7.4.5", "@babel/preset-env@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.5.tgz#bc470b53acaa48df4b8db24a570d6da1fef53c9a" integrity sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A== @@ -1528,63 +1073,6 @@ js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/preset-env@^7.7.1": - version "7.7.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.6.tgz#39ac600427bbb94eec6b27953f1dfa1d64d457b2" - integrity sha512-k5hO17iF/Q7tR9Jv8PdNBZWYW6RofxhnxKjBMc0nG4JTaWvOTiPoO/RLFwAKcA4FpmuBFm6jkoqaRJLGi0zdaQ== - dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.7.4" - "@babel/plugin-proposal-dynamic-import" "^7.7.4" - "@babel/plugin-proposal-json-strings" "^7.7.4" - "@babel/plugin-proposal-object-rest-spread" "^7.7.4" - "@babel/plugin-proposal-optional-catch-binding" "^7.7.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.7.4" - "@babel/plugin-syntax-async-generators" "^7.7.4" - "@babel/plugin-syntax-dynamic-import" "^7.7.4" - "@babel/plugin-syntax-json-strings" "^7.7.4" - "@babel/plugin-syntax-object-rest-spread" "^7.7.4" - "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" - "@babel/plugin-syntax-top-level-await" "^7.7.4" - "@babel/plugin-transform-arrow-functions" "^7.7.4" - "@babel/plugin-transform-async-to-generator" "^7.7.4" - "@babel/plugin-transform-block-scoped-functions" "^7.7.4" - "@babel/plugin-transform-block-scoping" "^7.7.4" - "@babel/plugin-transform-classes" "^7.7.4" - "@babel/plugin-transform-computed-properties" "^7.7.4" - "@babel/plugin-transform-destructuring" "^7.7.4" - "@babel/plugin-transform-dotall-regex" "^7.7.4" - "@babel/plugin-transform-duplicate-keys" "^7.7.4" - "@babel/plugin-transform-exponentiation-operator" "^7.7.4" - "@babel/plugin-transform-for-of" "^7.7.4" - "@babel/plugin-transform-function-name" "^7.7.4" - "@babel/plugin-transform-literals" "^7.7.4" - "@babel/plugin-transform-member-expression-literals" "^7.7.4" - "@babel/plugin-transform-modules-amd" "^7.7.5" - "@babel/plugin-transform-modules-commonjs" "^7.7.5" - "@babel/plugin-transform-modules-systemjs" "^7.7.4" - "@babel/plugin-transform-modules-umd" "^7.7.4" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.4" - "@babel/plugin-transform-new-target" "^7.7.4" - "@babel/plugin-transform-object-super" "^7.7.4" - "@babel/plugin-transform-parameters" "^7.7.4" - "@babel/plugin-transform-property-literals" "^7.7.4" - "@babel/plugin-transform-regenerator" "^7.7.5" - "@babel/plugin-transform-reserved-words" "^7.7.4" - "@babel/plugin-transform-shorthand-properties" "^7.7.4" - "@babel/plugin-transform-spread" "^7.7.4" - "@babel/plugin-transform-sticky-regex" "^7.7.4" - "@babel/plugin-transform-template-literals" "^7.7.4" - "@babel/plugin-transform-typeof-symbol" "^7.7.4" - "@babel/plugin-transform-unicode-regex" "^7.7.4" - "@babel/types" "^7.7.4" - browserslist "^4.6.0" - core-js-compat "^3.4.7" - invariant "^2.2.2" - js-levenshtein "^1.1.3" - semver "^5.5.0" - "@babel/preset-flow@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.0.0.tgz#afd764835d9535ec63d8c7d4caf1c06457263da2" @@ -1604,7 +1092,7 @@ "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" -"@babel/preset-react@^7.7.0", "@babel/preset-react@^7.7.4": +"@babel/preset-react@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.7.4.tgz#3fe2ea698d8fb536d8e7881a592c3c1ee8bf5707" integrity sha512-j+vZtg0/8pQr1H8wKoaJyGL2IEk3rG/GIvua7Sec7meXVIvGycihlGMx5xcU00kqCJbwzHs18xTu3YfREOqQ+g== @@ -3111,17 +2599,17 @@ "@types/node" ">=8.9.0" axios "^0.18.0" -"@storybook/addon-actions@^5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.2.8.tgz#f63c6e1afb59e94ca1ebc776b7cad9b815e7419e" - integrity sha512-hadk+UaU6upOW0g447RfLRrnXRgE2rjRVk5sT8mVxBMj032NnwUd7ie/BZwy1yg5B8oFtpkgQYwqhPtoO2xBaQ== - dependencies: - "@storybook/addons" "5.2.8" - "@storybook/api" "5.2.8" - "@storybook/client-api" "5.2.8" - "@storybook/components" "5.2.8" - "@storybook/core-events" "5.2.8" - "@storybook/theming" "5.2.8" +"@storybook/addon-actions@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.2.6.tgz#4fe411fc3bdb1d44058f23fbc8eb8d1bac29d521" + integrity sha512-CwTJPqe3NcEU7oqS5KoiCX9FXYmI2Dyp1Sh6r90JmXZ8B49ZXm6BDLX0gS3TooD6/AcdU8xdBcSvN0CkxQ5QGA== + dependencies: + "@storybook/addons" "5.2.6" + "@storybook/api" "5.2.6" + "@storybook/client-api" "5.2.6" + "@storybook/components" "5.2.6" + "@storybook/core-events" "5.2.6" + "@storybook/theming" "5.2.6" core-js "^3.0.1" fast-deep-equal "^2.0.1" global "^4.3.2" @@ -3138,15 +2626,15 @@ dependencies: global "^4.3.2" -"@storybook/addon-info@^5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/addon-info/-/addon-info-5.2.8.tgz#bf29741c21c16c85f4a7007606e8afa3eb77965c" - integrity sha512-iY8malDF6yayLfpiffMwDXOWeeoXdRbxse1f+kNHK4aVEUXLyh+uiogPhO8dzVDy8dQw1LP9C7xKZe2Dls59kw== +"@storybook/addon-info@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/addon-info/-/addon-info-5.2.6.tgz#25c8405ded9e20b1bf3b607d235601b087a73a5f" + integrity sha512-2ct91Zf14Be5HZ77szPpJK4Fvy4D/haQtziCfv9UKZXaBm7Rz9vKPuM3uCcfMywh1eMunhhluhJ/3bxmttHXAw== dependencies: - "@storybook/addons" "5.2.8" - "@storybook/client-logger" "5.2.8" - "@storybook/components" "5.2.8" - "@storybook/theming" "5.2.8" + "@storybook/addons" "5.2.6" + "@storybook/client-logger" "5.2.6" + "@storybook/components" "5.2.6" + "@storybook/theming" "5.2.6" core-js "^3.0.1" global "^4.3.2" jsx-to-string "^1.4.0" @@ -3160,17 +2648,17 @@ react-lifecycles-compat "^3.0.4" util-deprecate "^1.0.2" -"@storybook/addon-knobs@^5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-5.2.8.tgz#e0d03823969921a0da57a329376d03066dd749ee" - integrity sha512-5SAMJj+0pbhCiyNkKjkUxEbM9L/wrOE4HTvM7gvm902fULuKZklb3wV8iiUNRfIPCs6VhmmIhPzXICGjhW5xIg== - dependencies: - "@storybook/addons" "5.2.8" - "@storybook/api" "5.2.8" - "@storybook/client-api" "5.2.8" - "@storybook/components" "5.2.8" - "@storybook/core-events" "5.2.8" - "@storybook/theming" "5.2.8" +"@storybook/addon-knobs@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-5.2.6.tgz#28b2c74ea26519fef204915142a03bd7476f247c" + integrity sha512-whEZl6PpUPtOWBhmWlZ11EloxN6ad3WrJk5FyYlg3BcXG/HtlMVogBKdch83SYTT9jhHwbfwKnAng9J3UjgPbQ== + dependencies: + "@storybook/addons" "5.2.6" + "@storybook/api" "5.2.6" + "@storybook/client-api" "5.2.6" + "@storybook/components" "5.2.6" + "@storybook/core-events" "5.2.6" + "@storybook/theming" "5.2.6" "@types/react-color" "^3.0.1" copy-to-clipboard "^3.0.8" core-js "^3.0.1" @@ -3184,13 +2672,13 @@ react-lifecycles-compat "^3.0.4" react-select "^3.0.0" -"@storybook/addon-storyshots@^5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/addon-storyshots/-/addon-storyshots-5.2.8.tgz#1878d0cc7490941cc4006bd3bd96bfd06005e1e3" - integrity sha512-izUQTwzt1I0TdtYn3jv6yFIaW7H48gPW+nehisVXOA+0b0f+IySnC63+q3YcCQcC9cmZ5xxzZNJ1XycrsyVm0A== +"@storybook/addon-storyshots@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/addon-storyshots/-/addon-storyshots-5.2.6.tgz#cc94f256cb28e2769a3dd472af420f8e0fcc306f" + integrity sha512-04UX6VXFOrv1o41L8P3mevFYN2H9RU6JCNXfqCJLtD4ZxP5iDoXjF8/0VWLdqCPANe9Ng58r5BnZgNwWPjcGbA== dependencies: "@jest/transform" "^24.9.0" - "@storybook/addons" "5.2.8" + "@storybook/addons" "5.2.6" core-js "^3.0.1" glob "^7.1.3" global "^4.3.2" @@ -3199,29 +2687,29 @@ regenerator-runtime "^0.12.1" ts-dedent "^1.1.0" -"@storybook/addons@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.2.8.tgz#f8bf8bd555b7a69fb1e9a52ab8cdb96384d931ff" - integrity sha512-yAo1N5z/45bNIQP8SD+HVTr7X898bYAtz1EZBrQ6zD8bGamzA2Br06rOLL9xXw29eQhsaVnPlqgDwCS1sTC7aQ== +"@storybook/addons@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.2.6.tgz#c1278137acb3502e068b0b0d07a8371c607e9c02" + integrity sha512-5MF64lsAhIEMxTbVpYROz5Wez595iwSw45yXyP8gWt12d+EmFO5tdy7cYJCxcMuVhDfaCI78tFqS9orr1atVyA== dependencies: - "@storybook/api" "5.2.8" - "@storybook/channels" "5.2.8" - "@storybook/client-logger" "5.2.8" - "@storybook/core-events" "5.2.8" + "@storybook/api" "5.2.6" + "@storybook/channels" "5.2.6" + "@storybook/client-logger" "5.2.6" + "@storybook/core-events" "5.2.6" core-js "^3.0.1" global "^4.3.2" util-deprecate "^1.0.2" -"@storybook/api@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.2.8.tgz#21f03df8041114eb929bd10b570a17f266568b7f" - integrity sha512-rFrPtTFDIPQoicLwq1AVsOvZNTUKnjD1w/NX1kKcyuWLL9BcOkU3YNLBlliGBg2JX/yS+fJKMyKk4NMzNBCZCg== +"@storybook/api@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.2.6.tgz#43d3c20b90e585e6c94b36e29845d39704ae2135" + integrity sha512-X/di44/SAL68mD6RHTX2qdWwhjRW6BgcfPtu0dMd38ErB3AfsfP4BITXs6kFOeSM8kWiaQoyuw0pOBzA8vlYug== dependencies: - "@storybook/channels" "5.2.8" - "@storybook/client-logger" "5.2.8" - "@storybook/core-events" "5.2.8" - "@storybook/router" "5.2.8" - "@storybook/theming" "5.2.8" + "@storybook/channels" "5.2.6" + "@storybook/client-logger" "5.2.6" + "@storybook/core-events" "5.2.6" + "@storybook/router" "5.2.6" + "@storybook/theming" "5.2.6" core-js "^3.0.1" fast-deep-equal "^2.0.1" global "^4.3.2" @@ -3235,35 +2723,35 @@ telejson "^3.0.2" util-deprecate "^1.0.2" -"@storybook/channel-postmessage@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.2.8.tgz#7a84869ce0fc270c3b5dcd7fa4ed798b6055816f" - integrity sha512-RS3iDW1kpfODN+kBq3youn+KtLqHslZ4m7mTlOL80BUHKb4YkrA1lVkzpy1kVMWBU523pyDVQUVXr+M8y3iVug== +"@storybook/channel-postmessage@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.2.6.tgz#60aaef0e80300c9812a571ca3ce0f28e2c404f04" + integrity sha512-y+63wWiEc/Q4s4MZ3KJ//5A8j5VLufxuLvPxwv9FuS4z8lmN0fqeGJn857qIlFGbZhzsQaoRdmfsCQpBBgUneg== dependencies: - "@storybook/channels" "5.2.8" - "@storybook/client-logger" "5.2.8" + "@storybook/channels" "5.2.6" + "@storybook/client-logger" "5.2.6" core-js "^3.0.1" global "^4.3.2" telejson "^3.0.2" -"@storybook/channels@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.2.8.tgz#79a99ad85dcacb688073c22340c5b7d16b801202" - integrity sha512-mFwQec27QSrqcl+IH0xA+4jfoEqC4m1G99LBHt/aTDjLZXclX1A470WqeZCp7Gx4OALpaPEVTaaaKPbiKz4C6w== +"@storybook/channels@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.2.6.tgz#e2837508864dc4d5b5e03f078886f0ce113762ea" + integrity sha512-/UsktYsXuvb1efjVPCEivhh5ywRhm7hl73pQnpJLJHRqyLMM2I5nGPFELTTNuU9yWy7sP9QL5gRqBBPe1sqjZQ== dependencies: core-js "^3.0.1" -"@storybook/client-api@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.2.8.tgz#1de791f7888442287f848e5f544eb883c5edc0da" - integrity sha512-OCKhZ+2sS3ot0ZV48nD79BWVzvvdMjUFYl0073ps5q+1+TLic1AlNmH0Sb5/9NrYXNV86v3VrM2jUbGsKe1qyw== - dependencies: - "@storybook/addons" "5.2.8" - "@storybook/channel-postmessage" "5.2.8" - "@storybook/channels" "5.2.8" - "@storybook/client-logger" "5.2.8" - "@storybook/core-events" "5.2.8" - "@storybook/router" "5.2.8" +"@storybook/client-api@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.2.6.tgz#5760cb4302d82ce9210a63f3f55b1e05f04759c1" + integrity sha512-upynf4ER2fkThNnE+mBlfRFFJxTiOh60fho1ODFcBun9BbvRD2wOHLvw7+WigIhb99HM20vk8f2dhv3I5Udzlg== + dependencies: + "@storybook/addons" "5.2.6" + "@storybook/channel-postmessage" "5.2.6" + "@storybook/channels" "5.2.6" + "@storybook/client-logger" "5.2.6" + "@storybook/core-events" "5.2.6" + "@storybook/router" "5.2.6" common-tags "^1.8.0" core-js "^3.0.1" eventemitter3 "^4.0.0" @@ -3272,23 +2760,22 @@ lodash "^4.17.15" memoizerific "^1.11.3" qs "^6.6.0" - stable "^0.1.8" util-deprecate "^1.0.2" -"@storybook/client-logger@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.2.8.tgz#5affe2f9dbbee374721fd2e8729116f5ac39c779" - integrity sha512-+oVSEJdeh7TQ1Bhanb3mCr7fc3Bug3+K79abZ28J45Ub5x4L/ZVClj1xMgUsJs30BZ5FB8vhdgH6TQb0NSxR4A== +"@storybook/client-logger@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.2.6.tgz#cfc4536e9b724b086f7509c2bb34c221016713c9" + integrity sha512-hJvPD267cCwLIRMOISjDH8h9wbwOcXIJip29UlJbU9iMtZtgE+YelmlpmZJvqcDfUiXWWrOh7tP76mj8EAfwIQ== dependencies: core-js "^3.0.1" -"@storybook/components@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.2.8.tgz#f5d4a06ba4ba8c700b2d962deae182105b72fb99" - integrity sha512-h9l/LAMaj+emUCOyY/+ETy/S3P0npwQU280J88uL4O9XJALJ72EKfyttBCvMLvpM50E+fAPeDzuYn0t5qzGGxg== +"@storybook/components@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.2.6.tgz#cddb60227720aea7cae34fe782d0370bcdbd4005" + integrity sha512-C7OS90bZ1ZvxlWUZ3B2MPFFggqAtUo7X8DqqS3IwsuDUiK9dD/KS0MwPgOuFDnOTW1R5XqmQd/ylt53w3s/U5g== dependencies: - "@storybook/client-logger" "5.2.8" - "@storybook/theming" "5.2.8" + "@storybook/client-logger" "5.2.6" + "@storybook/theming" "5.2.6" "@types/react-syntax-highlighter" "10.1.0" "@types/react-textarea-autosize" "^4.3.3" core-js "^3.0.1" @@ -3307,32 +2794,32 @@ react-textarea-autosize "^7.1.0" simplebar-react "^1.0.0-alpha.6" -"@storybook/core-events@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.2.8.tgz#93fc458ea0820ff1409d268b0fe51abba200f5a4" - integrity sha512-NkQKC5doO/YL9gsO61bqaxgveKktkiJWZ3XyyhL1ZebgnO9wTlrU+i9b5aX73Myk1oxbicQw9KcwDGYk0qFuNQ== +"@storybook/core-events@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.2.6.tgz#34c9aae256e7e5f4a565b81f1e77dda8bccc6752" + integrity sha512-W8kLJ7tc0aAxs11CPUxUOCReocKL4MYGyjTg8qwk0USLzPUb/FUQWmhcm2ilFz6Nz8dXLcKrXdRVYTmiMsgAeg== dependencies: core-js "^3.0.1" -"@storybook/core@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.2.8.tgz#3f6ddbacc705c1893deb15582c3a0a1ecd882cd1" - integrity sha512-P1Xx4setLBESPgS5KgL7Jskf5Q6fRa3ApwPt+ocjDoSDGCvsV7cUEpAp09U65u+89e5K4nQxvaZouhknFQBc1A== +"@storybook/core@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.2.6.tgz#60c092607158d7d28db59f7e67da4f7e12703fb2" + integrity sha512-q7Ful7TCm9nmjgLsJFqIwVv395NlaOXgGajyaQCQlCKB2V+jgs7GDmdCNNdWAOue4eAsFU6wQSP9lWtq0yzK4w== dependencies: - "@babel/plugin-proposal-class-properties" "^7.7.0" - "@babel/plugin-proposal-object-rest-spread" "^7.6.2" + "@babel/plugin-proposal-class-properties" "^7.3.3" + "@babel/plugin-proposal-object-rest-spread" "^7.3.2" "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-transform-react-constant-elements" "^7.6.3" - "@babel/preset-env" "^7.7.1" - "@storybook/addons" "5.2.8" - "@storybook/channel-postmessage" "5.2.8" - "@storybook/client-api" "5.2.8" - "@storybook/client-logger" "5.2.8" - "@storybook/core-events" "5.2.8" - "@storybook/node-logger" "5.2.8" - "@storybook/router" "5.2.8" - "@storybook/theming" "5.2.8" - "@storybook/ui" "5.2.8" + "@babel/plugin-transform-react-constant-elements" "^7.2.0" + "@babel/preset-env" "^7.4.5" + "@storybook/addons" "5.2.6" + "@storybook/channel-postmessage" "5.2.6" + "@storybook/client-api" "5.2.6" + "@storybook/client-logger" "5.2.6" + "@storybook/core-events" "5.2.6" + "@storybook/node-logger" "5.2.6" + "@storybook/router" "5.2.6" + "@storybook/theming" "5.2.6" + "@storybook/ui" "5.2.6" airbnb-js-shims "^1 || ^2" ansi-to-html "^0.6.11" autoprefixer "^9.4.9" @@ -3388,10 +2875,10 @@ webpack-dev-middleware "^3.7.0" webpack-hot-middleware "^2.25.0" -"@storybook/node-logger@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.8.tgz#4a3df21d731014d54b9ca53d5b9a72dd350bb075" - integrity sha512-3TK5mx6VWbfJO+WUrqwPhTbTQ4qESTnwJY/02xPzOhvuC6tIG1QOxzi+Rq6rFlwxTpUuWh6iyDYnGIqFFQywkA== +"@storybook/node-logger@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.6.tgz#e353aff14375bef9e922c217a0afb50f93e2ceb1" + integrity sha512-Z3mn9CUSiG7kR2OBoz4lNeoeBS094h5d9wufZSp5S+M47L6KEXmTgNcuePKj+t8Z8KT/Ph8B63bjChseKp3DNw== dependencies: chalk "^2.4.2" core-js "^3.0.1" @@ -3399,17 +2886,17 @@ pretty-hrtime "^1.0.3" regenerator-runtime "^0.12.1" -"@storybook/react@^5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.2.8.tgz#8d44c2d34caa1d7d748ec1fc9cf0fe2a88b001f9" - integrity sha512-T1DoWpSz33vaGx85Dh7q2KYetg7dQyiYhuOnZm2WxZTFZOw1jP62si53JGFp0PKxnT6iOBLHo3v2QkRkjt2mdQ== +"@storybook/react@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.2.6.tgz#e61c0ed184add9e715191649ddb995eead756a90" + integrity sha512-yzhxxuoUx4jwn+PymU5wemzLb9ryXD9Y2Dv5kipCDkUS4cqDJwKcVO8tyhMigFUGTHREmJTmAESCKKPDR45SiQ== dependencies: - "@babel/plugin-transform-react-constant-elements" "^7.6.3" + "@babel/plugin-transform-react-constant-elements" "^7.2.0" "@babel/preset-flow" "^7.0.0" - "@babel/preset-react" "^7.7.0" - "@storybook/addons" "5.2.8" - "@storybook/core" "5.2.8" - "@storybook/node-logger" "5.2.8" + "@babel/preset-react" "^7.0.0" + "@storybook/addons" "5.2.6" + "@storybook/core" "5.2.6" + "@storybook/node-logger" "5.2.6" "@svgr/webpack" "^4.0.3" "@types/webpack-env" "^1.13.7" babel-plugin-add-react-displayname "^0.0.5" @@ -3427,10 +2914,10 @@ semver "^6.0.0" webpack "^4.33.0" -"@storybook/router@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.2.8.tgz#d7de2d401701857c033e28560c30e16512f7f72f" - integrity sha512-wnbyKESUMyv9fwo9W+n4Fev/jXylB8whpjtHrOttjguUOYX1zGSHdwNI66voPetbtVLxUeHyJteJwdyRDSirJg== +"@storybook/router@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.2.6.tgz#5180d3785501699283c6c3717986c877f84fead5" + integrity sha512-/FZd3fYg5s2QzOqSIP8UMOSnCIFFIlli/jKlOxvm3WpcpxgwQOY4lfHsLO+r9ThCLs2UvVg2R/HqGrOHqDFU7A== dependencies: "@reach/router" "^1.2.1" "@types/reach__router" "^1.2.3" @@ -3440,14 +2927,14 @@ memoizerific "^1.11.3" qs "^6.6.0" -"@storybook/theming@5.2.8", "@storybook/theming@^5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.2.8.tgz#a4c9e0e9a5789c1aa71e4fcb7a8ee86efe3dadcf" - integrity sha512-rGb66GkXb0jNJMH8UQ3Ru4FL+m1x0+UdxM8a8HSE/qb1GMv2qOwjVETfAL6nVL9u6ZmrtbhHoero4f6xDwZdRg== +"@storybook/theming@5.2.6", "@storybook/theming@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.2.6.tgz#e04170b3e53dcfc791b2381c8a39192ae88cd291" + integrity sha512-Xa9R/H8DDgmvxsCHloJUJ2d9ZQl80AeqHrL+c/AKNpx05s9lV74DcinusCf0kz72YGUO/Xt1bAjuOvLnAaS8Gw== dependencies: "@emotion/core" "^10.0.14" "@emotion/styled" "^10.0.14" - "@storybook/client-logger" "5.2.8" + "@storybook/client-logger" "5.2.6" common-tags "^1.8.0" core-js "^3.0.1" deep-object-diff "^1.1.0" @@ -3458,19 +2945,19 @@ prop-types "^15.7.2" resolve-from "^5.0.0" -"@storybook/ui@5.2.8": - version "5.2.8" - resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.2.8.tgz#da8afca9eb29a40ef3ddc6a9f6e76d7a3344f2ef" - integrity sha512-7t1ARBfylhEsLmGsZBUCj1Wf1oAgCDDrf7fi+Fhdg5Rr16CMoBbe24Gv/mPYv01/pUDhGodxzltKGX5x0Hto2w== - dependencies: - "@storybook/addons" "5.2.8" - "@storybook/api" "5.2.8" - "@storybook/channels" "5.2.8" - "@storybook/client-logger" "5.2.8" - "@storybook/components" "5.2.8" - "@storybook/core-events" "5.2.8" - "@storybook/router" "5.2.8" - "@storybook/theming" "5.2.8" +"@storybook/ui@5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.2.6.tgz#33df2f2e03d9cf81dc52928a0dc4db280ee8f56a" + integrity sha512-jT3PtpEsTqnESO0U8BotC+5P971Xqy0s2leSZcgU9PNe4Eb7NaxypSULOulPgPAx1JOmMipUBdK54PP/nyudkA== + dependencies: + "@storybook/addons" "5.2.6" + "@storybook/api" "5.2.6" + "@storybook/channels" "5.2.6" + "@storybook/client-logger" "5.2.6" + "@storybook/components" "5.2.6" + "@storybook/core-events" "5.2.6" + "@storybook/router" "5.2.6" + "@storybook/theming" "5.2.6" copy-to-clipboard "^3.0.8" core-js "^3.0.1" core-js-pure "^3.0.1" @@ -7764,15 +7251,6 @@ browserslist@^4.6.0, browserslist@^4.6.3: electron-to-chromium "^1.3.188" node-releases "^1.1.25" -browserslist@^4.8.2: - version "4.8.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.2.tgz#b45720ad5fbc8713b7253c20766f701c9a694289" - integrity sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA== - dependencies: - caniuse-lite "^1.0.30001015" - electron-to-chromium "^1.3.322" - node-releases "^1.1.42" - bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -8182,11 +7660,6 @@ caniuse-lite@^1.0.30000984: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9" integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw== -caniuse-lite@^1.0.30001015: - version "1.0.30001016" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz#16ea48d7d6e8caf3cad3295c2d746fe38c4e7f66" - integrity sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA== - capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -9496,14 +8969,6 @@ core-js-compat@^3.1.1: core-js-pure "3.1.3" semver "^6.1.0" -core-js-compat@^3.4.7: - version "3.5.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.5.0.tgz#5a11a619a9e9dd2dcf1c742b2060bc4a2143e5b6" - integrity sha512-E7iJB72svRjJTnm9HDvujzNVMCm3ZcDYEedkJ/sDTNsy/0yooCd9Cg7GSzE7b4e0LfIkjijdB1tqg0pGwxWeWg== - dependencies: - browserslist "^4.8.2" - semver "^6.3.0" - core-js-pure@3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.3.tgz#4c90752d5b9471f641514f3728f51c1e0783d0b5" @@ -11490,11 +10955,6 @@ electron-to-chromium@^1.3.191: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.246.tgz#38c30a380398b293f39a19d4346f18e2cb376b72" integrity sha512-CzR7VM16UmZQVgd5I5qu/rx0e67l6FF17rpJD2kRFX9n1ygHFIS+TV9DO55MSZKBGVuQ0Ph1JLLTFEReCKU6nQ== -electron-to-chromium@^1.3.322: - version "1.3.322" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8" - integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA== - elegant-spinner@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" @@ -20986,13 +20446,6 @@ node-releases@^1.1.25: dependencies: semver "^5.3.0" -node-releases@^1.1.42: - version "1.1.42" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.42.tgz#a999f6a62f8746981f6da90627a8d2fc090bbad7" - integrity sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA== - dependencies: - semver "^6.3.0" - node-sass@^4.9.4: version "4.9.4" resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.4.tgz#349bd7f1c89422ffe7e1e4b60f2055a69fbc5512" @@ -24836,13 +24289,6 @@ regenerate-unicode-properties@^8.0.2: dependencies: regenerate "^1.4.0" -regenerate-unicode-properties@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" - integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== - dependencies: - regenerate "^1.4.0" - regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" @@ -24939,18 +24385,6 @@ regexpu-core@^4.5.4: unicode-match-property-ecmascript "^1.0.4" unicode-match-property-value-ecmascript "^1.1.0" -regexpu-core@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" - integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.1.0" - regjsgen "^0.5.0" - regjsparser "^0.6.0" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.1.0" - registry-auth-token@^3.0.1, registry-auth-token@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" From 3816a89ff0d5d76990c7aba45cf9b193ec2b433b Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:27:11 -0700 Subject: [PATCH 16/60] Revert "Update memoize-one related packages (#53080)" This reverts commit ffe24cd832d68f131123ca52550673ff1ead6996. --- x-pack/package.json | 4 ++-- yarn.lock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/package.json b/x-pack/package.json index 675040ee9fe1ba..b91e06629ae489 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -75,7 +75,7 @@ "@types/jsonwebtoken": "^7.2.8", "@types/lodash": "^3.10.1", "@types/mapbox-gl": "^0.54.1", - "@types/memoize-one": "^4.1.1", + "@types/memoize-one": "^4.1.0", "@types/mime": "^2.0.1", "@types/mocha": "^5.2.7", "@types/nock": "^10.0.3", @@ -267,7 +267,7 @@ "mapbox-gl": "1.3.1", "mapbox-gl-draw-rectangle-mode": "^1.0.4", "markdown-it": "^10.0.0", - "memoize-one": "^5.1.1", + "memoize-one": "^5.0.0", "mime": "^2.4.4", "moment": "^2.24.0", "moment-duration-format": "^2.3.2", diff --git a/yarn.lock b/yarn.lock index 4d33241f2ef6fe..f7e8f93d898f36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3829,7 +3829,7 @@ dependencies: "@types/linkify-it" "*" -"@types/memoize-one@^4.1.1": +"@types/memoize-one@^4.1.0": version "4.1.1" resolved "https://registry.yarnpkg.com/@types/memoize-one/-/memoize-one-4.1.1.tgz#41dd138a4335b5041f7d8fc038f9d593d88b3369" integrity sha512-+9djKUUn8hOyktLCfCy4hLaIPgDNovaU36fsnZe9trFHr6ddlbIn2q0SEsnkCkNR+pBWEU440Molz/+Mpyf+gQ== From ce3b4748d7870aad986e3b6383130689ee79d80d Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:27:19 -0700 Subject: [PATCH 17/60] Revert "Update eslint related packages (#53078)" This reverts commit 9e50a1089c76a7cdad0a4e9fc20ecbcbb8438f7d. --- package.json | 12 +- packages/eslint-config-kibana/package.json | 4 +- .../kbn-eslint-plugin-eslint/package.json | 4 +- yarn.lock | 144 +++++++++--------- 4 files changed, 83 insertions(+), 81 deletions(-) diff --git a/package.json b/package.json index 07f25b8c4335b2..372ed10a98cff1 100644 --- a/package.json +++ b/package.json @@ -310,7 +310,7 @@ "@types/delete-empty": "^2.0.0", "@types/elasticsearch": "^5.0.33", "@types/enzyme": "^3.9.0", - "@types/eslint": "^6.1.3", + "@types/eslint": "^6.1.2", "@types/fetch-mock": "^7.3.1", "@types/getopts": "^2.0.1", "@types/glob": "^7.1.1", @@ -385,19 +385,19 @@ "enzyme-adapter-react-16": "^1.15.1", "enzyme-adapter-utils": "^1.12.1", "enzyme-to-json": "^3.4.3", - "eslint": "^6.7.2", - "eslint-config-prettier": "^6.7.0", + "eslint": "^6.5.1", + "eslint-config-prettier": "^6.4.0", "eslint-plugin-babel": "^5.3.0", "eslint-plugin-ban": "^1.3.0", - "eslint-plugin-cypress": "^2.8.0", - "eslint-plugin-import": "^2.19.1", + "eslint-plugin-cypress": "^2.7.0", + "eslint-plugin-import": "^2.18.2", "eslint-plugin-jest": "^22.19.0", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-mocha": "^6.2.0", "eslint-plugin-no-unsanitized": "^3.0.2", "eslint-plugin-node": "^10.0.0", "eslint-plugin-prefer-object-spread": "^1.2.1", - "eslint-plugin-prettier": "^3.1.2", + "eslint-plugin-prettier": "^3.1.1", "eslint-plugin-react": "^7.16.0", "eslint-plugin-react-hooks": "^2.1.2", "exit-hook": "^2.2.0", diff --git a/packages/eslint-config-kibana/package.json b/packages/eslint-config-kibana/package.json index 2e72066fcbc68d..7917297883b033 100644 --- a/packages/eslint-config-kibana/package.json +++ b/packages/eslint-config-kibana/package.json @@ -18,11 +18,11 @@ "@typescript-eslint/eslint-plugin": "^2.10.0", "@typescript-eslint/parser": "^2.10.0", "babel-eslint": "^10.0.3", - "eslint": "^6.7.2", + "eslint": "^6.5.1", "eslint-plugin-babel": "^5.3.0", "eslint-plugin-ban": "^1.3.0", "eslint-plugin-jsx-a11y": "^6.2.3", - "eslint-plugin-import": "^2.19.1", + "eslint-plugin-import": "^2.18.2", "eslint-plugin-jest": "^22.19.0", "eslint-plugin-mocha": "^6.2.0", "eslint-plugin-no-unsanitized": "^3.0.2", diff --git a/packages/kbn-eslint-plugin-eslint/package.json b/packages/kbn-eslint-plugin-eslint/package.json index 70d6b0f0174703..badcf13187cafb 100644 --- a/packages/kbn-eslint-plugin-eslint/package.json +++ b/packages/kbn-eslint-plugin-eslint/package.json @@ -4,12 +4,12 @@ "private": true, "license": "Apache-2.0", "peerDependencies": { - "eslint": "6.7.2", + "eslint": "6.5.1", "babel-eslint": "^10.0.3" }, "dependencies": { "micromatch": "3.1.10", "dedent": "^0.7.0", - "eslint-module-utils": "2.5.0" + "eslint-module-utils": "2.4.1" } } diff --git a/yarn.lock b/yarn.lock index f7e8f93d898f36..0d036593393952 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3467,10 +3467,10 @@ resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== -"@types/eslint@^6.1.3": - version "6.1.3" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-6.1.3.tgz#ec2a66e445a48efaa234020eb3b6e8f06afc9c61" - integrity sha512-llYf1QNZaDweXtA7uY6JczcwHmFwJL9TpK3E6sY0B18l6ulDT6VWNMAdEjYccFHiDfxLPxffd8QmSDV4QUUspA== +"@types/eslint@^6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-6.1.2.tgz#297ece0f3815f93d699b18bdade5e6bee747284f" + integrity sha512-t+smTKg1e9SshiIOI94Zi+Lvo3bfHF20MuKP8w3VGWdrS1dYm33A7xrSoyy9FQv6oE2TwYqEXVJ50I0or8+FWQ== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -4811,7 +4811,7 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" -acorn-jsx@^5.1.0: +acorn-jsx@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384" integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw== @@ -11478,10 +11478,10 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-config-prettier@^6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz#9a876952e12df2b284adbd3440994bf1f39dfbb9" - integrity sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ== +eslint-config-prettier@^6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.4.0.tgz#0a04f147e31d33c6c161b2dd0971418ac52d0477" + integrity sha512-YrKucoFdc7SEko5Sxe4r6ixqXPDP1tunGw91POeZTTRKItf/AMFYt/YLEQtZMkR2LVpAVhcAcZgcWpm1oGPW7w== dependencies: get-stdin "^6.0.0" @@ -11520,12 +11520,20 @@ eslint-import-resolver-webpack@0.11.1: resolve "^1.10.0" semver "^5.3.0" -eslint-module-utils@2.5.0, eslint-module-utils@^2.4.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz#cdf0b40d623032274ccd2abd7e64c4e524d6e19c" - integrity sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw== +eslint-module-utils@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz#7b4675875bf96b0dbf1b21977456e5bb1f5e018c" + integrity sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw== dependencies: - debug "^2.6.9" + debug "^2.6.8" + pkg-dir "^2.0.0" + +eslint-module-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a" + integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw== + dependencies: + debug "^2.6.8" pkg-dir "^2.0.0" eslint-plugin-babel@^5.3.0: @@ -11542,10 +11550,10 @@ eslint-plugin-ban@^1.3.0: dependencies: requireindex "~1.2.0" -eslint-plugin-cypress@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.8.0.tgz#95a3fe4aa36dbeccd0337fad09496222905f6d8b" - integrity sha512-5J3xn0hH5KWh3wG0tEO7KXQc1LRqveBi0oTLG3+275j6W+P9uB9sNC1t+CWZieqz0rPkHoWWopntsE03WqJ84g== +eslint-plugin-cypress@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.7.0.tgz#117f14ce63698e4c4f3afea3d7e27025c8d504f0" + integrity sha512-52Lq5ePCD/8jc536e1RqtLfj33BAy1s7BlYgCjbG39J5kqUitcTlRY5i3NRoeAyPHueDwETsq0eASF44ugLosQ== dependencies: globals "^11.12.0" @@ -11557,23 +11565,22 @@ eslint-plugin-es@^2.0.0: eslint-utils "^1.4.2" regexpp "^3.0.0" -eslint-plugin-import@^2.19.1: - version "2.19.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz#5654e10b7839d064dd0d46cd1b88ec2133a11448" - integrity sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw== +eslint-plugin-import@^2.18.2: + version "2.18.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6" + integrity sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ== dependencies: array-includes "^3.0.3" - array.prototype.flat "^1.2.1" contains-path "^0.1.0" debug "^2.6.9" doctrine "1.5.0" eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.4.1" + eslint-module-utils "^2.4.0" has "^1.0.3" minimatch "^3.0.4" object.values "^1.1.0" read-pkg-up "^2.0.0" - resolve "^1.12.0" + resolve "^1.11.0" eslint-plugin-jest@^22.19.0: version "22.19.0" @@ -11626,10 +11633,10 @@ eslint-plugin-prefer-object-spread@^1.2.1: resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-object-spread/-/eslint-plugin-prefer-object-spread-1.2.1.tgz#27fb91853690cceb3ae6101d9c8aecc6a67a402c" integrity sha1-J/uRhTaQzOs65hAdnIrsxqZ6QCw= -eslint-plugin-prettier@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba" - integrity sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA== +eslint-plugin-prettier@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.1.tgz#507b8562410d02a03f0ddc949c616f877852f2ba" + integrity sha512-A+TZuHZ0KU0cnn56/9mfR7/KjUJ9QNVXUhwvRFSR7PGPe0zQR6PTkmyqg1AtUUEOzTqeRsUwyKFh0oVZKVCrtA== dependencies: prettier-linter-helpers "^1.0.0" @@ -11738,10 +11745,10 @@ eslint@^2.7.0: text-table "~0.2.0" user-home "^2.0.0" -eslint@^6.7.2: - version "6.7.2" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.7.2.tgz#c17707ca4ad7b2d8af986a33feba71e18a9fecd1" - integrity sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng== +eslint@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.5.1.tgz#828e4c469697d43bb586144be152198b91e96ed6" + integrity sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -11750,19 +11757,19 @@ eslint@^6.7.2: debug "^4.0.1" doctrine "^3.0.0" eslint-scope "^5.0.0" - eslint-utils "^1.4.3" + eslint-utils "^1.4.2" eslint-visitor-keys "^1.1.0" - espree "^6.1.2" + espree "^6.1.1" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" glob-parent "^5.0.0" - globals "^12.1.0" + globals "^11.7.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^7.0.0" + inquirer "^6.4.1" is-glob "^4.0.0" js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" @@ -11771,7 +11778,7 @@ eslint@^6.7.2: minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.3" + optionator "^0.8.2" progress "^2.0.0" regexpp "^2.0.1" semver "^6.1.2" @@ -11789,13 +11796,13 @@ espree@^3.1.6: acorn "^5.5.0" acorn-jsx "^3.0.0" -espree@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d" - integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA== +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== dependencies: - acorn "^7.1.0" - acorn-jsx "^5.1.0" + acorn "^7.0.0" + acorn-jsx "^5.0.2" eslint-visitor-keys "^1.1.0" esprima-fb@^15001.1.0-dev-harmony-fb: @@ -12429,7 +12436,7 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4, fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -13885,7 +13892,7 @@ global@^4.4.0: min-document "^2.19.0" process "^0.11.10" -globals@^11.1.0: +globals@^11.1.0, globals@^11.7.0: version "11.7.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" integrity sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg== @@ -13895,13 +13902,6 @@ globals@^11.12.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^12.1.0: - version "12.3.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13" - integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw== - dependencies: - type-fest "^0.8.1" - globals@^9.18.0, globals@^9.2.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -15831,6 +15831,25 @@ inquirer@^6.2.0: strip-ansi "^4.0.0" through "^2.3.6" +inquirer@^6.4.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + inquirer@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.0.tgz#9e2b032dde77da1db5db804758b8fea3a970519a" @@ -21068,7 +21087,7 @@ optional-js@^2.0.0: resolved "https://registry.yarnpkg.com/optional-js/-/optional-js-2.1.1.tgz#c2dc519ad119648510b4d241dbb60b1167c36a46" integrity sha512-mUS4bDngcD5kKzzRUd1HVQkr9Lzzby3fSrrPR9wOHhQiyYo+hDS5NVli5YQzGjQRQ15k5Sno4xH9pfykJdeEUA== -optionator@^0.8.1: +optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= @@ -21080,18 +21099,6 @@ optionator@^0.8.1: type-check "~0.3.2" wordwrap "~1.0.0" -optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - ora@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" @@ -30453,11 +30460,6 @@ with@^5.0.0: acorn "^3.1.0" acorn-globals "^3.0.0" -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" From 8e39ba342edd80ade7952d2de019512291172be1 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:27:26 -0700 Subject: [PATCH 18/60] Revert "Update dependency simple-git to v1.129.0 (#53077)" This reverts commit 9a05c75adde1c5e80ded846b8938079977631b1d. --- package.json | 2 +- packages/kbn-es/package.json | 2 +- x-pack/package.json | 2 +- yarn.lock | 15 +++++++++++---- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 372ed10a98cff1..1edbd245aa7d44 100644 --- a/package.json +++ b/package.json @@ -453,7 +453,7 @@ "regenerate": "^1.4.0", "sass-lint": "^1.12.1", "selenium-webdriver": "^4.0.0-alpha.5", - "simple-git": "1.129.0", + "simple-git": "1.116.0", "sinon": "^7.4.2", "strip-ansi": "^3.0.1", "supertest": "^3.1.0", diff --git a/packages/kbn-es/package.json b/packages/kbn-es/package.json index ccc396b5522e29..cb501dab3ddb75 100644 --- a/packages/kbn-es/package.json +++ b/packages/kbn-es/package.json @@ -15,7 +15,7 @@ "getopts": "^2.2.4", "glob": "^7.1.2", "node-fetch": "^2.6.0", - "simple-git": "^1.129.0", + "simple-git": "^1.91.0", "tar-fs": "^1.16.3", "tree-kill": "^1.2.1", "yauzl": "^2.10.0" diff --git a/x-pack/package.json b/x-pack/package.json index b91e06629ae489..35a9b3198dcf5d 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -157,7 +157,7 @@ "rxjs-marbles": "^5.0.3", "sass-loader": "^7.3.1", "sass-resources-loader": "^2.0.1", - "simple-git": "1.129.0", + "simple-git": "1.116.0", "sinon": "^7.4.2", "string-replace-loader": "^2.2.0", "supertest": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index 0d036593393952..aa6917e8ea2677 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25868,13 +25868,20 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -simple-git@1.129.0, simple-git@^1.129.0: - version "1.129.0" - resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.129.0.tgz#eddd2611d2bf41c77e1d08cd70c0b7f3af785040" - integrity sha512-XbzNmugMTeV2crZnPl+b1ZJn+nqXCUNyrZxDXpLM0kHL3B85sbPlpd8q9I4qtAHI9D2FxTB6w4BuiAGKYtyzKw== +simple-git@1.116.0: + version "1.116.0" + resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.116.0.tgz#ea6e533466f1e0152186e306e004d4eefa6e3e00" + integrity sha512-Pbo3tceqMYy0j3U7jzMKabOWcx5+67GdgQUjpK83XUxGhA+1BX93UPvlWNzbCRoFwd7EJTyDSCC2XCoT4NTLYQ== dependencies: debug "^4.0.1" +simple-git@^1.91.0: + version "1.92.0" + resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.92.0.tgz#6061468eb7d19f0141078fc742e62457e910f547" + integrity sha1-YGFGjrfRnwFBB4/HQuYkV+kQ9Uc= + dependencies: + debug "^3.1.0" + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" From 98076311b908b3842ac8b601fe0514072e521880 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:27:45 -0700 Subject: [PATCH 19/60] Revert "Update dependency getos to ^3.1.1 (#53074)" This reverts commit cf2e0ec6e73f02f8496b23447622403ec496d822. --- package.json | 2 +- x-pack/package.json | 2 +- yarn.lock | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 1edbd245aa7d44..2c8b4cafa89bf9 100644 --- a/package.json +++ b/package.json @@ -172,7 +172,7 @@ "fast-deep-equal": "^3.1.1", "file-loader": "4.2.0", "font-awesome": "4.7.0", - "getos": "^3.1.1", + "getos": "^3.1.0", "glob": "^7.1.2", "glob-all": "^3.1.0", "globby": "^8.0.1", diff --git a/x-pack/package.json b/x-pack/package.json index 35a9b3198dcf5d..83db779666c968 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -232,7 +232,7 @@ "fp-ts": "^2.0.5", "geojson-rewind": "^0.3.1", "get-port": "4.2.0", - "getos": "^3.1.1", + "getos": "^3.1.0", "git-url-parse": "11.1.2", "github-markdown-css": "^2.10.0", "glob": "^7.1.2", diff --git a/yarn.lock b/yarn.lock index aa6917e8ea2677..29395d2470bd94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5983,6 +5983,13 @@ async@1.x, async@^1.4.2, async@^1.5.2, async@~1.5.2: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= +async@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.4.0.tgz#4990200f18ea5b837c2cc4f8c031a6985c385611" + integrity sha1-SZAgDxjqW4N8LMT4wDGmmFw4VhE= + dependencies: + lodash "^4.14.0" + async@2.6.1, async@^2.5.0, async@^2.6.0, async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" @@ -13617,13 +13624,20 @@ getopts@^2.2.5: resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA== -getos@3.1.1, getos@^3.1.1: +getos@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.1.tgz#967a813cceafee0156b0483f7cffa5b3eff029c5" integrity sha512-oUP1rnEhAr97rkitiszGP9EgDVYnmchgFzfqRzSkgtfv7ai6tEi7Ko8GgjNXts7VLWEqrTWyhsOKLe5C5b/Zkg== dependencies: async "2.6.1" +getos@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.0.tgz#db3aa4df15a3295557ce5e81aa9e3e5cdfaa6567" + integrity sha512-i9vrxtDu5DlLVFcrbqUqGWYlZN/zZ4pGMICCAcZoYsX3JA54nYp8r5EThw5K+m2q3wszkx4Th746JstspB0H4Q== + dependencies: + async "2.4.0" + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" From 64a7b51a41af37ae6022d2f7fde2eace0b121f38 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:27:54 -0700 Subject: [PATCH 20/60] Revert "Update dependency geckodriver to ^1.19.1 (#53073)" This reverts commit f8c98f6e7133af47ee0fb9c7e894548441c72485. --- package.json | 2 +- yarn.lock | 20 ++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 2c8b4cafa89bf9..ab0a4a69f74153 100644 --- a/package.json +++ b/package.json @@ -403,7 +403,7 @@ "exit-hook": "^2.2.0", "faker": "1.1.0", "fetch-mock": "^7.3.9", - "geckodriver": "^1.19.1", + "geckodriver": "^1.19.0", "getopts": "^2.2.4", "grunt": "1.0.4", "grunt-available-tasks": "^0.6.3", diff --git a/yarn.lock b/yarn.lock index 29395d2470bd94..91113907c497e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13442,15 +13442,15 @@ gaze@^1.0.0, gaze@^1.1.0: dependencies: globule "^1.0.0" -geckodriver@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.19.1.tgz#556f95fd6451b553cec89f81f81abbefce10d6e5" - integrity sha512-xWL/+eEhQ6+t98rc1c+xVM3hshDJibXtZf9WJA3sshxq4k5L1PBwfmswyBmmlKUfBr4xuC256gLVC2RxFhiCsQ== +geckodriver@^1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.19.0.tgz#b2b07e343c2e409ce645e65fe88132bd34fa400a" + integrity sha512-Zq98rXKjvB+NCfzKlJGkQkFAO8zvmUSNqYEIxUwlF1qxmv4taRwwBbEfDa6Dj7Auf7C0p+ZZZmIA8KmlL1cfsw== dependencies: adm-zip "0.4.11" bluebird "3.4.6" got "5.6.0" - https-proxy-agent "3.0.0" + https-proxy-agent "2.2.1" tar "4.4.2" generate-function@^2.0.0: @@ -15344,15 +15344,7 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.0.tgz#0106efa5d63d6d6f3ab87c999fa4877a3fd1ff97" - integrity sha512-y4jAxNEihqvBI5F3SaO2rtsjIOnnNA8sEbuiP+UhJZJHeM2NRm6c09ax2tgqme+SgUUvjao2fJXF4h3D6Cb2HQ== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - -https-proxy-agent@^2.2.1: +https-proxy-agent@2.2.1, https-proxy-agent@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== From fb1670c54b40e6f12f1340ed7faa97644980ab6e Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 17 Dec 2019 11:32:30 -0700 Subject: [PATCH 21/60] Revert "Update dependency jimp to v0.9.3 (#53075)" This reverts commit 19c0626aa513a64b0a7b9d964a43b2f051032266. # Conflicts: # yarn.lock --- package.json | 2 +- yarn.lock | 413 ++++++++++++++++++++++++--------------------------- 2 files changed, 191 insertions(+), 224 deletions(-) diff --git a/package.json b/package.json index ab0a4a69f74153..25f8809f2ddd5f 100644 --- a/package.json +++ b/package.json @@ -422,7 +422,7 @@ "jest": "^24.9.0", "jest-cli": "^24.9.0", "jest-raw-loader": "^1.0.1", - "jimp": "0.9.3", + "jimp": "0.8.4", "json5": "^1.0.1", "karma": "3.1.4", "karma-chrome-launcher": "2.2.0", diff --git a/yarn.lock b/yarn.lock index 91113907c497e0..27e4e12c280a6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1845,26 +1845,24 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" -"@jimp/bmp@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.9.3.tgz#98eafc81674ce750f428ac9380007f1a4e90255e" - integrity sha512-wXZYccgGQAsIK8DZX0wZE3gbSd2mL2+eheSJMts6I5hQjxhVRZd1Gwu425nUQGzfKCOgKYTW0nLv7/8OoOTTkw== +"@jimp/bmp@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.8.4.tgz#3246e0c6b073b3e2d9b61075ac0146d9124c9277" + integrity sha512-Cf/V+SUyEVxCCP8q1emkarCHJ8NkLFcLp41VMqBihoR4ke0TIPfCSdgW/JXbM/28vvZ5a2bvMe6uOll6cFggvA== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" + "@jimp/utils" "^0.8.4" bmp-js "^0.1.0" - core-js "^3.4.1" + core-js "^2.5.7" -"@jimp/core@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.9.3.tgz#bffbf955c046569bf4b682b575228e31bb41e445" - integrity sha512-kB9lvst1QhgYOC963SAuPgv+DdVfxTProphrSffAAoo5eLeQab/Ca3ZUeX1E/SnLSr+NGVnNCd8c9gyuKDiENg== +"@jimp/core@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.8.4.tgz#fbdb3cb0823301381736e988674f14c282dc5c63" + integrity sha512-3fK5UEOEQsfSDhsrAgBT6W8Up51qkeCj9RVjusxUaEGmix34PO/KTVfzURlu6NOpOUvtfNXsCq9xS7cxBTWSCA== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" + "@jimp/utils" "^0.8.4" any-base "^1.1.0" buffer "^5.2.0" - core-js "^3.4.1" + core-js "^2.5.7" exif-parser "^0.1.12" file-type "^9.0.0" load-bmfont "^1.3.1" @@ -1873,256 +1871,231 @@ pixelmatch "^4.0.2" tinycolor2 "^1.4.1" -"@jimp/custom@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.9.3.tgz#b49dfe1d6b24e62fd4101a7db77104024c8d97e8" - integrity sha512-2E7yabQMeqjcK8+ZFu3Ja5cWyrB0zv/pmzNSDg/BBPJ59HE0fj/qcERAz6VklcjHUYRUfmE5uODsb+4DE0o/YQ== +"@jimp/custom@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.8.4.tgz#abd61281ce12194ae23046ee71d60b754b515bc8" + integrity sha512-iS/RB3QQKpm4QS8lxxtQzvYDMph9YvOn3d68gMM4pDKn95n3nt5/ySHFv6fQq/yzfox1OPdeYaXbOLvC3+ofqw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/core" "^0.9.3" - core-js "^3.4.1" + "@jimp/core" "^0.8.4" + core-js "^2.5.7" -"@jimp/gif@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.9.3.tgz#b2b1a519092f94a913a955f252996f9a968930db" - integrity sha512-DshKgMQ8lXorI/xTRyeRkZqZ3JqgnL2aGYAhx0SkAunyHgXji27chmrOGj/6KVDBucrDf/6mSexnSoUDnlWrfA== +"@jimp/gif@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.8.4.tgz#1429a71ed3b055f73d63c9b195fa7f0a46e947b5" + integrity sha512-YpHZ7aWzmrviY7YigXRolHs6oBhGJItRry8fh3zebAgKth06GMv58ce84yXXOKX4yQ+QGd6GgOWzePx+KMP9TA== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" omggif "^1.0.9" -"@jimp/jpeg@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.9.3.tgz#a759cb3bccf3cb163166873b9bdc0c949c5991b5" - integrity sha512-AJzcTJXfN9BHtpzAbICwR3+GoH0pSr6OYXbAS6yuKwz+xVn9UHrEjQb74CIzIRqrT/VWcIKg29cMQxgokzWY7w== +"@jimp/jpeg@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.8.4.tgz#effde867116f88f59ac20b44b1a526b11caca026" + integrity sha512-7exKk3LNPKJgsFzUPL+mOJtIEHcLp6yU9sVbULffVDjVUun6/Are2tCX8rCXZq28yiUhofzr61k5UqjkKFJXrA== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" jpeg-js "^0.3.4" -"@jimp/plugin-blit@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-0.9.3.tgz#740346ac62ec0f7ae4458f5fd59c7582e630a8e8" - integrity sha512-+UxCsJ3XkRSdpigpTBJ9WkdwUc3OtBlhVZdU6OL6M9ldume5Gj3rTyWvMCqytOK1tZ/+7HmxoWe4IWX31hz9qA== +"@jimp/plugin-blit@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-0.8.4.tgz#991b4199cc5506f0faae22b821b14ec93fbce1bb" + integrity sha512-H9bpetmOUgEHpkDSRzbXLMXQhr34i8YicYV3EDeuHU8mKlAjtMbVpbp5ZN4mcadTz+EYdTdVNfQNsRCcIb5Oeg== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-blur@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-0.9.3.tgz#9df505aaa63de138060264cf83ed4a98304bf105" - integrity sha512-RADcYjZ5vbk5ZrUiK7qv0G4xOpHtu19HWVVX9JTDbm4VByWTxPboVKlgiYLA6l+IxIXNtEqDclsADIM0s9FQhA== +"@jimp/plugin-blur@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-0.8.4.tgz#460f79c45eda7f24adf624a691134d6192d3dbb4" + integrity sha512-gvEDWW7+MI9Hk1KKzuFliRdDPaofkxB4pRJ/n1hipDoOGcNYFqxx5FGNQ4wsGSDpQ+RiHZF+JGKKb+EIwHg+0Q== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-color@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-0.9.3.tgz#4a5ad28f68901355878f5330186c260f4f87f944" - integrity sha512-gHDA5GVx4/R4fitEACKmWH7hNy0aU48MZWYRxmATvuqY39KidJ0fjwp+brQ3Ivgb35AgFVc2jQYc3U/JXv4RxQ== +"@jimp/plugin-color@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-0.8.4.tgz#a9aa525421ea50bf2c1baec7618f73b7e4fc3464" + integrity sha512-DHCGMxInCI1coXMIfdZJ5G/4hpt5yZLNB5+oUIxT4aClzyhUjqD4xOcnO7hlPY6LuX8+FX7cYMHhdMfhTXB3Dg== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" tinycolor2 "^1.4.1" -"@jimp/plugin-contain@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-0.9.3.tgz#d0da9892edea25549611c88e125bfcc59045c426" - integrity sha512-vdYAtp65LNDT/hMctow5o0a/SbD41/y7Z9AO7MGsfUIK92Woq90SNTWx7JplDl4HSZGrqaBONnfiEhRiYlDrdg== +"@jimp/plugin-contain@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-0.8.4.tgz#2db8c12de910490cd74f339e9414a968b8c9328e" + integrity sha512-3wwLXig5LkOMg5FrNZrX/r99ehaA+0s3dkro3CiRg0Ez6Y0fz067so+HdsmqmoG78WY/dCdgdps/xLOW2VV4DQ== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-cover@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-0.9.3.tgz#2fca63620fcf8145bdecf315cf461588b09d9488" - integrity sha512-yOwsvakgyS2/C4iZF1a1wg63QKfYvqb2d6k+rgY/0vaAe44JtEx+Gbg+7iOt4EaMm5BDlxRwmcA2Q8Pef8TvAQ== +"@jimp/plugin-cover@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-0.8.4.tgz#a09bfbbe88129754ca35e281707bc5ed3f3f0c63" + integrity sha512-U0xmSfGLmw0Ieiw00CM8DQ+XoQVBxbjsLE5To8EejnyLx5X+oNZ8r7E5EsQaushUlzij95IqMCloo+nCGhdYMw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-crop@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-0.9.3.tgz#9b19c11293714a99c03d4b517ab597a5f88823e8" - integrity sha512-kqMXSyY8hrfo0idr6qY2USOWPrNqpDWs+D6Vwa+kV6SGJhj3rMTIcptQDaamIETSxbjkE8rwUu3K4Q5UD69D7w== +"@jimp/plugin-crop@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-0.8.4.tgz#ca5bd359c4e4b2374777bae6130e8b94552932fa" + integrity sha512-Neqs0K4cr7SU9nSte2qvGVh/8+K9ArH8mH1fWhZw4Zq8qD9NicX+g5hqmpmeSjOKD73t/jOmwvBevfJDu2KKSA== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-displace@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-0.9.3.tgz#07645687b29ebc8a8491244410172795d511ba21" - integrity sha512-0AdwxYRWDmJ2wIRIj2RR3sRmNjMhcy5Kwt9Jbi/RRnzxkRScZAiyzkNZhBul23EM7ClfjrUrZufuUvRMHxZRDw== +"@jimp/plugin-displace@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-0.8.4.tgz#c6d5cff889e52cb64194979967e6bd7fff4d5d1b" + integrity sha512-qKCwAP2lAO3R8ofYaEF/Gh+sfcjzZLtEiYHzjx/mYvPpXS6Yvkvl28aUH8pwdJYT+QYGelHmOne0RJvjsac1NQ== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-dither@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-0.9.3.tgz#292b3ee617a5dcfe065d13b643055e910f8b6934" - integrity sha512-8OE+Xak9xepiCwSV+oAsb/gupTnttG3aDKxtpSZjwHebnr+k1VG8NgICbMSFATTVJqqZ18oj6LC+5726qHUJ9w== +"@jimp/plugin-dither@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-0.8.4.tgz#a2320d6a8c467cf7697109e0c5ed4ee3d3898b73" + integrity sha512-19+y5VAO6d0keRne9eJCdOeB9X0LFuRdRSjgwl/57JtREeoPj+iKBg6REBl4atiSGd7/UCFg3wRtFOw24XFKgw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-flip@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-0.9.3.tgz#a755ffa1d860106067215987cbac213501d22b41" - integrity sha512-w+lzE1ZF/UOjB8qJdeIm+dLQtOK1obZwGYdCIbgxZxw4SfkkjAftJdY8o8RNOXhHDZqGu+cYQZbMKP1zcoNkyQ== +"@jimp/plugin-flip@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-0.8.4.tgz#08bf46470c3c0b4890691f554c28ccf17813746f" + integrity sha512-1BtKtc8cANuGgiWyOmltQZaR3Y5Og/GS/db8wBpFNLJ33Ir5UAGN2raDtx4EYEd5okuRVFj3OP+wAZl69m72LQ== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-gaussian@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-gaussian/-/plugin-gaussian-0.9.3.tgz#b10b5a5b4c37cb4edc3ed22a9b25294e68daf2f8" - integrity sha512-RPrWwzlZsbWC2opSgeyWt30JU9Uwg1+GwBnoNpEMLKeqm0Dv6snASASa4zVtviGWAIq//p3Jrap7g57hKqL0Cg== +"@jimp/plugin-gaussian@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-gaussian/-/plugin-gaussian-0.8.4.tgz#f3be12c5f16c5670959ab711e69b2963f66f7b4f" + integrity sha512-qYcVmiJn8l8uDZqk4FlB/qTV8fJgiJAh/xc/WKNEp2E8qFEgxoIPeimPHO8cJorEHqlh8I8l24OZkTkkEKaFfw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-invert@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-invert/-/plugin-invert-0.9.3.tgz#723a873133a1d62f9b93e023991f262c85917c78" - integrity sha512-0lRsh7IPkzyYqExrZDT50h38xdlB/+KrdiDcuxWwWyIlKauLMR0kInjwf8sPeb3elPLeETmze7uwPAxrIAtsGQ== +"@jimp/plugin-invert@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-invert/-/plugin-invert-0.8.4.tgz#fd4577beba2973f663164f5ee454b2172ca56b34" + integrity sha512-OQ/dFDbBUmEd935Gitl5Pmgz+nLVyszwS0RqL6+G1U9EHYBeiHDrmY2sj7NgDjDEJYlRLxGlBRsTIPHzF3tdNw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-mask@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-0.9.3.tgz#6329ec861269244ab10ab9b3f54b1624c4ce0bab" - integrity sha512-nZ0J62Hly9JtMZctlSDVgnTd8Fg2XGikzAYilSTCjzIRtbXL5Be/qSAZrMfLD3CZ8exTxdlEGRkEJI3RZKXYCw== +"@jimp/plugin-mask@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-0.8.4.tgz#0dfe02a14530c3bddfc258e83bd3c979e53d15ef" + integrity sha512-uqLdRGShHwCd9RHv8bMntTfDNDI2pcEeE7+F868P6PngWLKrzQCpuAyTnK6WK0ZN95fSsgy7TzCoesYk+FchkQ== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-normalize@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-normalize/-/plugin-normalize-0.9.3.tgz#564155032d1b9dc567dbb7427a85606a25427c30" - integrity sha512-0IvgTt4R15QJnoCHvvqlK56zOtCsQV7Mkx757kdNah8uyPGjadTcFBuqCaOMK943X36IIv+o7Ix7yvNUJZt4aw== +"@jimp/plugin-normalize@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-normalize/-/plugin-normalize-0.8.4.tgz#aa2c3131082b6ceef2fb6222323db9f7d837447c" + integrity sha512-+ihgQeVD8syWxw12F5ngUUdtlIcGDqH7hEoHcwVVGOFfaJqR4YBQR4FM3QLFFFdi2X/uK2nGJt9cMh0UaINEgw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-print@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-0.9.3.tgz#b4470137312232de9b35eaf412cd753f999c58d8" - integrity sha512-pV6oX5Bhe9O/dbgrotz46Bv6u1M+/n9G0kRUunDjwzXrvON5raBFEJHQDPcTXiqPT25Gc9Ba4/Akfo/Zl6+wgQ== +"@jimp/plugin-print@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-0.8.4.tgz#c110d6e7632e3c9cf47ce395e36b0f3c1461a9ca" + integrity sha512-Wg5tZI3hW5DG9Caz4wg4ZolS3Lvv4MFAxORPAeWeahDpHs38XZ7ydJ0KR39p2oWJPP0yIFv1fETYpU7BiJPRRw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" load-bmfont "^1.4.0" -"@jimp/plugin-resize@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.9.3.tgz#916abd57c4f9b426984354c77555ade1efda7a82" - integrity sha512-YzqVE8QoDIZpVuI52v+WejwEjEEiJfNFviQfprfm5af7uSSseZgDw1sJ0koqAu+liMSY+Ewp79v2SDrKoJKqtg== +"@jimp/plugin-resize@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.8.4.tgz#6690f50c98cfd89ac3682b58ba9623e7c46e0be6" + integrity sha512-z9tumvsQja/YFTSeGvofYLvVws8LZYLYVW8l17hBETzfZQdVEvPOdWKkXqsAsK5uY9m8M5rH7kR8NZbCDVbyzA== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-rotate@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-0.9.3.tgz#aa0d674c08726c0ae3ebc7f2adbfca0a927b1d9f" - integrity sha512-kADY2pI3/yMyHbuyvKB4nqPoKf8DPQBU1b4zz2K7SxcwKh1krFf4Fa9mmhhDLoFwuNSy0SPb1JCMUO4BtFCFLA== +"@jimp/plugin-rotate@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-0.8.4.tgz#bf3ea70d10123f1372507b74d06bfefb40b3e526" + integrity sha512-PVxpt3DjqaUnHP6Nd3tzZjl4SYe/FYXszGTshtx51AMuvZLnpvekrrclYyc7Dc1Ry3kx3ma6UuLCvmf85hrdmw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugin-scale@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugin-scale/-/plugin-scale-0.9.3.tgz#427fed7642883c27601aae33c25413980b6a2c50" - integrity sha512-vZaiL5Qc+WrgGEfUe4Y0vG+qbT6pe2TW68/mu124E1tKVcZjHKZUeFN0Wr/hP2myN6nqTYj0/sord2OS/04JpA== +"@jimp/plugin-scale@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugin-scale/-/plugin-scale-0.8.4.tgz#2de9cc80d49f6a36e4177b22e0ab1d4305331c2e" + integrity sha512-PrBTOMJ5n4gbIvRNxWfc1MdgHw4vd5r1UOHRVuc6ZQ9Z/FueBuvIidnz7GBRHbsRm3IjckvsLfEL1nIK0Kqh3A== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" -"@jimp/plugins@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/plugins/-/plugins-0.9.3.tgz#bdff9d49484469c4d74ef47c2708e75773ca22b9" - integrity sha512-KYCSgFGoZBNC0224X5yUnMHCZnCdUVrsu2Yo67o3XZfUgDjO81J+vdzZ0twpPQ6qLLVAP+nQ8hkRV/QzEUstMw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/plugin-blit" "^0.9.3" - "@jimp/plugin-blur" "^0.9.3" - "@jimp/plugin-color" "^0.9.3" - "@jimp/plugin-contain" "^0.9.3" - "@jimp/plugin-cover" "^0.9.3" - "@jimp/plugin-crop" "^0.9.3" - "@jimp/plugin-displace" "^0.9.3" - "@jimp/plugin-dither" "^0.9.3" - "@jimp/plugin-flip" "^0.9.3" - "@jimp/plugin-gaussian" "^0.9.3" - "@jimp/plugin-invert" "^0.9.3" - "@jimp/plugin-mask" "^0.9.3" - "@jimp/plugin-normalize" "^0.9.3" - "@jimp/plugin-print" "^0.9.3" - "@jimp/plugin-resize" "^0.9.3" - "@jimp/plugin-rotate" "^0.9.3" - "@jimp/plugin-scale" "^0.9.3" - core-js "^3.4.1" +"@jimp/plugins@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/plugins/-/plugins-0.8.4.tgz#af24c0686aec327f3abcc50ba5bbae1df2113fb0" + integrity sha512-Vd0oCe0bj7c+crHL6ee178q2c1o50UnbCmc0imHYg7M+pY8S1kl4ubZWwkAg2W96FCarGrm9eqPvCUyAdFOi9w== + dependencies: + "@jimp/plugin-blit" "^0.8.4" + "@jimp/plugin-blur" "^0.8.4" + "@jimp/plugin-color" "^0.8.4" + "@jimp/plugin-contain" "^0.8.4" + "@jimp/plugin-cover" "^0.8.4" + "@jimp/plugin-crop" "^0.8.4" + "@jimp/plugin-displace" "^0.8.4" + "@jimp/plugin-dither" "^0.8.4" + "@jimp/plugin-flip" "^0.8.4" + "@jimp/plugin-gaussian" "^0.8.4" + "@jimp/plugin-invert" "^0.8.4" + "@jimp/plugin-mask" "^0.8.4" + "@jimp/plugin-normalize" "^0.8.4" + "@jimp/plugin-print" "^0.8.4" + "@jimp/plugin-resize" "^0.8.4" + "@jimp/plugin-rotate" "^0.8.4" + "@jimp/plugin-scale" "^0.8.4" + core-js "^2.5.7" timm "^1.6.1" -"@jimp/png@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.9.3.tgz#5c1bbb89b32e2332891a13efdb423e87287a8321" - integrity sha512-LJXUemDTSbTGAGEp9hNQH0uTRSB8gYeE6FsfT3M00oZincu6/WzDzl0P8E95rMjNxZqAihdTyOP3+kcrbbqX+w== +"@jimp/png@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.8.4.tgz#d150ddaaebafcda83d820390f62a4d3c409acc03" + integrity sha512-DLj260SwQr9ZNhSto1BacXGNRhIQiLNOESPoq5DGjbqiPCmYNxE7CPlXB1BVh0T3AmZBjnZkZORU0Y9wTi3gJw== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.9.3" - core-js "^3.4.1" + "@jimp/utils" "^0.8.4" + core-js "^2.5.7" pngjs "^3.3.3" -"@jimp/tiff@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.9.3.tgz#a4498c0616fb24034f5512b159b75b0aea389e9c" - integrity sha512-w9H6dT+GDHN//Srsv27JhRn7R2byzUahOGfFw7KpIn95jg0ogcxjKTo/RAGQC56sr4U092e4Npl7E85Lt934WQ== +"@jimp/tiff@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.8.4.tgz#bc18c32cef996ad986a92bb7d926d6abd1db9d10" + integrity sha512-SQmf1B/TbCtbwzJReLw/lzGqbeu8MOfT+wkaia0XWS72H6bEW66PTQKhB4/3uzC/Xnmsep1WNQITlwcWdgc36Q== dependencies: - "@babel/runtime" "^7.7.2" - core-js "^3.4.1" + core-js "^2.5.7" utif "^2.0.1" -"@jimp/types@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.9.3.tgz#75337245a1a8c7c84a414beca3cfeded338c0ef1" - integrity sha512-hUJKoT2IhnbO/trxNWzN19n8g+p7aKbM1R+71n4wMZnD41PzrVtz+sBBCdB+JCjBJs/i7fJt4d9z0i3Xe8m7Zw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/bmp" "^0.9.3" - "@jimp/gif" "^0.9.3" - "@jimp/jpeg" "^0.9.3" - "@jimp/png" "^0.9.3" - "@jimp/tiff" "^0.9.3" - core-js "^3.4.1" +"@jimp/types@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.8.4.tgz#01df00a5adb955cb4ba79df1288408faa3bb40ed" + integrity sha512-BCehQ5hrTOGDGdeROwXOYqgFGAzJPkuXmVJXgMgBoW1YjoGWhXJ5iShaJ/l7DRErrdezoWUdAhTFlV5bJf51dg== + dependencies: + "@jimp/bmp" "^0.8.4" + "@jimp/gif" "^0.8.4" + "@jimp/jpeg" "^0.8.4" + "@jimp/png" "^0.8.4" + "@jimp/tiff" "^0.8.4" + core-js "^2.5.7" timm "^1.6.1" -"@jimp/utils@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.9.3.tgz#fd7af0d1138febbeacc841be4b802218444ce088" - integrity sha512-9D2Of6BcjYONtl77YfmU2y5aRMLe0/O2e2aQvfCxdNwD33jRdwNdN4i3m73dpiClNquApIjL4nYGhTixA4UstA== +"@jimp/utils@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.8.4.tgz#a6bbdc13dba99b95d4cabf0bde87b1bcd2230d25" + integrity sha512-6Cwplao7IgwhFRijMvvyjdV7Sa7Fw71vS1aDsUDCVpi3XHsiLUM+nPTno6OKjzg2z2EufuolWPEvuq/GSte4lA== dependencies: - "@babel/runtime" "^7.7.2" - core-js "^3.4.1" + core-js "^2.5.7" "@mapbox/extent@0.4.0": version "0.4.0" @@ -9001,11 +8974,6 @@ core-js@^3.0.1, core-js@^3.0.4, core-js@^3.2.1: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.2.1.tgz#cd41f38534da6cc59f7db050fe67307de9868b09" integrity sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw== -core-js@^3.4.1: - version "3.5.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.5.0.tgz#66df8e49be4bd775e6f952a9d083b756ad41c1ed" - integrity sha512-Ifh3kj78gzQ7NAoJXeTu+XwzDld0QRIwjBLRqAMhuLhP3d2Av5wmgE9ycfnvK6NAEjTkQ1sDPeoEZAWO3Hx1Uw== - core-util-is@1.0.2, core-util-is@^1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -17320,16 +17288,15 @@ jest@^24.9.0: import-local "^2.0.0" jest-cli "^24.9.0" -jimp@0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.9.3.tgz#85e8e80eea65a7e6de806c6bb622ec6a7244e6f3" - integrity sha512-dIxvT1OMRkd3+B18XUhJ5WZ2Dw7Hp8mvjaTqfi945zZ7fga6LT22h3NLYDorHHAiy9z30KjfNnOgpBoxrdjDZg== +jimp@0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.8.4.tgz#9c7c6ee4c8992e585a60914c62aee0c5e5c7955b" + integrity sha512-xCPvd2HIH8iR7+gWVnivzXwiQGnLBmLDpaEj5M0vQf3uur5MuLCOWbBduAdk6r3ur8X0kwgM4eEM0i7o+k9x9g== dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/custom" "^0.9.3" - "@jimp/plugins" "^0.9.3" - "@jimp/types" "^0.9.3" - core-js "^3.4.1" + "@jimp/custom" "^0.8.4" + "@jimp/plugins" "^0.8.4" + "@jimp/types" "^0.8.4" + core-js "^2.5.7" regenerator-runtime "^0.13.3" jit-grunt@0.10.0: From 18b5cf9adbe04c16866fdb5915c8f46cf7b2eb7a Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Tue, 17 Dec 2019 18:52:57 +0000 Subject: [PATCH 22/60] [Logs UI / Metrics UI] New Platform migration server followups (#51615) --- .../settings/apm_indices/get_apm_indices.ts | 4 - .../plugins/infra/common/http_api/index.ts | 1 + .../common/http_api/metrics_explorer/index.ts | 96 +++++++++++++++++++ x-pack/legacy/plugins/infra/index.ts | 8 +- .../metrics_explorer/aggregation.tsx | 55 +++++------ .../helpers/calculate_domian.test.ts | 18 ++-- .../helpers/create_formatter_for_metric.ts | 10 +- .../create_formatter_for_metrics.test.ts | 17 ++-- .../helpers/create_metric_label.test.ts | 6 +- .../helpers/create_tsvb_link.test.ts | 8 +- .../helpers/create_tsvb_link.ts | 10 +- .../helpers/metric_to_format.test.ts | 20 ++-- .../helpers/metric_to_format.ts | 7 +- .../components/metrics_explorer/metrics.tsx | 9 +- .../components/metrics_explorer/toolbar.tsx | 9 +- .../use_metrics_explorer_data.test.tsx | 5 +- .../use_metrics_explorer_data.ts | 9 +- .../use_metrics_explorer_options.test.tsx | 5 +- .../use_metrics_explorer_options.ts | 8 +- .../use_metric_explorer_state.test.tsx | 33 +++---- .../use_metric_explorer_state.ts | 4 +- .../public/utils/fixtures/metrics_explorer.ts | 12 +-- .../lib/adapters/framework/adapter_types.ts | 6 +- .../framework/kibana_framework_adapter.ts | 6 +- .../lib/adapters/metrics/adapter_types.ts | 2 +- .../metrics/kibana_metrics_adapter.ts | 2 +- .../server/lib/domains/metrics_domain.ts | 2 +- .../infra/server/new_platform_index.ts | 5 +- .../infra/server/new_platform_plugin.ts | 14 +++ .../log_analysis/results/log_entry_rate.ts | 10 +- .../server/routes/metrics_explorer/index.ts | 25 +++-- .../lib/create_metrics_model.ts | 7 +- .../lib/populate_series_with_tsvb_data.ts | 12 +-- .../server/routes/metrics_explorer/schema.ts | 41 -------- .../server/routes/metrics_explorer/types.ts | 74 ++++---------- x-pack/plugins/infra/kibana.json | 1 + 36 files changed, 279 insertions(+), 282 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/common/http_api/metrics_explorer/index.ts delete mode 100644 x-pack/legacy/plugins/infra/server/routes/metrics_explorer/schema.ts diff --git a/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts b/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts index e451f89af5620f..e7b2330b472d8e 100644 --- a/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts +++ b/x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts @@ -54,10 +54,6 @@ export function getApmIndicesConfig(config: APMConfig): ApmIndicesConfig { }; } -// export async function getApmIndices(context: APMRequestHandlerContext) { -// return _getApmIndices(context.core, context.config); -// } - export async function getApmIndices({ config, savedObjectsClient diff --git a/x-pack/legacy/plugins/infra/common/http_api/index.ts b/x-pack/legacy/plugins/infra/common/http_api/index.ts index 5278ae6c249c87..977654ae2250d0 100644 --- a/x-pack/legacy/plugins/infra/common/http_api/index.ts +++ b/x-pack/legacy/plugins/infra/common/http_api/index.ts @@ -6,3 +6,4 @@ export * from './log_analysis'; export * from './metadata_api'; +export * from './metrics_explorer'; diff --git a/x-pack/legacy/plugins/infra/common/http_api/metrics_explorer/index.ts b/x-pack/legacy/plugins/infra/common/http_api/metrics_explorer/index.ts new file mode 100644 index 00000000000000..c10f86c40ad467 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/http_api/metrics_explorer/index.ts @@ -0,0 +1,96 @@ +/* + * 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 * as rt from 'io-ts'; + +export const METRIC_EXPLORER_AGGREGATIONS = [ + 'avg', + 'max', + 'min', + 'cardinality', + 'rate', + 'count', +] as const; + +type MetricExplorerAggregations = typeof METRIC_EXPLORER_AGGREGATIONS[number]; + +const metricsExplorerAggregationKeys = METRIC_EXPLORER_AGGREGATIONS.reduce< + Record +>((acc, agg) => ({ ...acc, [agg]: null }), {} as Record); + +export const metricsExplorerAggregationRT = rt.keyof(metricsExplorerAggregationKeys); + +export const metricsExplorerMetricRequiredFieldsRT = rt.type({ + aggregation: metricsExplorerAggregationRT, +}); + +export const metricsExplorerMetricOptionalFieldsRT = rt.partial({ + field: rt.union([rt.string, rt.undefined]), +}); + +export const metricsExplorerMetricRT = rt.intersection([ + metricsExplorerMetricRequiredFieldsRT, + metricsExplorerMetricOptionalFieldsRT, +]); + +export const timeRangeRT = rt.type({ + field: rt.string, + from: rt.number, + to: rt.number, + interval: rt.string, +}); + +export const metricsExplorerRequestBodyRequiredFieldsRT = rt.type({ + timerange: timeRangeRT, + indexPattern: rt.string, + metrics: rt.array(metricsExplorerMetricRT), +}); + +export const metricsExplorerRequestBodyOptionalFieldsRT = rt.partial({ + groupBy: rt.union([rt.string, rt.null, rt.undefined]), + afterKey: rt.union([rt.string, rt.null, rt.undefined]), + limit: rt.union([rt.number, rt.null, rt.undefined]), + filterQuery: rt.union([rt.string, rt.null, rt.undefined]), +}); + +export const metricsExplorerRequestBodyRT = rt.intersection([ + metricsExplorerRequestBodyRequiredFieldsRT, + metricsExplorerRequestBodyOptionalFieldsRT, +]); + +export const metricsExplorerPageInfoRT = rt.type({ + total: rt.number, + afterKey: rt.union([rt.string, rt.null]), +}); + +export const metricsExplorerColumnTypeRT = rt.keyof({ + date: null, + number: null, + string: null, +}); + +export const metricsExplorerColumnRT = rt.type({ + name: rt.string, + type: metricsExplorerColumnTypeRT, +}); + +export const metricsExplorerRowRT = rt.intersection([ + rt.type({ + timestamp: rt.number, + }), + rt.record(rt.string, rt.union([rt.string, rt.number, rt.null, rt.undefined])), +]); + +export const metricsExplorerSeriesRT = rt.type({ + id: rt.string, + columns: rt.array(metricsExplorerColumnRT), + rows: rt.array(metricsExplorerRowRT), +}); + +export const metricsExplorerResponseRT = rt.type({ + series: rt.array(metricsExplorerSeriesRT), + pageInfo: metricsExplorerPageInfoRT, +}); diff --git a/x-pack/legacy/plugins/infra/index.ts b/x-pack/legacy/plugins/infra/index.ts index 5466f2572a48e8..38661f430c4020 100644 --- a/x-pack/legacy/plugins/infra/index.ts +++ b/x-pack/legacy/plugins/infra/index.ts @@ -14,6 +14,8 @@ import { getConfigSchema } from './server/kibana.index'; import { savedObjectMappings } from './server/saved_objects'; import { plugin, InfraServerPluginDeps } from './server/new_platform_index'; import { InfraSetup } from '../../../plugins/infra/server'; +import { PluginSetupContract as FeaturesPluginSetup } from '../../../plugins/features/server'; +import { SpacesPluginSetup } from '../../../plugins/spaces/server'; import { APMPluginContract } from '../../../plugins/apm/server'; const APP_ID = 'infra'; @@ -91,8 +93,8 @@ export function infra(kibana: any) { indexPatternsServiceFactory: legacyServer.indexPatternsServiceFactory, }, metrics: legacyServer.plugins.metrics, - spaces: plugins.spaces, - features: plugins.features, + spaces: plugins.spaces as SpacesPluginSetup, + features: plugins.features as FeaturesPluginSetup, // NP_NOTE: [TSVB_GROUP] Huge hack to make TSVB (getVisData()) work with raw requests that // originate from the New Platform router (and are very different to the old request object). // Once TSVB has migrated over to NP, and can work with the new raw requests, or ideally just @@ -113,7 +115,7 @@ export function infra(kibana: any) { const libs = infraPluginInstance.getLibs(); - // NP_TODO how do we replace this? Answer: return from setup function. + // NP_NOTE: Left here for now for legacy plugins to consume legacyServer.expose( 'defineInternalSourceConfiguration', libs.sources.defineInternalSourceConfiguration.bind(libs.sources) diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/aggregation.tsx b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/aggregation.tsx index d498ba1229b44c..3550cfc9e03eeb 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/aggregation.tsx +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/aggregation.tsx @@ -10,6 +10,10 @@ import { i18n } from '@kbn/i18n'; import React, { useCallback } from 'react'; import { MetricsExplorerAggregation } from '../../../server/routes/metrics_explorer/types'; import { MetricsExplorerOptions } from '../../containers/metrics_explorer/use_metrics_explorer_options'; +import { + metricsExplorerAggregationRT, + METRIC_EXPLORER_AGGREGATIONS, +} from '../../../common/http_api/metrics_explorer'; interface Props { options: MetricsExplorerOptions; @@ -17,43 +21,32 @@ interface Props { onChange: (aggregation: MetricsExplorerAggregation) => void; } -const isMetricsExplorerAggregation = (subject: any): subject is MetricsExplorerAggregation => { - return Object.keys(MetricsExplorerAggregation).includes(subject); -}; - export const MetricsExplorerAggregationPicker = ({ options, onChange }: Props) => { const AGGREGATION_LABELS = { - [MetricsExplorerAggregation.avg]: i18n.translate( - 'xpack.infra.metricsExplorer.aggregationLables.avg', - { defaultMessage: 'Average' } - ), - [MetricsExplorerAggregation.max]: i18n.translate( - 'xpack.infra.metricsExplorer.aggregationLables.max', - { defaultMessage: 'Max' } - ), - [MetricsExplorerAggregation.min]: i18n.translate( - 'xpack.infra.metricsExplorer.aggregationLables.min', - { defaultMessage: 'Min' } - ), - [MetricsExplorerAggregation.cardinality]: i18n.translate( - 'xpack.infra.metricsExplorer.aggregationLables.cardinality', - { defaultMessage: 'Cardinality' } - ), - [MetricsExplorerAggregation.rate]: i18n.translate( - 'xpack.infra.metricsExplorer.aggregationLables.rate', - { defaultMessage: 'Rate' } - ), - [MetricsExplorerAggregation.count]: i18n.translate( - 'xpack.infra.metricsExplorer.aggregationLables.count', - { defaultMessage: 'Document count' } - ), + ['avg']: i18n.translate('xpack.infra.metricsExplorer.aggregationLables.avg', { + defaultMessage: 'Average', + }), + ['max']: i18n.translate('xpack.infra.metricsExplorer.aggregationLables.max', { + defaultMessage: 'Max', + }), + ['min']: i18n.translate('xpack.infra.metricsExplorer.aggregationLables.min', { + defaultMessage: 'Min', + }), + ['cardinality']: i18n.translate('xpack.infra.metricsExplorer.aggregationLables.cardinality', { + defaultMessage: 'Cardinality', + }), + ['rate']: i18n.translate('xpack.infra.metricsExplorer.aggregationLables.rate', { + defaultMessage: 'Rate', + }), + ['count']: i18n.translate('xpack.infra.metricsExplorer.aggregationLables.count', { + defaultMessage: 'Document count', + }), }; const handleChange = useCallback( e => { const aggregation = - (isMetricsExplorerAggregation(e.target.value) && e.target.value) || - MetricsExplorerAggregation.avg; + (metricsExplorerAggregationRT.is(e.target.value) && e.target.value) || 'avg'; onChange(aggregation); }, [onChange] @@ -66,7 +59,7 @@ export const MetricsExplorerAggregationPicker = ({ options, onChange }: Props) = })} fullWidth value={options.aggregation} - options={Object.keys(MetricsExplorerAggregation).map(k => ({ + options={METRIC_EXPLORER_AGGREGATIONS.map(k => ({ text: AGGREGATION_LABELS[k as MetricsExplorerAggregation], value: k, }))} diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domian.test.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domian.test.ts index c335b8b3c31ac1..e85cd67060d2cf 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domian.test.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/calculate_domian.test.ts @@ -5,21 +5,17 @@ */ import { calculateDomain } from './calculate_domain'; -import { - MetricsExplorerSeries, - MetricsExplorerAggregation, - MetricsExplorerColumnType, -} from '../../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerSeries } from '../../../../server/routes/metrics_explorer/types'; import { MetricsExplorerOptionsMetric } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; import { MetricsExplorerColor } from '../../../../common/color_palette'; describe('calculateDomain()', () => { const series: MetricsExplorerSeries = { id: 'test-01', columns: [ - { type: MetricsExplorerColumnType.date, name: 'timestamp' }, - { type: MetricsExplorerColumnType.number, name: 'metric_0' }, - { type: MetricsExplorerColumnType.number, name: 'metric_1' }, - { type: MetricsExplorerColumnType.string, name: 'groupBy' }, + { type: 'date', name: 'timestamp' }, + { type: 'number', name: 'metric_0' }, + { type: 'number', name: 'metric_1' }, + { type: 'string', name: 'groupBy' }, ], rows: [ { timestamp: 1562860500000, metric_0: null, metric_1: null }, @@ -31,12 +27,12 @@ describe('calculateDomain()', () => { }; const metrics: MetricsExplorerOptionsMetric[] = [ { - aggregation: MetricsExplorerAggregation.avg, + aggregation: 'avg', field: 'system.memory.free', color: MetricsExplorerColor.color0, }, { - aggregation: MetricsExplorerAggregation.avg, + aggregation: 'avg', field: 'system.memory.used.bytes', color: MetricsExplorerColor.color1, }, diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metric.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metric.ts index 3451d901d45162..1e9902337e0324 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metric.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metric.ts @@ -4,20 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - MetricsExplorerAggregation, - MetricsExplorerMetric, -} from '../../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerMetric } from '../../../../server/routes/metrics_explorer/types'; import { createFormatter } from '../../../utils/formatters'; import { InfraFormatterType } from '../../../lib/lib'; import { metricToFormat } from './metric_to_format'; export const createFormatterForMetric = (metric?: MetricsExplorerMetric) => { if (metric && metric.field) { const format = metricToFormat(metric); - if ( - format === InfraFormatterType.bits && - metric.aggregation === MetricsExplorerAggregation.rate - ) { + if (format === InfraFormatterType.bits && metric.aggregation === 'rate') { return createFormatter(InfraFormatterType.bits, '{{value}}/s'); } return createFormatter(format); diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metrics.test.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metrics.test.ts index 12058f37aeb1a6..592dd70345bfa3 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metrics.test.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metrics.test.ts @@ -5,34 +5,35 @@ */ import { createFormatterForMetric } from './create_formatter_for_metric'; -import { MetricsExplorerAggregation } from '../../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerMetric } from '../../../../server/routes/metrics_explorer/types'; + describe('createFormatterForMetric()', () => { it('should just work for count', () => { - const metric = { aggregation: MetricsExplorerAggregation.count }; + const metric: MetricsExplorerMetric = { aggregation: 'count' }; const format = createFormatterForMetric(metric); expect(format(1291929)).toBe('1,291,929'); }); it('should just work for numerics', () => { - const metric = { aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }; + const metric: MetricsExplorerMetric = { aggregation: 'avg', field: 'system.load.1' }; const format = createFormatterForMetric(metric); expect(format(1000.2)).toBe('1,000.2'); }); it('should just work for percents', () => { - const metric = { aggregation: MetricsExplorerAggregation.avg, field: 'system.cpu.total.pct' }; + const metric: MetricsExplorerMetric = { aggregation: 'avg', field: 'system.cpu.total.pct' }; const format = createFormatterForMetric(metric); expect(format(0.349)).toBe('34.9%'); }); it('should just work for rates', () => { - const metric = { - aggregation: MetricsExplorerAggregation.rate, + const metric: MetricsExplorerMetric = { + aggregation: 'rate', field: 'system.network.out.bytes', }; const format = createFormatterForMetric(metric); expect(format(103929292)).toBe('831.4Mbit/s'); }); it('should just work for bytes', () => { - const metric = { - aggregation: MetricsExplorerAggregation.avg, + const metric: MetricsExplorerMetric = { + aggregation: 'avg', field: 'system.network.out.bytes', }; const format = createFormatterForMetric(metric); diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.test.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.test.ts index b148d68c71dbae..0c52d8d56a6e91 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.test.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.test.ts @@ -5,15 +5,15 @@ */ import { createMetricLabel } from './create_metric_label'; -import { MetricsExplorerAggregation } from '../../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerMetric } from '../../../../server/routes/metrics_explorer/types'; describe('createMetricLabel()', () => { it('should work with metrics with fields', () => { - const metric = { aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }; + const metric: MetricsExplorerMetric = { aggregation: 'avg', field: 'system.load.1' }; expect(createMetricLabel(metric)).toBe('avg(system.load.1)'); }); it('should work with document count', () => { - const metric = { aggregation: MetricsExplorerAggregation.count }; + const metric: MetricsExplorerMetric = { aggregation: 'count' }; expect(createMetricLabel(metric)).toBe('count()'); }); }); diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.test.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.test.ts index d190d09da992ea..860c4f1ba406cf 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.test.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.test.ts @@ -8,11 +8,11 @@ import { createTSVBLink, createFilterFromOptions } from './create_tsvb_link'; import { source, options, timeRange, chartOptions } from '../../../utils/fixtures/metrics_explorer'; import uuid from 'uuid'; import { OutputBuffer } from 'uuid/interfaces'; -import { MetricsExplorerAggregation } from '../../../../server/routes/metrics_explorer/types'; import { MetricsExplorerYAxisMode, MetricsExplorerChartType, } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; +import { MetricsExplorerOptions } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; jest.mock('uuid'); const mockedUuid = uuid as jest.Mocked; @@ -28,11 +28,9 @@ describe('createTSVBLink()', () => { }); it('should work with rates', () => { - const customOptions = { + const customOptions: MetricsExplorerOptions = { ...options, - metrics: [ - { aggregation: MetricsExplorerAggregation.rate, field: 'system.network.out.bytes' }, - ], + metrics: [{ aggregation: 'rate', field: 'system.network.out.bytes' }], }; const link = createTSVBLink(source, customOptions, series, timeRange, chartOptions); expect(link).toBe( diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.ts index 788de6a129aa9c..2fe81123594e98 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.ts @@ -8,10 +8,7 @@ import { encode } from 'rison-node'; import uuid from 'uuid'; import { set } from 'lodash'; import { colorTransformer, MetricsExplorerColor } from '../../../../common/color_palette'; -import { - MetricsExplorerSeries, - MetricsExplorerAggregation, -} from '../../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerSeries } from '../../../../server/routes/metrics_explorer/types'; import { MetricsExplorerOptions, MetricsExplorerOptionsMetric, @@ -26,7 +23,7 @@ import { SourceQuery } from '../../../graphql/types'; import { createMetricLabel } from './create_metric_label'; export const metricsExplorerMetricToTSVBMetric = (metric: MetricsExplorerOptionsMetric) => { - if (metric.aggregation === MetricsExplorerAggregation.rate) { + if (metric.aggregation === 'rate') { const metricId = uuid.v1(); const positiveOnlyId = uuid.v1(); const derivativeId = uuid.v1(); @@ -73,8 +70,7 @@ const mapMetricToSeries = (chartOptions: MetricsExplorerChartOptions) => ( ), fill: chartOptions.type === MetricsExplorerChartType.area ? 0.5 : 0, formatter: format === InfraFormatterType.bits ? InfraFormatterType.bytes : format, - value_template: - MetricsExplorerAggregation.rate === metric.aggregation ? '{{value}}/s' : '{{value}}', + value_template: 'rate' === metric.aggregation ? '{{value}}/s' : '{{value}}', id: uuid.v1(), line_width: 2, metrics: metricsExplorerMetricToTSVBMetric(metric), diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.test.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.test.ts index 9812023174a8c5..a38a9ac54d8280 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.test.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.test.ts @@ -5,37 +5,37 @@ */ import { metricToFormat } from './metric_to_format'; -import { MetricsExplorerAggregation } from '../../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerMetric } from '../../../../server/routes/metrics_explorer/types'; import { InfraFormatterType } from '../../../lib/lib'; describe('metricToFormat()', () => { it('should just work for numeric metrics', () => { - const metric = { aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }; + const metric: MetricsExplorerMetric = { aggregation: 'avg', field: 'system.load.1' }; expect(metricToFormat(metric)).toBe(InfraFormatterType.number); }); it('should just work for byte metrics', () => { - const metric = { - aggregation: MetricsExplorerAggregation.avg, + const metric: MetricsExplorerMetric = { + aggregation: 'avg', field: 'system.network.out.bytes', }; expect(metricToFormat(metric)).toBe(InfraFormatterType.bytes); }); it('should just work for rate bytes metrics', () => { - const metric = { - aggregation: MetricsExplorerAggregation.rate, + const metric: MetricsExplorerMetric = { + aggregation: 'rate', field: 'system.network.out.bytes', }; expect(metricToFormat(metric)).toBe(InfraFormatterType.bits); }); it('should just work for rate metrics', () => { - const metric = { - aggregation: MetricsExplorerAggregation.rate, + const metric: MetricsExplorerMetric = { + aggregation: 'rate', field: 'system.cpu.user.ticks', }; expect(metricToFormat(metric)).toBe(InfraFormatterType.number); }); it('should just work for percent metrics', () => { - const metric = { - aggregation: MetricsExplorerAggregation.avg, + const metric: MetricsExplorerMetric = { + aggregation: 'avg', field: 'system.cpu.user.pct', }; expect(metricToFormat(metric)).toBe(InfraFormatterType.percent); diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.ts b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.ts index de6214fda2df3b..69f2bd50ef42f0 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.ts +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.ts @@ -5,10 +5,7 @@ */ import { last } from 'lodash'; -import { - MetricsExplorerAggregation, - MetricsExplorerMetric, -} from '../../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerMetric } from '../../../../server/routes/metrics_explorer/types'; import { InfraFormatterType } from '../../../lib/lib'; export const metricToFormat = (metric?: MetricsExplorerMetric) => { if (metric && metric.field) { @@ -16,7 +13,7 @@ export const metricToFormat = (metric?: MetricsExplorerMetric) => { if (suffix === 'pct') { return InfraFormatterType.percent; } - if (suffix === 'bytes' && metric.aggregation === MetricsExplorerAggregation.rate) { + if (suffix === 'bytes' && metric.aggregation === 'rate') { return InfraFormatterType.bits; } if (suffix === 'bytes') { diff --git a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx index 42df7c6915a0df..31d301e2164f87 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx +++ b/x-pack/legacy/plugins/infra/public/components/metrics_explorer/metrics.tsx @@ -10,10 +10,7 @@ import { i18n } from '@kbn/i18n'; import React, { useCallback, useState } from 'react'; import { FieldType } from 'ui/index_patterns'; import { colorTransformer, MetricsExplorerColor } from '../../../common/color_palette'; -import { - MetricsExplorerMetric, - MetricsExplorerAggregation, -} from '../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerMetric } from '../../../server/routes/metrics_explorer/types'; import { MetricsExplorerOptions } from '../../containers/metrics_explorer/use_metrics_explorer_options'; import { isDisplayable } from '../../utils/is_displayable'; @@ -61,7 +58,7 @@ export const MetricsExplorerMetrics = ({ options, onChange, fields, autoFocus = .filter(field => isDisplayable(field)) .map(field => ({ label: field.name, value: field.name })); const selectedOptions = options.metrics - .filter(m => m.aggregation !== MetricsExplorerAggregation.count) + .filter(m => m.aggregation !== 'count') .map(metric => ({ label: metric.field || '', value: metric.field || '', @@ -74,7 +71,7 @@ export const MetricsExplorerMetrics = ({ options, onChange, fields, autoFocus = return ( { - const isDefaultOptions = - options.aggregation === MetricsExplorerAggregation.avg && options.metrics.length === 0; + const isDefaultOptions = options.aggregation === 'avg' && options.metrics.length === 0; return ( - + - {options.aggregation !== MetricsExplorerAggregation.count && ( + {options.aggregation !== 'count' && ( )} - {options.aggregation !== MetricsExplorerAggregation.count && ( + {options.aggregation !== 'count' && ( { rerender({ options: { ...options, - aggregation: MetricsExplorerAggregation.count, - metrics: [{ aggregation: MetricsExplorerAggregation.count }], + aggregation: 'count', + metrics: [{ aggregation: 'count' }], }, source, derivedIndexPattern, diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts index c2a599ea1ae781..1bca733a6e02a2 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts +++ b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts @@ -9,10 +9,7 @@ import { isEqual } from 'lodash'; import { useEffect, useState } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; import { SourceQuery } from '../../../common/graphql/types'; -import { - MetricsExplorerAggregation, - MetricsExplorerResponse, -} from '../../../server/routes/metrics_explorer/types'; +import { MetricsExplorerResponse } from '../../../server/routes/metrics_explorer/types'; import { fetch } from '../../utils/fetch'; import { convertKueryToElasticSearchQuery } from '../../utils/kuery'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions } from './use_metrics_explorer_options'; @@ -48,8 +45,8 @@ export function useMetricsExplorerData( '../api/infra/metrics_explorer', { metrics: - options.aggregation === MetricsExplorerAggregation.count - ? [{ aggregation: MetricsExplorerAggregation.count }] + options.aggregation === 'count' + ? [{ aggregation: 'count' }] : options.metrics.map(metric => ({ aggregation: metric.aggregation, field: metric.field, diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.test.tsx b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.test.tsx index e58184c78b4b83..1381ed9da656a9 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.test.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.test.tsx @@ -14,7 +14,6 @@ import { DEFAULT_OPTIONS, DEFAULT_TIMERANGE, } from './use_metrics_explorer_options'; -import { MetricsExplorerAggregation } from '../../../server/routes/metrics_explorer/types'; const renderUseMetricsExplorerOptionsHook = () => renderHook(() => useMetricsExplorerOptions(), { @@ -68,7 +67,7 @@ describe('useMetricExplorerOptions', () => { const { result, rerender } = renderUseMetricsExplorerOptionsHook(); const newOptions: MetricsExplorerOptions = { ...DEFAULT_OPTIONS, - metrics: [{ aggregation: MetricsExplorerAggregation.count }], + metrics: [{ aggregation: 'count' }], }; act(() => { result.current.setOptions(newOptions); @@ -95,7 +94,7 @@ describe('useMetricExplorerOptions', () => { it('should load from store when available', () => { const newOptions: MetricsExplorerOptions = { ...DEFAULT_OPTIONS, - metrics: [{ aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }], + metrics: [{ aggregation: 'avg', field: 'system.load.1' }], }; STORE.MetricsExplorerOptions = JSON.stringify(newOptions); const { result } = renderUseMetricsExplorerOptionsHook(); diff --git a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts index de7a8d5805ecc6..076a9159940e20 100644 --- a/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts +++ b/x-pack/legacy/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts @@ -62,24 +62,24 @@ export const DEFAULT_CHART_OPTIONS: MetricsExplorerChartOptions = { export const DEFAULT_METRICS: MetricsExplorerOptionsMetric[] = [ { - aggregation: MetricsExplorerAggregation.avg, + aggregation: 'avg', field: 'system.cpu.user.pct', color: MetricsExplorerColor.color0, }, { - aggregation: MetricsExplorerAggregation.avg, + aggregation: 'avg', field: 'kubernetes.pod.cpu.usage.node.pct', color: MetricsExplorerColor.color1, }, { - aggregation: MetricsExplorerAggregation.avg, + aggregation: 'avg', field: 'docker.cpu.total.pct', color: MetricsExplorerColor.color2, }, ]; export const DEFAULT_OPTIONS: MetricsExplorerOptions = { - aggregation: MetricsExplorerAggregation.avg, + aggregation: 'avg', metrics: DEFAULT_METRICS, }; diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.test.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.test.tsx index 0512fb0a46b901..14533d46aaef8e 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.test.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.test.tsx @@ -15,7 +15,6 @@ import { resp, createSeries, } from '../../../utils/fixtures/metrics_explorer'; -import { MetricsExplorerAggregation } from '../../../../server/routes/metrics_explorer/types'; const renderUseMetricsExplorerStateHook = () => renderHook(props => useMetricsExplorerState(props.source, props.derivedIndexPattern), { @@ -89,11 +88,9 @@ describe('useMetricsExplorerState', () => { it('should change the metric', async () => { const { result } = renderUseMetricsExplorerStateHook(); const { handleMetricsChange } = result.current; - handleMetricsChange([ - { aggregation: MetricsExplorerAggregation.max, field: 'system.load.1' }, - ]); + handleMetricsChange([{ aggregation: 'max', field: 'system.load.1' }]); expect(result.current.options.metrics).toEqual([ - { aggregation: MetricsExplorerAggregation.max, field: 'system.load.1' }, + { aggregation: 'max', field: 'system.load.1' }, ]); }); }); @@ -134,38 +131,32 @@ describe('useMetricsExplorerState', () => { it('should set the metrics to only count when selecting count', async () => { const { result, waitForNextUpdate } = renderUseMetricsExplorerStateHook(); const { handleMetricsChange } = result.current; - handleMetricsChange([ - { aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }, - ]); + handleMetricsChange([{ aggregation: 'avg', field: 'system.load.1' }]); expect(result.current.options.metrics).toEqual([ - { aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }, + { aggregation: 'avg', field: 'system.load.1' }, ]); await waitForNextUpdate(); const { handleAggregationChange } = result.current; - handleAggregationChange(MetricsExplorerAggregation.count); + handleAggregationChange('count'); await waitForNextUpdate(); - expect(result.current.options.aggregation).toBe(MetricsExplorerAggregation.count); - expect(result.current.options.metrics).toEqual([ - { aggregation: MetricsExplorerAggregation.count }, - ]); + expect(result.current.options.aggregation).toBe('count'); + expect(result.current.options.metrics).toEqual([{ aggregation: 'count' }]); }); it('should change aggregation for metrics', async () => { const { result, waitForNextUpdate } = renderUseMetricsExplorerStateHook(); const { handleMetricsChange } = result.current; - handleMetricsChange([ - { aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }, - ]); + handleMetricsChange([{ aggregation: 'avg', field: 'system.load.1' }]); expect(result.current.options.metrics).toEqual([ - { aggregation: MetricsExplorerAggregation.avg, field: 'system.load.1' }, + { aggregation: 'avg', field: 'system.load.1' }, ]); await waitForNextUpdate(); const { handleAggregationChange } = result.current; - handleAggregationChange(MetricsExplorerAggregation.max); + handleAggregationChange('max'); await waitForNextUpdate(); - expect(result.current.options.aggregation).toBe(MetricsExplorerAggregation.max); + expect(result.current.options.aggregation).toBe('max'); expect(result.current.options.metrics).toEqual([ - { aggregation: MetricsExplorerAggregation.max, field: 'system.load.1' }, + { aggregation: 'max', field: 'system.load.1' }, ]); }); }); diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts index 57ea8861697014..22d18234197b66 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts @@ -99,10 +99,10 @@ export const useMetricsExplorerState = ( (aggregation: MetricsExplorerAggregation) => { setAfterKey(null); const metrics = - aggregation === MetricsExplorerAggregation.count + aggregation === 'count' ? [{ aggregation }] : options.metrics - .filter(metric => metric.aggregation !== MetricsExplorerAggregation.count) + .filter(metric => metric.aggregation !== 'count') .map(metric => ({ ...metric, aggregation, diff --git a/x-pack/legacy/plugins/infra/public/utils/fixtures/metrics_explorer.ts b/x-pack/legacy/plugins/infra/public/utils/fixtures/metrics_explorer.ts index d553f03c4ed342..3d5198f2d379b9 100644 --- a/x-pack/legacy/plugins/infra/public/utils/fixtures/metrics_explorer.ts +++ b/x-pack/legacy/plugins/infra/public/utils/fixtures/metrics_explorer.ts @@ -5,10 +5,8 @@ */ import { - MetricsExplorerAggregation, MetricsExplorerResponse, MetricsExplorerSeries, - MetricsExplorerColumnType, } from '../../../server/routes/metrics_explorer/types'; import { MetricsExplorerOptions, @@ -21,8 +19,8 @@ import { export const options: MetricsExplorerOptions = { limit: 3, groupBy: 'host.name', - aggregation: MetricsExplorerAggregation.avg, - metrics: [{ aggregation: MetricsExplorerAggregation.avg, field: 'system.cpu.user.pct' }], + aggregation: 'avg', + metrics: [{ aggregation: 'avg', field: 'system.cpu.user.pct' }], }; export const source = { @@ -58,9 +56,9 @@ export const timeRange: MetricsExplorerTimeOptions = { export const createSeries = (id: string): MetricsExplorerSeries => ({ id, columns: [ - { name: 'timestamp', type: MetricsExplorerColumnType.date }, - { name: 'metric_0', type: MetricsExplorerColumnType.number }, - { name: 'groupBy', type: MetricsExplorerColumnType.string }, + { name: 'timestamp', type: 'date' }, + { name: 'metric_0', type: 'number' }, + { name: 'groupBy', type: 'string' }, ], rows: [ { timestamp: 1, metric_0: 0.5, groupBy: id }, diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts index a0fd6d3e951bfb..28d5f75c3fdaf8 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -9,19 +9,21 @@ import { Lifecycle } from 'hapi'; import { ObjectType } from '@kbn/config-schema'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { RouteMethod, RouteConfig } from '../../../../../../../../src/core/server'; +import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../../plugins/features/server'; +import { SpacesPluginSetup } from '../../../../../../../plugins/spaces/server'; import { APMPluginContract } from '../../../../../../../plugins/apm/server'; // NP_TODO: Compose real types from plugins we depend on, no "any" export interface InfraServerPluginDeps { + spaces: SpacesPluginSetup; usageCollection: UsageCollectionSetup; - spaces: any; metrics: { getVisData: any; }; indexPatterns: { indexPatternsServiceFactory: any; }; - features: any; + features: FeaturesPluginSetup; apm: APMPluginContract; ___legacy: any; } diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index 19121d92f02c90..b0cdb8389cb290 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -147,10 +147,6 @@ export class KibanaFramework { headers, body: errorBody, }); - - // NP_TODO: Do we still need to re-throw this error in this case? if we do, can we - // still call the response.customError method to control the HTTP response? - // throw error; } } this.router.post(routeOptions, handler); @@ -250,7 +246,7 @@ export class KibanaFramework { } } - // NP_TODO: This method needs to no longer require full KibanaRequest + // NP_TODO: [TSVB_GROUP] This method needs fixing when the metrics plugin has migrated to the New Platform public async makeTSVBRequest( request: KibanaRequest, model: TSVBMetricModel, diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/adapter_types.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/adapter_types.ts index acd7a2528bb424..844eaf76049277 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/adapter_types.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/adapter_types.ts @@ -28,7 +28,7 @@ export interface InfraMetricsAdapter { getMetrics( requestContext: RequestHandlerContext, options: InfraMetricsRequestOptions, - request: KibanaRequest // NP_TODO: temporarily needed until metrics getVisData no longer needs full request + request: KibanaRequest ): Promise; } diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index c4146f5758d80c..c1b567576c2149 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -25,7 +25,7 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { public async getMetrics( requestContext: RequestHandlerContext, options: InfraMetricsRequestOptions, - rawRequest: KibanaRequest // NP_TODO: Temporarily needed until metrics getVisData no longer needs full request + rawRequest: KibanaRequest ): Promise { const indexPattern = `${options.sourceConfiguration.metricAlias},${options.sourceConfiguration.logAlias}`; const fields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); diff --git a/x-pack/legacy/plugins/infra/server/lib/domains/metrics_domain.ts b/x-pack/legacy/plugins/infra/server/lib/domains/metrics_domain.ts index 5d7d54a6a2e501..e53e45afae5c48 100644 --- a/x-pack/legacy/plugins/infra/server/lib/domains/metrics_domain.ts +++ b/x-pack/legacy/plugins/infra/server/lib/domains/metrics_domain.ts @@ -18,7 +18,7 @@ export class InfraMetricsDomain { public async getMetrics( requestContext: RequestHandlerContext, options: InfraMetricsRequestOptions, - rawRequest: KibanaRequest // NP_TODO: temporarily needed until metrics getVisData no longer needs full request + rawRequest: KibanaRequest ): Promise { return await this.adapter.getMetrics(requestContext, options, rawRequest); } diff --git a/x-pack/legacy/plugins/infra/server/new_platform_index.ts b/x-pack/legacy/plugins/infra/server/new_platform_index.ts index 6b759ecfe9fde9..e59897a6b241dc 100644 --- a/x-pack/legacy/plugins/infra/server/new_platform_index.ts +++ b/x-pack/legacy/plugins/infra/server/new_platform_index.ts @@ -5,11 +5,10 @@ */ import { PluginInitializerContext } from 'src/core/server'; -import { InfraServerPlugin } from './new_platform_plugin'; +import { InfraServerPlugin, InfraPluginSetup } from './new_platform_plugin'; import { config, InfraConfig } from '../../../../plugins/infra/server'; import { InfraServerPluginDeps } from './lib/adapters/framework'; - -export { config, InfraConfig, InfraServerPluginDeps }; +export { config, InfraConfig, InfraServerPluginDeps, InfraPluginSetup }; export function plugin(context: PluginInitializerContext) { return new InfraServerPlugin(context); diff --git a/x-pack/legacy/plugins/infra/server/new_platform_plugin.ts b/x-pack/legacy/plugins/infra/server/new_platform_plugin.ts index 462a07574b2dd4..ad26663402adc4 100644 --- a/x-pack/legacy/plugins/infra/server/new_platform_plugin.ts +++ b/x-pack/legacy/plugins/infra/server/new_platform_plugin.ts @@ -23,11 +23,19 @@ import { InfraSources } from './lib/sources'; import { InfraServerPluginDeps } from './lib/adapters/framework'; import { METRICS_FEATURE, LOGS_FEATURE } from './features'; import { UsageCollector } from './usage/usage_collector'; +import { InfraStaticSourceConfiguration } from './lib/sources/types'; export interface KbnServer extends Server { usage: any; } +export interface InfraPluginSetup { + defineInternalSourceConfiguration: ( + sourceId: string, + sourceProperties: InfraStaticSourceConfiguration + ) => void; +} + const DEFAULT_CONFIG: InfraConfig = { enabled: true, query: { @@ -103,5 +111,11 @@ export class InfraServerPlugin { // Telemetry UsageCollector.registerUsageCollector(plugins.usageCollection); + + return { + defineInternalSourceConfiguration(sourceId, sourceProperties) { + sources.defineInternalSourceConfiguration(sourceId, sourceProperties); + }, + } as InfraPluginSetup; } } diff --git a/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts index 02866e797e305b..9778311bd8e58c 100644 --- a/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts +++ b/x-pack/legacy/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts @@ -33,12 +33,12 @@ export const initGetLogEntryRateRoute = ({ framework, logAnalysis }: InfraBacken }, }, async (requestContext, request, response) => { - const payload = pipe( - getLogEntryRateRequestPayloadRT.decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - try { + const payload = pipe( + getLogEntryRateRequestPayloadRT.decode(request.body), + fold(throwErrors(Boom.badRequest), identity) + ); + const logEntryRateBuckets = await logAnalysis.getLogEntryRateBuckets( requestContext, payload.data.sourceId, diff --git a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/index.ts b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/index.ts index 0c69034c669400..64cdb9318b6e18 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/index.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/index.ts @@ -4,15 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ +import Boom from 'boom'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; import { schema } from '@kbn/config-schema'; import { InfraBackendLibs } from '../../lib/infra_types'; import { getGroupings } from './lib/get_groupings'; import { populateSeriesWithTSVBData } from './lib/populate_series_with_tsvb_data'; -import { MetricsExplorerRequestBody } from './types'; -// import { metricsExplorerSchema } from './schema'; -// import { MetricsExplorerResponse, MetricsExplorerRequestBody } from './types'; +import { metricsExplorerRequestBodyRT, metricsExplorerResponseRT } from '../../../common/http_api'; +import { throwErrors } from '../../../common/runtime_types'; -// NP_TODO: need to replace all of this with real types or io-ts or something? const escapeHatch = schema.object({}, { allowUnknowns: true }); export const initMetricExplorerRoute = (libs: InfraBackendLibs) => { @@ -29,20 +31,27 @@ export const initMetricExplorerRoute = (libs: InfraBackendLibs) => { }, async (requestContext, request, response) => { try { + const payload = pipe( + metricsExplorerRequestBodyRT.decode(request.body), + fold(throwErrors(Boom.badRequest), identity) + ); + const search = (searchOptions: object) => callWithRequest<{}, Aggregation>(requestContext, 'search', searchOptions); - const options = request.body as MetricsExplorerRequestBody; // Need to remove this casting and swap in config-schema demands :( + // First we get the groupings from a composite aggregation - const groupings = await getGroupings(search, options); + const groupings = await getGroupings(search, payload); // Then we take the results and fill in the data from TSVB with the // user's custom metrics const seriesWithMetrics = await Promise.all( groupings.series.map( - populateSeriesWithTSVBData(request, options, framework, requestContext) + populateSeriesWithTSVBData(request, payload, framework, requestContext) ) ); - return response.ok({ body: { ...groupings, series: seriesWithMetrics } }); + return response.ok({ + body: metricsExplorerResponseRT.encode({ ...groupings, series: seriesWithMetrics }), + }); } catch (error) { return response.internalError({ body: error.message, diff --git a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts index 64b9fba0e7aa26..9e5fe16d482b2d 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts @@ -5,7 +5,7 @@ */ import { InfraMetricModelMetricType } from '../../../lib/adapters/metrics'; -import { MetricsExplorerAggregation, MetricsExplorerRequestBody } from '../types'; +import { MetricsExplorerRequestBody } from '../types'; import { InfraMetric } from '../../../graphql/types'; import { TSVBMetricModel } from '../../../../common/inventory_models/types'; export const createMetricModel = (options: MetricsExplorerRequestBody): TSVBMetricModel => { @@ -20,7 +20,7 @@ export const createMetricModel = (options: MetricsExplorerRequestBody): TSVBMetr // when the responses are processed and combined with the grouping request. series: options.metrics.map((metric, index) => { // If the metric is a rate then we need to add TSVB metrics for calculating the derivative - if (metric.aggregation === MetricsExplorerAggregation.rate) { + if (metric.aggregation === 'rate') { const aggType = 'max'; return { id: `metric_${index}`, @@ -49,8 +49,7 @@ export const createMetricModel = (options: MetricsExplorerRequestBody): TSVBMetr }; } // Create a basic TSVB series with a single metric - const aggregation = - MetricsExplorerAggregation[metric.aggregation] || MetricsExplorerAggregation.avg; + const aggregation = metric.aggregation || 'avg'; return { id: `metric_${index}`, diff --git a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts index 1a0edb1053730c..3dfbfbb5c39797 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts @@ -8,10 +8,10 @@ import { union } from 'lodash'; import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; import { - MetricsExplorerColumnType, MetricsExplorerRow, MetricsExplorerSeries, MetricsExplorerRequestBody, + MetricsExplorerColumn, } from '../types'; import { createMetricModel } from './create_metrics_model'; import { JsonObject } from '../../../../common/typed_json'; @@ -95,11 +95,11 @@ export const populateSeriesWithTSVBData = ( // Setup the dynamic columns and row attributes depending on if the user is doing a group by // and multiple metrics - const attributeColumns = - options.groupBy != null ? [{ name: 'groupBy', type: MetricsExplorerColumnType.string }] : []; - const metricColumns = options.metrics.map((m, i) => ({ + const attributeColumns: MetricsExplorerColumn[] = + options.groupBy != null ? [{ name: 'groupBy', type: 'string' }] : []; + const metricColumns: MetricsExplorerColumn[] = options.metrics.map((m, i) => ({ name: `metric_${i}`, - type: MetricsExplorerColumnType.number, + type: 'number', })); const rowAttributes = options.groupBy != null ? { groupBy: series.id } : {}; @@ -132,7 +132,7 @@ export const populateSeriesWithTSVBData = ( ...series, rows, columns: [ - { name: 'timestamp', type: MetricsExplorerColumnType.date }, + { name: 'timestamp', type: 'date' } as MetricsExplorerColumn, ...metricColumns, ...attributeColumns, ], diff --git a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/schema.ts b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/schema.ts deleted file mode 100644 index 00231bc2a7938c..00000000000000 --- a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/schema.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 * as Joi from 'joi'; -import { values } from 'lodash'; -import { MetricsExplorerColor } from '../../../common/color_palette'; -import { MetricsExplorerAggregation } from './types'; - -export const metricsExplorerSchema = Joi.object({ - limit: Joi.number() - .min(1) - .default(9), - afterKey: Joi.string().allow(null), - groupBy: Joi.string().allow(null), - indexPattern: Joi.string().required(), - metrics: Joi.array() - .items( - Joi.object().keys({ - aggregation: Joi.string() - .valid(values(MetricsExplorerAggregation)) - .required(), - field: Joi.string(), - rate: Joi.bool().default(false), - color: Joi.string().valid(values(MetricsExplorerColor)), - label: Joi.string(), - }) - ) - .required(), - filterQuery: Joi.string(), - timerange: Joi.object() - .keys({ - field: Joi.string().required(), - from: Joi.number().required(), - to: Joi.number().required(), - interval: Joi.string().required(), - }) - .required(), -}); diff --git a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/types.ts b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/types.ts index a43e3adbdd184f..f4c5e26c5c6d13 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/types.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metrics_explorer/types.ts @@ -4,65 +4,33 @@ * you may not use this file except in compliance with the Elastic License. */ -export interface InfraTimerange { - field: string; - from: number; - to: number; - interval: string; -} +import * as rt from 'io-ts'; +import { + metricsExplorerMetricRT, + metricsExplorerPageInfoRT, + metricsExplorerColumnRT, + metricsExplorerRowRT, + metricsExplorerSeriesRT, + metricsExplorerRequestBodyRT, + metricsExplorerResponseRT, + metricsExplorerAggregationRT, + metricsExplorerColumnTypeRT, +} from '../../../common/http_api'; -export enum MetricsExplorerAggregation { - avg = 'avg', - max = 'max', - min = 'min', - cardinality = 'cardinality', - rate = 'rate', - count = 'count', -} +export type MetricsExplorerAggregation = rt.TypeOf; -export interface MetricsExplorerMetric { - aggregation: MetricsExplorerAggregation; - field?: string | undefined; -} +export type MetricsExplorerColumnType = rt.TypeOf; -export interface MetricsExplorerRequestBody { - timerange: InfraTimerange; - indexPattern: string; - metrics: MetricsExplorerMetric[]; - groupBy?: string; - afterKey?: string; - limit?: number; - filterQuery?: string; -} +export type MetricsExplorerMetric = rt.TypeOf; -export interface MetricsExplorerPageInfo { - total: number; - afterKey?: string | null; -} +export type MetricsExplorerPageInfo = rt.TypeOf; -export enum MetricsExplorerColumnType { - date = 'date', - number = 'number', - string = 'string', -} +export type MetricsExplorerColumn = rt.TypeOf; -export interface MetricsExplorerColumn { - name: string; - type: MetricsExplorerColumnType; -} +export type MetricsExplorerRow = rt.TypeOf; -export interface MetricsExplorerRow { - timestamp: number; - [key: string]: string | number | null | undefined; -} +export type MetricsExplorerSeries = rt.TypeOf; -export interface MetricsExplorerSeries { - id: string; - columns: MetricsExplorerColumn[]; - rows: MetricsExplorerRow[]; -} +export type MetricsExplorerRequestBody = rt.TypeOf; -export interface MetricsExplorerResponse { - series: MetricsExplorerSeries[]; - pageInfo: MetricsExplorerPageInfo; -} +export type MetricsExplorerResponse = rt.TypeOf; diff --git a/x-pack/plugins/infra/kibana.json b/x-pack/plugins/infra/kibana.json index b0670a58ae1e8f..ec5420a4d28d58 100644 --- a/x-pack/plugins/infra/kibana.json +++ b/x-pack/plugins/infra/kibana.json @@ -1,5 +1,6 @@ { "id": "infra", "version": "8.0.0", + "kibanaVersion": "kibana", "server": true } From 2d36b216afb3b29187b2ec0cd261ac3b6ec634d9 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Tue, 17 Dec 2019 13:00:54 -0600 Subject: [PATCH 23/60] move management registry to new platform (#53020) * move management registry to new platform --- .i18nrc.json | 2 +- .../public/components/telemetry_form.js | 2 +- src/legacy/ui/public/management/index.js | 5 +- .../public/new_platform/__mocks__/helpers.ts | 2 + .../new_platform/new_platform.karma_mock.js | 7 +++ .../ui/public/new_platform/new_platform.ts | 2 + src/plugins/management/kibana.json | 7 +++ src/plugins/management/public/index.ts | 27 +++++++++ .../management/public/legacy}/index.js | 11 +--- .../management/public/legacy}/section.js | 10 ++-- .../management/public/legacy}/section.test.js | 55 ++++++++--------- .../public/legacy}/sections_register.js | 60 +++++++++++-------- src/plugins/management/public/mocks/index.ts | 26 ++++++++ src/plugins/management/public/plugin.ts | 35 +++++++++++ src/plugins/management/public/types.ts | 22 +++++++ .../__jest__/start_trial.test.js | 1 + .../__jest__/telemetry_opt_in.test.js | 4 +- .../__jest__/upload_license.test.tsx | 2 + .../remote_clusters_add.test.js | 2 + .../remote_clusters_edit.test.js | 1 + .../remote_clusters_list.test.js | 2 + .../sections/job_list/job_list.test.js | 1 - .../__jest__/client_integration/home.test.ts | 1 + .../client_integration/policy_edit.test.ts | 2 + .../client_integration/repository_add.test.ts | 2 + .../repository_edit.test.ts | 2 + .../translations/translations/ja-JP.json | 4 +- .../translations/translations/zh-CN.json | 6 +- 28 files changed, 220 insertions(+), 83 deletions(-) create mode 100644 src/plugins/management/kibana.json create mode 100644 src/plugins/management/public/index.ts rename src/{legacy/ui/public/management/__tests__ => plugins/management/public/legacy}/index.js (76%) rename src/{legacy/ui/public/management => plugins/management/public/legacy}/section.js (92%) rename src/{legacy/ui/public/management => plugins/management/public/legacy}/section.test.js (83%) rename src/{legacy/ui/public/management => plugins/management/public/legacy}/sections_register.js (54%) create mode 100644 src/plugins/management/public/mocks/index.ts create mode 100644 src/plugins/management/public/plugin.ts create mode 100644 src/plugins/management/public/types.ts diff --git a/.i18nrc.json b/.i18nrc.json index ddde50b62a8f39..23f3d6ee33829d 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -21,7 +21,7 @@ "kbn": "src/legacy/core_plugins/kibana", "kbnDocViews": "src/legacy/core_plugins/kbn_doc_views", "kbnVislibVisTypes": "src/legacy/core_plugins/kbn_vislib_vis_types", - "management": "src/legacy/core_plugins/management", + "management": ["src/legacy/core_plugins/management", "src/plugins/management"], "kibana_react": "src/legacy/core_plugins/kibana_react", "kibana-react": "src/plugins/kibana_react", "kibana_utils": "src/plugins/kibana_utils", diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js index 94a387565f38d7..aed84770571652 100644 --- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js +++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js @@ -31,7 +31,7 @@ import { } from '@elastic/eui'; import { PRIVACY_STATEMENT_URL } from '../../common/constants'; import { OptInExampleFlyout } from './opt_in_details_component'; -import { Field } from 'ui/management'; +import { Field } from '../../../kibana/public/management/sections/settings/components/field/field'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; diff --git a/src/legacy/ui/public/management/index.js b/src/legacy/ui/public/management/index.js index a27ff493b317e5..ed8ddb65315e2c 100644 --- a/src/legacy/ui/public/management/index.js +++ b/src/legacy/ui/public/management/index.js @@ -23,7 +23,8 @@ export { PAGE_FOOTER_COMPONENT, } from '../../../core_plugins/kibana/public/management/sections/settings/components/default_component_registry'; export { registerSettingsComponent } from '../../../core_plugins/kibana/public/management/sections/settings/components/component_registry'; -export { Field } from '../../../core_plugins/kibana/public/management/sections/settings/components/field/field'; -export { management } from './sections_register'; export { SidebarNav } from './components'; export { MANAGEMENT_BREADCRUMB } from './breadcrumbs'; + +import { npStart } from 'ui/new_platform'; +export const management = npStart.plugins.management.legacy; diff --git a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts index a0a917bc480499..d1d7603bd82ed0 100644 --- a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts +++ b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts @@ -25,6 +25,7 @@ import { navigationPluginMock } from '../../../../../plugins/navigation/public/m import { expressionsPluginMock } from '../../../../../plugins/expressions/public/mocks'; import { inspectorPluginMock } from '../../../../../plugins/inspector/public/mocks'; import { uiActionsPluginMock } from '../../../../../plugins/ui_actions/public/mocks'; +import { managementPluginMock } from '../../../../../plugins/management/public/mocks'; import { usageCollectionPluginMock } from '../../../../../plugins/usage_collection/public/mocks'; /* eslint-enable @kbn/eslint/no-restricted-paths */ @@ -45,6 +46,7 @@ export const pluginsMock = { inspector: inspectorPluginMock.createStartContract(), expressions: expressionsPluginMock.createStartContract(), uiActions: uiActionsPluginMock.createStartContract(), + management: managementPluginMock.createStartContract(), }), }; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 20a7e0d5dde8d3..3b2a77cefb7305 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -137,6 +137,13 @@ export const npStart = { chrome: {}, }, plugins: { + management: { + legacy: { + getSection: () => ({ + register: sinon.fake(), + }), + }, + }, embeddable: { getEmbeddableFactory: sinon.fake(), getEmbeddableFactories: sinon.fake(), diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index 138bb4135c507d..df3fa7c6ea466c 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -32,6 +32,7 @@ import { DevToolsSetup, DevToolsStart } from '../../../../plugins/dev_tools/publ import { KibanaLegacySetup, KibanaLegacyStart } from '../../../../plugins/kibana_legacy/public'; import { HomePublicPluginSetup, HomePublicPluginStart } from '../../../../plugins/home/public'; import { SharePluginSetup, SharePluginStart } from '../../../../plugins/share/public'; +import { ManagementStart } from '../../../../plugins/management/public'; import { BfetchPublicSetup, BfetchPublicStart } from '../../../../plugins/bfetch/public'; import { UsageCollectionSetup } from '../../../../plugins/usage_collection/public'; import { @@ -67,6 +68,7 @@ export interface PluginsStart { dev_tools: DevToolsStart; kibana_legacy: KibanaLegacyStart; share: SharePluginStart; + management: ManagementStart; } export const npSetup = { diff --git a/src/plugins/management/kibana.json b/src/plugins/management/kibana.json new file mode 100644 index 00000000000000..755a387afbd051 --- /dev/null +++ b/src/plugins/management/kibana.json @@ -0,0 +1,7 @@ +{ + "id": "management", + "version": "kibana", + "server": false, + "ui": true, + "requiredPlugins": [] +} diff --git a/src/plugins/management/public/index.ts b/src/plugins/management/public/index.ts new file mode 100644 index 00000000000000..ee3866c734f194 --- /dev/null +++ b/src/plugins/management/public/index.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginInitializerContext } from 'kibana/public'; +import { ManagementPlugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new ManagementPlugin(); +} + +export { ManagementStart } from './types'; diff --git a/src/legacy/ui/public/management/__tests__/index.js b/src/plugins/management/public/legacy/index.js similarity index 76% rename from src/legacy/ui/public/management/__tests__/index.js rename to src/plugins/management/public/legacy/index.js index 6c794b3c189f0f..63b9d2c6b27d7e 100644 --- a/src/legacy/ui/public/management/__tests__/index.js +++ b/src/plugins/management/public/legacy/index.js @@ -17,13 +17,4 @@ * under the License. */ -import expect from '@kbn/expect'; - -import { management } from '..'; -import { ManagementSection } from '../section'; - -describe('Management', () => { - it('provides ManagementSection', () => { - expect(management).to.be.a(ManagementSection); - }); -}); +export { management } from './sections_register'; diff --git a/src/legacy/ui/public/management/section.js b/src/plugins/management/public/legacy/section.js similarity index 92% rename from src/legacy/ui/public/management/section.js rename to src/plugins/management/public/legacy/section.js index b6952695cd910d..f269e3fe295b75 100644 --- a/src/legacy/ui/public/management/section.js +++ b/src/plugins/management/public/legacy/section.js @@ -18,8 +18,7 @@ */ import { assign } from 'lodash'; -import { IndexedArray } from '../indexed_array'; -import { capabilities } from '../capabilities'; +import { IndexedArray } from '../../../../legacy/ui/public/indexed_array'; const listeners = []; @@ -37,7 +36,7 @@ export class ManagementSection { * @returns {ManagementSection} */ - constructor(id, options = {}) { + constructor(id, options = {}, capabilities) { this.display = id; this.id = id; this.items = new IndexedArray({ @@ -49,13 +48,14 @@ export class ManagementSection { this.tooltip = ''; this.icon = ''; this.url = ''; + this.capabilities = capabilities; assign(this, options); } get visibleItems() { return this.items.inOrder.filter(item => { - const capabilityManagementSection = capabilities.get().management[this.id]; + const capabilityManagementSection = this.capabilities.management[this.id]; const itemCapability = capabilityManagementSection ? capabilityManagementSection[item.id] : null; @@ -83,7 +83,7 @@ export class ManagementSection { */ register(id, options = {}) { - const item = new ManagementSection(id, assign(options, { parent: this })); + const item = new ManagementSection(id, assign(options, { parent: this }), this.capabilities); if (this.hasItem(id)) { throw new Error(`'${id}' is already registered`); diff --git a/src/legacy/ui/public/management/section.test.js b/src/plugins/management/public/legacy/section.test.js similarity index 83% rename from src/legacy/ui/public/management/section.test.js rename to src/plugins/management/public/legacy/section.test.js index e3e0dd3a427cbe..61bafd298afb32 100644 --- a/src/legacy/ui/public/management/section.test.js +++ b/src/plugins/management/public/legacy/section.test.js @@ -16,62 +16,59 @@ * specific language governing permissions and limitations * under the License. */ -jest.mock('ui/capabilities', () => ({ - capabilities: { - get: () => ({ - navLinks: {}, - management: { - kibana: { - sampleFeature1: true, - sampleFeature2: false, - }, - }, - }), - }, -})); import { ManagementSection } from './section'; -import { IndexedArray } from '../indexed_array'; +import { IndexedArray } from '../../../../legacy/ui/public/indexed_array'; + +const capabilitiesMock = { + management: { + kibana: { sampleFeature2: false }, + }, +}; describe('ManagementSection', () => { describe('constructor', () => { it('defaults display to id', () => { - const section = new ManagementSection('kibana'); + const section = new ManagementSection('kibana', {}, capabilitiesMock); expect(section.display).toBe('kibana'); }); it('defaults visible to true', () => { - const section = new ManagementSection('kibana'); + const section = new ManagementSection('kibana', {}, capabilitiesMock); expect(section.visible).toBe(true); }); it('defaults disabled to false', () => { - const section = new ManagementSection('kibana'); + const section = new ManagementSection('kibana', {}, capabilitiesMock); expect(section.disabled).toBe(false); }); it('defaults tooltip to empty string', () => { - const section = new ManagementSection('kibana'); + const section = new ManagementSection('kibana', {}, capabilitiesMock); expect(section.tooltip).toBe(''); }); it('defaults url to empty string', () => { - const section = new ManagementSection('kibana'); + const section = new ManagementSection('kibana', {}, capabilitiesMock); expect(section.url).toBe(''); }); it('exposes items', () => { - const section = new ManagementSection('kibana'); + const section = new ManagementSection('kibana', {}, capabilitiesMock); expect(section.items).toHaveLength(0); }); it('exposes visibleItems', () => { - const section = new ManagementSection('kibana'); + const section = new ManagementSection('kibana', {}, capabilitiesMock); expect(section.visibleItems).toHaveLength(0); }); it('assigns all options', () => { - const section = new ManagementSection('kibana', { description: 'test', url: 'foobar' }); + const section = new ManagementSection( + 'kibana', + { description: 'test', url: 'foobar' }, + capabilitiesMock + ); expect(section.description).toBe('test'); expect(section.url).toBe('foobar'); }); @@ -81,7 +78,7 @@ describe('ManagementSection', () => { let section; beforeEach(() => { - section = new ManagementSection('kibana'); + section = new ManagementSection('kibana', {}, capabilitiesMock); }); it('returns a ManagementSection', () => { @@ -129,7 +126,7 @@ describe('ManagementSection', () => { let section; beforeEach(() => { - section = new ManagementSection('kibana'); + section = new ManagementSection('kibana', {}, capabilitiesMock); section.register('about'); }); @@ -160,7 +157,7 @@ describe('ManagementSection', () => { let section; beforeEach(() => { - section = new ManagementSection('kibana'); + section = new ManagementSection('kibana', {}, capabilitiesMock); section.register('about'); }); @@ -187,7 +184,7 @@ describe('ManagementSection', () => { let section; beforeEach(() => { - section = new ManagementSection('kibana'); + section = new ManagementSection('kibana', {}, capabilitiesMock); section.register('three', { order: 3 }); section.register('one', { order: 1 }); @@ -217,7 +214,7 @@ describe('ManagementSection', () => { let section; beforeEach(() => { - section = new ManagementSection('kibana'); + section = new ManagementSection('kibana', {}, capabilitiesMock); }); it('hide sets visible to false', () => { @@ -236,7 +233,7 @@ describe('ManagementSection', () => { let section; beforeEach(() => { - section = new ManagementSection('kibana'); + section = new ManagementSection('kibana', {}, capabilitiesMock); }); it('disable sets disabled to true', () => { @@ -254,7 +251,7 @@ describe('ManagementSection', () => { let section; beforeEach(() => { - section = new ManagementSection('kibana'); + section = new ManagementSection('kibana', {}, capabilitiesMock); section.register('three', { order: 3 }); section.register('one', { order: 1 }); diff --git a/src/legacy/ui/public/management/sections_register.js b/src/plugins/management/public/legacy/sections_register.js similarity index 54% rename from src/legacy/ui/public/management/sections_register.js rename to src/plugins/management/public/legacy/sections_register.js index a63fd390ea3caa..888b2c5bc3aeb6 100644 --- a/src/legacy/ui/public/management/sections_register.js +++ b/src/plugins/management/public/legacy/sections_register.js @@ -20,33 +20,41 @@ import { ManagementSection } from './section'; import { i18n } from '@kbn/i18n'; -export const management = new ManagementSection('management', { - display: i18n.translate('common.ui.management.displayName', { - defaultMessage: 'Management', - }), -}); +export const management = capabilities => { + const main = new ManagementSection( + 'management', + { + display: i18n.translate('management.displayName', { + defaultMessage: 'Management', + }), + }, + capabilities + ); -management.register('data', { - display: i18n.translate('common.ui.management.connectDataDisplayName', { - defaultMessage: 'Connect Data', - }), - order: 0, -}); + main.register('data', { + display: i18n.translate('management.connectDataDisplayName', { + defaultMessage: 'Connect Data', + }), + order: 0, + }); -management.register('elasticsearch', { - display: 'Elasticsearch', - order: 20, - icon: 'logoElasticsearch', -}); + main.register('elasticsearch', { + display: 'Elasticsearch', + order: 20, + icon: 'logoElasticsearch', + }); -management.register('kibana', { - display: 'Kibana', - order: 30, - icon: 'logoKibana', -}); + main.register('kibana', { + display: 'Kibana', + order: 30, + icon: 'logoKibana', + }); -management.register('logstash', { - display: 'Logstash', - order: 30, - icon: 'logoLogstash', -}); + main.register('logstash', { + display: 'Logstash', + order: 30, + icon: 'logoLogstash', + }); + + return main; +}; diff --git a/src/plugins/management/public/mocks/index.ts b/src/plugins/management/public/mocks/index.ts new file mode 100644 index 00000000000000..cc56928e8e5298 --- /dev/null +++ b/src/plugins/management/public/mocks/index.ts @@ -0,0 +1,26 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const createStartContract = () => ({ + legacy: {}, +}); + +export const managementPluginMock = { + createStartContract, +}; diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts new file mode 100644 index 00000000000000..c65dfd1dc7bb45 --- /dev/null +++ b/src/plugins/management/public/plugin.ts @@ -0,0 +1,35 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { ManagementStart } from './types'; +// @ts-ignore +import { management } from './legacy'; + +export class ManagementPlugin implements Plugin<{}, ManagementStart> { + public setup(core: CoreSetup) { + return {}; + } + + public start(core: CoreStart) { + return { + legacy: management(core.application.capabilities), + }; + } +} diff --git a/src/plugins/management/public/types.ts b/src/plugins/management/public/types.ts new file mode 100644 index 00000000000000..6ca1faf338c39f --- /dev/null +++ b/src/plugins/management/public/types.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface ManagementStart { + legacy: any; +} diff --git a/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js b/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js index 69c606c866eef3..5436a51a2632b0 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js +++ b/x-pack/legacy/plugins/license_management/__jest__/start_trial.test.js @@ -6,6 +6,7 @@ import { StartTrial } from '../public/np_ready/application/sections/license_dashboard/start_trial'; import { createMockLicense, getComponent } from './util'; +jest.mock('ui/new_platform'); jest.mock(`@elastic/eui/lib/components/form/form_row/make_id`, () => () => `generated-id`); describe('StartTrial component when trial is allowed', () => { diff --git a/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js b/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js index 8df35b797bf45a..1b03ce869e52bf 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js +++ b/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js @@ -11,9 +11,7 @@ import { import { TelemetryOptIn } from '../public/np_ready/application/components/telemetry_opt_in'; import { mountWithIntl } from '../../../../test_utils/enzyme_helpers'; -jest.mock('ui/capabilities', () => ({ - get: jest.fn(), -})); +jest.mock('ui/new_platform'); setTelemetryEnabled(true); diff --git a/x-pack/legacy/plugins/license_management/__jest__/upload_license.test.tsx b/x-pack/legacy/plugins/license_management/__jest__/upload_license.test.tsx index b852daf78ca158..ca9b5b0db9ca1a 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/upload_license.test.tsx +++ b/x-pack/legacy/plugins/license_management/__jest__/upload_license.test.tsx @@ -9,6 +9,8 @@ import { mountWithIntl } from '../../../../test_utils/enzyme_helpers'; import React from 'react'; import { Provider } from 'react-redux'; +jest.mock('ui/new_platform'); + // @ts-ignore import { uploadLicense } from '../public/np_ready/application/store/actions/upload_license'; diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js b/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js index c1ef7db2efc5cf..8f34e7d84a08be 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js +++ b/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_add.test.js @@ -7,6 +7,8 @@ import { pageHelpers, nextTick, setupEnvironment } from './helpers'; import { NON_ALPHA_NUMERIC_CHARS, ACCENTED_CHARS } from './helpers/constants'; +jest.mock('ui/new_platform'); + const { setup } = pageHelpers.remoteClustersAdd; describe('Create Remote cluster', () => { diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js b/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js index c380eaadd8e64c..95dc65a96e30a3 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js +++ b/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_edit.test.js @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +jest.mock('ui/new_platform'); import { RemoteClusterForm } from '../../public/app/sections/components/remote_cluster_form'; import { pageHelpers, setupEnvironment, nextTick } from './helpers'; import { REMOTE_CLUSTER_EDIT, REMOTE_CLUSTER_EDIT_NAME } from './helpers/constants'; diff --git a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js b/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js index 178dd341a75a7f..699c00e450a1fd 100644 --- a/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js +++ b/x-pack/legacy/plugins/remote_clusters/__jest__/client_integration/remote_clusters_list.test.js @@ -15,6 +15,8 @@ import { import { getRouter } from '../../public/app/services'; import { getRemoteClusterMock } from '../../fixtures/remote_cluster'; +jest.mock('ui/new_platform'); + const { setup } = pageHelpers.remoteClustersList; describe('', () => { diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js index 627091e0cf7492..5c7d53efbd62ce 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js @@ -9,7 +9,6 @@ import { rollupJobsStore } from '../../store'; import { JobList } from './job_list'; jest.mock('ui/new_platform'); - jest.mock('ui/chrome', () => ({ addBasePath: () => {}, breadcrumbs: { set: () => {} }, diff --git a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/home.test.ts b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/home.test.ts index effab0fcadf4df..69b5ca9e2b68f9 100644 --- a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/home.test.ts +++ b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/home.test.ts @@ -21,6 +21,7 @@ import moment from 'moment-timezone'; const { setup } = pageHelpers.home; +jest.mock('ui/new_platform'); jest.mock('ui/i18n', () => { const I18nContext = ({ children }: any) => children; return { I18nContext }; diff --git a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts index e14a080137c607..1222697956ffba 100644 --- a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts +++ b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts @@ -11,6 +11,8 @@ import { PolicyForm } from '../../public/app/components/policy_form'; import { PolicyFormTestBed } from './helpers/policy_form.helpers'; import { POLICY_EDIT } from './helpers/constant'; +jest.mock('ui/new_platform'); + const { setup } = pageHelpers.policyEdit; const { setup: setupPolicyAdd } = pageHelpers.policyAdd; diff --git a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts index df250159c7f696..1f70755d5fd85a 100644 --- a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts +++ b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts @@ -11,6 +11,8 @@ import { RepositoryType } from '../../common/types'; import { setupEnvironment, pageHelpers, nextTick } from './helpers'; import { RepositoryAddTestBed } from './helpers/repository_add.helpers'; +jest.mock('ui/new_platform'); + const { setup } = pageHelpers.repositoryAdd; const repositoryTypes = ['fs', 'url', 'source', 'azure', 'gcs', 's3', 'hdfs']; diff --git a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts index ef74482fc9de79..cca81c0e74285e 100644 --- a/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts +++ b/x-pack/legacy/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts @@ -12,6 +12,8 @@ import { RepositoryEditTestSubjects } from './helpers/repository_edit.helpers'; import { RepositoryAddTestSubjects } from './helpers/repository_add.helpers'; import { REPOSITORY_EDIT } from './helpers/constant'; +jest.mock('ui/new_platform'); + const { setup } = pageHelpers.repositoryEdit; const { setup: setupRepositoryAdd } = pageHelpers.repositoryAdd; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b7036399f3f718..413e0a9a4cc505 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -461,8 +461,8 @@ "common.ui.legacyBrowserMessage": "この Kibana インストレーションは、現在ご使用のブラウザが満たしていない厳格なセキュリティ要件が有効になっています。", "common.ui.legacyBrowserTitle": "ブラウザをアップグレードしてください", "common.ui.management.breadcrumb": "管理", - "common.ui.management.connectDataDisplayName": "データに接続", - "common.ui.management.displayName": "管理", + "management.connectDataDisplayName": "データに接続", + "management.displayName": "管理", "common.ui.management.nav.menu": "管理メニュー", "common.ui.modals.cancelButtonLabel": "キャンセル", "common.ui.notify.fatalError.errorStatusMessage": "エラー {errStatus} {errStatusText}: {errMessage}", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index af4aa1f0c7bbec..0f6d03e7fb68d7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -461,8 +461,8 @@ "common.ui.legacyBrowserMessage": "此 Kibana 安装启用了当前浏览器未满足的严格安全要求。", "common.ui.legacyBrowserTitle": "请升级您的浏览器", "common.ui.management.breadcrumb": "管理", - "common.ui.management.connectDataDisplayName": "连接数据", - "common.ui.management.displayName": "管理", + "management.connectDataDisplayName": "连接数据", + "management.displayName": "管理", "common.ui.management.nav.menu": "管理菜单", "common.ui.modals.cancelButtonLabel": "取消", "common.ui.notify.fatalError.errorStatusMessage": "错误 {errStatus} {errStatusText}:{errMessage}", @@ -12810,4 +12810,4 @@ "xpack.licensing.welcomeBanner.licenseIsExpiredDescription.updateYourLicenseLinkText": "更新您的许可", "xpack.licensing.welcomeBanner.licenseIsExpiredTitle": "您的{licenseType}许可已过期" } -} \ No newline at end of file +} From e5c562b5c1b0c63865a051f2d7da5a3aded96beb Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 17 Dec 2019 12:26:50 -0700 Subject: [PATCH 24/60] associate metadata with runnables (#53245) --- .../lib/failure_metadata.test.ts | 6 ++--- .../lib/failure_metadata.ts | 18 ++++++------- .../functional_test_runner/lib/lifecycle.ts | 2 ++ .../lib/mocha/decorate_mocha_ui.js | 6 ++--- .../lib/mocha/wrap_runnable_args.js | 26 ++++++++----------- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts index 7ae46ef6fac1e0..b1f57cee8c23c3 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts @@ -25,7 +25,7 @@ it('collects metadata for the current test', async () => { const failureMetadata = new FailureMetadata(lifecycle); const test1 = {}; - await lifecycle.beforeEachTest.trigger(test1); + await lifecycle.beforeEachRunnable.trigger(test1); failureMetadata.add({ foo: 'bar' }); expect(failureMetadata.get(test1)).toMatchInlineSnapshot(` @@ -35,7 +35,7 @@ it('collects metadata for the current test', async () => { `); const test2 = {}; - await lifecycle.beforeEachTest.trigger(test2); + await lifecycle.beforeEachRunnable.trigger(test2); failureMetadata.add({ test: 2 }); expect(failureMetadata.get(test1)).toMatchInlineSnapshot(` @@ -55,7 +55,7 @@ it('adds messages to the messages state', () => { const failureMetadata = new FailureMetadata(lifecycle); const test1 = {}; - lifecycle.beforeEachTest.trigger(test1); + lifecycle.beforeEachRunnable.trigger(test1); failureMetadata.addMessages(['foo', 'bar']); failureMetadata.addMessages(['baz']); diff --git a/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts index 9dc58d5b0b21f8..be033e063fb9d3 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts @@ -29,7 +29,7 @@ interface Metadata { export class FailureMetadata { // mocha's global types mean we can't import Mocha or it will override the global jest types.............. - private currentTest?: any; + private currentRunnable?: any; private readonly allMetadata = new Map(); constructor(lifecycle: Lifecycle) { @@ -39,18 +39,18 @@ export class FailureMetadata { ); } - lifecycle.beforeEachTest.add(test => { - this.currentTest = test; + lifecycle.beforeEachRunnable.add(runnable => { + this.currentRunnable = runnable; }); } add(metadata: Metadata | ((current: Metadata) => Metadata)) { - if (!this.currentTest) { - throw new Error('no current test to associate metadata with'); + if (!this.currentRunnable) { + throw new Error('no current runnable to associate metadata with'); } - const current = this.allMetadata.get(this.currentTest); - this.allMetadata.set(this.currentTest, { + const current = this.allMetadata.get(this.currentRunnable); + this.allMetadata.set(this.currentRunnable, { ...current, ...(typeof metadata === 'function' ? metadata(current || {}) : metadata), }); @@ -98,7 +98,7 @@ export class FailureMetadata { return screenshot; } - get(test: any) { - return this.allMetadata.get(test); + get(runnable: any) { + return this.allMetadata.get(runnable); } } diff --git a/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts b/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts index 7f78bc28c6d3d9..95843ae4dcff2b 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/lifecycle.ts @@ -22,11 +22,13 @@ import { LifecyclePhase } from './lifecycle_phase'; // mocha's global types mean we can't import Mocha or it will override the global jest types.............. type ItsASuite = any; type ItsATest = any; +type ItsARunnable = any; export class Lifecycle { public readonly beforeTests = new LifecyclePhase<[]>({ singular: true, }); + public readonly beforeEachRunnable = new LifecyclePhase<[ItsARunnable]>(); public readonly beforeTestSuite = new LifecyclePhase<[ItsASuite]>(); public readonly beforeEachTest = new LifecyclePhase<[ItsATest]>(); public readonly afterTestSuite = new LifecyclePhase<[ItsASuite]>(); diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js index 4eb45229c22346..64fc51a04aac9b 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js @@ -19,7 +19,7 @@ import { createAssignmentProxy } from './assignment_proxy'; import { wrapFunction } from './wrap_function'; -import { wrapRunnableArgsWithErrorHandler } from './wrap_runnable_args'; +import { wrapRunnableArgs } from './wrap_runnable_args'; export function decorateMochaUi(lifecycle, context) { // incremented at the start of each suite, decremented after @@ -93,7 +93,7 @@ export function decorateMochaUi(lifecycle, context) { function wrapTestFunction(name, fn) { return wrapNonSuiteFunction( name, - wrapRunnableArgsWithErrorHandler(fn, async (err, test) => { + wrapRunnableArgs(fn, lifecycle, async (err, test) => { await lifecycle.testFailure.trigger(err, test); }) ); @@ -111,7 +111,7 @@ export function decorateMochaUi(lifecycle, context) { function wrapTestHookFunction(name, fn) { return wrapNonSuiteFunction( name, - wrapRunnableArgsWithErrorHandler(fn, async (err, test) => { + wrapRunnableArgs(fn, lifecycle, async (err, test) => { await lifecycle.testHookFailure.trigger(err, test); }) ); diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/wrap_runnable_args.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/wrap_runnable_args.js index 5ee21e81e83ccf..d312ad8079dc1e 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/wrap_runnable_args.js +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/wrap_runnable_args.js @@ -23,28 +23,24 @@ import { wrapFunction, wrapAsyncFunction } from './wrap_function'; * Wraps a "runnable" defining function (it(), beforeEach(), etc.) * so that any "runnable" arguments passed to it are wrapped and will * trigger a lifecycle event if they throw an error. - * - * @param {Function} fn - * @param {String} eventName - * @return {Function} */ -export function wrapRunnableArgsWithErrorHandler(fn, handler) { +export function wrapRunnableArgs(fn, lifecycle, handler) { return wrapFunction(fn, { before(target, thisArg, argumentsList) { for (let i = 0; i < argumentsList.length; i++) { if (typeof argumentsList[i] === 'function') { - argumentsList[i] = wrapRunnableError(argumentsList[i], handler); + argumentsList[i] = wrapAsyncFunction(argumentsList[i], { + async before(target, thisArg) { + await lifecycle.beforeEachRunnable.trigger(thisArg); + }, + + async handleError(target, thisArg, argumentsList, err) { + await handler(err, thisArg.test); + throw err; + }, + }); } } }, }); } - -function wrapRunnableError(runnable, handler) { - return wrapAsyncFunction(runnable, { - async handleError(target, thisArg, argumentsList, err) { - await handler(err, thisArg.test); - throw err; - }, - }); -} From 099ec54c7251b81109a5928bf67de4fd3b126f55 Mon Sep 17 00:00:00 2001 From: gchaps <33642766+gchaps@users.noreply.github.com> Date: Tue, 17 Dec 2019 11:48:55 -0800 Subject: [PATCH 25/60] [DOCS] Updates Discover documentation (#51837) * [DOCS] Updates View in Context doc in Discover * [DOCS] Updates Discover docs on viewing document data * [DOCS] Adds workflow to Discover docs * [DOCS] Updates Discover docs intro page * [DOCS] More updates to Discover docs * [DOCS] More updates to Discover docs * [DOCS] Incorporates review comments in Discover docs * [DOCS] Edits to discover intro * [DOCS] Edits to Discover docs * [DOCS] Incorporates edits in Discover docs --- docs/discover/context.asciidoc | 126 +++++------ docs/discover/document-data.asciidoc | 98 ++++----- docs/discover/field-filter.asciidoc | 199 +++++++++--------- docs/discover/images/move-icon.png | Bin 0 -> 1497 bytes docs/discover/images/sort-icon.png | Bin 0 -> 1472 bytes docs/discover/viewing-field-stats.asciidoc | 12 +- .../Discover-ContextView-SizePicker-Newer.png | Bin 5250 -> 0 bytes .../Discover-ContextView-SizePicker-Older.png | Bin 5032 -> 0 bytes docs/images/Discover-ContextView.png | Bin 107911 -> 123344 bytes docs/images/Discover-Start.png | Bin 393829 -> 209454 bytes docs/images/Expanded-Document.png | Bin 78411 -> 141385 bytes docs/user/discover.asciidoc | 97 ++++++++- 12 files changed, 292 insertions(+), 240 deletions(-) create mode 100644 docs/discover/images/move-icon.png create mode 100644 docs/discover/images/sort-icon.png delete mode 100644 docs/images/Discover-ContextView-SizePicker-Newer.png delete mode 100644 docs/images/Discover-ContextView-SizePicker-Older.png diff --git a/docs/discover/context.asciidoc b/docs/discover/context.asciidoc index 9049109d6124d2..c402a734a16fae 100644 --- a/docs/discover/context.asciidoc +++ b/docs/discover/context.asciidoc @@ -1,90 +1,66 @@ [[document-context]] -== Viewing Document Context +== Viewing a document in context -For certain applications it can be useful to inspect a window of documents -surrounding a specific event. The context view enables you to do just that for -<> that are configured to contain time-based events. +Once you've narrowed your search to a specific event, +you might want to inspect the documents that occurred +immediately before and after the event. With the Context view, +you can do just that for index patterns that contain time-based events. -To show the context surrounding an anchor document, click the *Expand* button -image:images/ExpandButton.jpg[Expand Button] to the left of the document's -table entry and then click the *View surrounding documents* link. +To open the Context view, click the expand icon (<) in the document table, and then click +*View surrounding documents.* -image::images/Expanded-Document.png[Expanded Document] -{nbsp} +The documents are sorted +by the time field specified in the index pattern and displayed using the +same set of columns as the *Discover* view from which the context was opened. +The anchor document is highlighted in blue. -The context view displays a number of documents before and after the anchor -document. The anchor document itself is highlighted in blue. The view is sorted -by the time field specified in the index pattern configuration and uses the -same set of columns as the Discover view the context was opened from. If there -are multiple documents with the same time field value, the internal document -order is used as a secondary sorting criterion by default. - -[NOTE] --- -The field used for tiebreaking in case of equal time field values can be -configured using the advanced setting `context:tieBreakerFields` in -< Advanced Settings*>>, which defaults to the -`_doc` field. The value of this setting can be a comma-separated list of field -names, which will be checked in sequence for suitability when a context is -about to be displayed. The first suitable field is then used as the tiebreaking -field. A field is suitable if the field exists and is sortable in the index -pattern the context is based on. - -While not required, it is recommended to only -use fields which have {ref}/doc-values.html[doc values] enabled to achieve -good performance and avoid unnecessary {ref}/modules-fielddata.html[field -data] usage. Common examples for suitable fields include log line numbers, -monotonically increasing counters and high-precision timestamps. --- +[role="screenshot"] image::images/Discover-ContextView.png[Context View] -NOTE: The number of documents displayed by default can be configured -via the `context:defaultSize` setting in < -Advanced Settings*>>. - [float] -[[change-context-size]] -=== Changing the Context Size - -You can change the number documents displayed before and after the anchor -document independently. - -To increase the number of displayed documents that are newer than the anchor -document, click the *Load 5 more* button above the document list or enter the -desired number into the input box right of the button. - -image::images/Discover-ContextView-SizePicker-Newer.png[] -{nbsp} - -To increase the number of displayed documents that are older than the anchor -document, click the *Load 5 more* button below the document list or enter the -desired number into the input box right of the button. +[[filter-context]] +=== Filter the context -image::images/Discover-ContextView-SizePicker-Older.png[] -{nbsp} +The +filters you applied in *Discover* are carried over to the Context view. Pinned filters remain active, while normal +filters are copied in a disabled state. You can re-enable these filters to +refine your context view. -NOTE: The default number of documents loaded with each button click can be -configured via the `context:step` setting in < -Advanced Settings*>>. +If the Context view contains a large number of documents not related to the event under +investigation, you can use filters to restrict the documents to +display. [float] -[[filter-context]] -=== Filtering the Context - -Depending on how the documents are partitioned into index patterns, the context -view might contain a large number of documents not related to the event under -investigation. In order to adapt the focus of the context view to the task at -hand, you can use filters to restrict the documents considered by Kibana for -display in the context view. - -When switching from the discover view to the context view, the previously -applied filters are carried over. Pinned filters remain active while normal -filters are copied in a disabled state. You can selectively re-enabled them to -refine your context view. +[[change-context-size]] +=== Change the number of surrounding documents -New filters can be added via the *Add a filter* link in the filter bar, by -clicking the filter icons appearing when hovering a field, or by expanding -documents and clicking the filter icons in the table. +By default, the five newest and oldest +documents are listed. To increase the number of documents that surround the anchor document, +click *Load*. Five documents are added with each click. -image::images/Discover-ContextView-FilterMontage.png[] +[float] +[[configure-context-ContextView]] +=== Configure the context view + +To configure the Context view, use these settings in <>. + +[horizontal] +`context:defaultSize`:: The number of documents to display by default. +`context:step`:: The default number of documents to load with each button click. +`context:tieBreakerFields`:: The field to use for tiebreaking in case of equal time field values. +The default is the +`_doc` field. ++ +You can enter a comma-separated list of field +names, which is checked in sequence for suitability when a context is +displayed. The first suitable field is used as the tiebreaking +field. A field is suitable if the field exists and is sortable in the index +pattern the context is based on. ++ +Although not required, it is recommended to only +use fields that have {ref}/doc-values.html[doc values] enabled to achieve +good performance and avoid unnecessary {ref}/modules-fielddata.html[field +data] usage. Common examples for suitable fields include log line numbers, +monotonically increasing counters and high-precision timestamps. diff --git a/docs/discover/document-data.asciidoc b/docs/discover/document-data.asciidoc index dc6a45dc5ad7ef..b45a31065aa9a6 100644 --- a/docs/discover/document-data.asciidoc +++ b/docs/discover/document-data.asciidoc @@ -1,69 +1,55 @@ [[document-data]] -== Viewing Document Data +== Viewing document data -When you submit a search query, the 500 most recent documents that match the query -are listed in the Documents table. You can configure the number of documents shown -in the table by setting the `discover:sampleSize` property in <>. By default, the table shows the localized version of the time -field configured for the selected <> and the document `_source`. You can -<> from the Fields list. -You can <> by any indexed field that's included -in the table. - -To view a document's field data, click the *Expand* button -image:images/ExpandButton.jpg[Expand Button] to the left of the document's table -entry. - -image::images/Expanded-Document.png[] - -To view the original JSON document (pretty-printed), click the *JSON* tab. - -To view the document data as a separate page, click the *View single document* -link. You can bookmark and share this link to provide direct access to a -particular document. - -To display or hide a field's column in the Documents table, click the -image:images/add-column-button.png[Add Column] *Toggle column in table* button. - -To collapse the document details, click the *Collapse* button -image:images/CollapseButton.jpg[Collapse Button]. +When you submit a search query in *Discover*, the most recent documents that match the query +are listed in the documents table. +By default, the table includes columns for +the time field and the document `_source`, which shows all fields and values in the document. [float] [[sorting]] -=== Sorting the Document List -You can sort the documents in the Documents table by the values in any indexed -field. If a time field is configured for the current index pattern, the -documents are sorted in reverse chronological order by default. - -To change the sort order, hover over the name of the field you want to sort by -and click the sort button. Click again to reverse the sort order. +=== Modify the document table + +Use the following commands to +tailor the documents table to suit your needs. + +[horizontal] +Add a field column:: +Hover over the list of *Available fields* and then click *add* next to each field you want include as a column in the table. +The first field you add replaces the `_source` column. +Change sort order:: By default, columns are sorted by the values in the field. +If a time field is configured for the current index pattern, +the documents are sorted in reverse chronological order. ++ +To change the sort order, hover over the column +and click image:images/sort-icon.png[]. +The first click sorts by ascending order, the second click sorts by descending order, and the third +click removes the field from the sorted fields. + +Move a field column:: Hover over the column header and click the move left (<<) or move right icon (>>). +Remove a field column :: Hover over the list of *Specified fields* +and then click *remove*. +Or, use the (x) control in the column header. [float] -[[adding-columns]] -=== Adding Field Columns to the Documents Table -By default, the Documents table shows the localized version of the time field -that's configured for the selected index pattern and the document `_source`. -You can add fields to the table from the Fields list or from a document's -field data. - -To add a field column from the Fields list, hover over the field and click its -*add* button. +=== Drill down into field-level details +To view the document data in either table or JSON format, click the expand icon (>). +The expanded view provides these options for viewing your document: -To add a field column from a document's field data, expand the document -and click the field's -image:images/add-column-button.png[Add Column] *Toggle column in table* button. +* View the events that surround your document. +For example, you might want to see the 10 documents that occurred +immediately before and after your event. -Added field columns replace the `_source` column in the Documents table. The added -fields are also added to the *Selected Fields* list. +* View the document data as a separate page. You can bookmark and +share the link for direct access to a particular document. -To rearrange the field columns, hover over the header of the column you want to move -and click the *Move left* or *Move right* button. +[role="screenshot"] +image::images/Expanded-Document.png[] -image:images/Discover-MoveColumn.jpg[Move Column] [float] -[[removing-columns]] -=== Removing Field Columns from the Documents Table -To remove a field column from the Documents table, hover over the header of the -column you want to remove and click the *Remove* button -image:images/RemoveFieldButton.jpg[Remove Field Button]. \ No newline at end of file +=== Configure the number of documents to show + +By default, the documents table includes the 500 most recent documents that +match the query. To change this number, set the `discover:sampleSize` property in <>. diff --git a/docs/discover/field-filter.asciidoc b/docs/discover/field-filter.asciidoc index 5646fe079401e2..49bb6078cdc588 100644 --- a/docs/discover/field-filter.asciidoc +++ b/docs/discover/field-filter.asciidoc @@ -1,127 +1,132 @@ [[field-filter]] -== Filtering by Field -You can filter the search results to display only those documents that contain -a particular value in a field. You can also create negative filters that -exclude documents that contain the specified field value. +== Filtering by field -You add field filters from the Fields list, the Documents table, or by manually -adding a filter. In addition to creating positive and negative filters, the -Documents table enables you to filter on whether or not a field is present. The -applied filters are shown below the Query bar. Negative filters are shown in red. +*Discover* offers +various types of filters, so you can restrict your documents to the exact data you want. +For example, you might look at the results for a +particular period of time. Or, you might include—or exclude— +all HTTP redirects that come from a specific IP and port. -To add a filter from the Fields list: +[float] +=== Add a filter + +A quick way to add a filter is from the fields list. -. Click the name of the field you want to filter on. This displays the top -five values for that field. +. Click the field to filter on. ++ +You'll see the number of documents that contain +the field, the top 5 values for the field, and the percentage of documents +that contain each value. + [role="screenshot"] image::images/filter-field.png[height=317] -. To add a positive filter, click the *Positive Filter* button -image:images/PositiveFilter.jpg[Positive Filter]. -This includes only those documents that contain that value in the field. -. To add a negative filter, click the *Negative Filter* button -image:images/NegativeFilter.jpg[Negative Filter]. -This excludes documents that contain that value in the field. - -To add a filter from the Documents table: - -. Expand a document in the Documents table by clicking the *Expand* button -image:images/ExpandButton.jpg[Expand Button] to the left of the document's -table entry. + +. Use the image:images/PositiveFilter.jpg[Positive Filter] icon to +show only documents that contain that value, +or image:images/NegativeFilter.jpg[Negative Filter] to exclude all documents with that value. + -image::images/Expanded-Document.png[] -. To add a positive filter, click the *Positive Filter* button -image:images/PositiveFilter.jpg[Positive Filter Button] to the right of the -field name. This includes only those documents that contain that value in the -field. -. To add a negative filter, click the *Negative Filter* button -image:images/NegativeFilter.jpg[Negative Filter Button] to the right of the -field name. This excludes documents that contain that value in the field. -. To filter on whether or not documents contain the field, click the -*Exists* button image:images/ExistsButton.jpg[Exists Button] to the right of the -field name. This includes only those documents that contain the field. - -To manually add a filter: - -. Click *Add Filter*. A popup will be displayed for you to create the filter. - -. Choose a field to filter by. This list of fields will include fields from the -index pattern you are currently querying against. +If there is no data to display, you might need to set a <>. +You can choose a time from the quick filter or choose your +own using absolute or relative times. + +. Try also these filtering options: ++ +* To limit the field +list to a particular data type, click *Filter by type*. +You can also filter for whether that type is +aggregatable or searchable. + -image::images/add_filter_field.png[] -. Choose an operation for your filter. +* To filter for whether a field is present, expand the document in +the document table, hover over the field, and click the *Filter for field present* icon. + +[float] +=== Filter by condition + +You can filter using advanced criteria, +such as if a value is equal to or in between certain values. + +. Click *Add Filter*. + +. Select a field. + +. Select an operation for your filter: + -image::images/add_filter_operator.png[] -The following operators can be selected: [horizontal] -`is`:: Filter where the value for the field matches the given value. -`is not`:: Filter where the value for the field does not match the given value. -`is one of`:: Filter where the value for the field matches one of the specified values. -`is not one of`:: Filter where the value for the field does not match any of the specified values. -`is between`:: Filter where the value for the field is in the given range. -`is not between`:: Filter where the value for the field is not in the given range. -`exists`:: Filter where any value is present for the field. -`does not exist`:: Filter where no value is present for the field. -. Choose the value(s) for your filter. Values from your indices may be suggested -as selections if you are filtering against an aggregatable field. +`is`:: The value for the field matches the given value. +`is not`:: The value for the field does not match the given value. +`is one of`:: The field matches one of the specified values. +`is not one of`:: The value for the field does not match any of the specified values. +`is between`:: The value for the field is in the given range. +`is not between`:: The value for the field is not in the given range. +`exists`:: Any value is present for the field. +`does not exist`:: No value is present for the field. +. Choose values for your filter. + -image::images/add_filter_value.png[] -. (Optional) Specify a label for the filter. If you specify a label, it will be -displayed below the query bar instead of the filter definition. -. Click *Save*. The filter will be applied to your search and be displayed below -the query bar. +Values from your indices may be suggested +as selections if you are filtering against an aggregatable field. +. (Optional) Specify a label for the filter. + +. Click *Save* to apply the filter to your search. ++ NOTE: If you are experiencing long-running queries as a result of the value suggestions, you can -turn off the suggestions by setting the advanced setting, `filterEditor:suggestValues`, to `false`. +turn off the suggestions by setting `filterEditor:suggestValues` to `false` +in <>. [float] [[filter-pinning]] -=== Managing Filters +=== Edit, disable, and delete filters + +To modify a filter, click its tag, and then select one of the following actions. + +*Pin across all apps*:: +Persist the filter +when you switch contexts in Kibana. For example, you can pin a filter +in *Discover* and it remains in place when you switch to *Visualize*. +A filter is based on a particular index field—if the indices being +searched do not contain the field in a pinned filter, it has no effect. -To modify a filter, click on it and click one of the action buttons. +*Edit filter*:: +Edit the +filter definition and label. -image::images/filter-allbuttons.png[] +*Exclude results*:: +Switch from a positive +filter to a negative filter, and vice versa. -  +*Temporarily disable*:: +Disable the filter without +removing it. Click again to reenable the filter. + +*Delete*:: +Delete the filter. + +To apply an action to all filters, +click the *Actions* icon, and then select the action. -Pin across all apps :: Pinned filters -persist when you switch contexts in Kibana. For example, you can pin a filter -in Discover and it remains in place when you switch to Visualize. -Note that a filter is based on a particular index field--if the indices being -searched don't contain the field in a pinned filter, it has no effect. -Edit Filter :: <> definition. Enables you to manually update the filter and -specify a label for the filter. -Exclude results :: Switch from a positive -filter to a negative filter and vice-versa. -Temporarily disable :: Disable the filter without -removing it. Click again to reenable the filter. Diagonal stripes indicate -that a filter is disabled. -Remove Filter :: Remove the filter. -To apply a filter action to all of the applied filters, -click *Actions* and select the action. [float] [[filter-edit]] -=== Editing a Filter -You can edit a filter by changing the field, operator, or value associated -with the filter (see the Add Filter section above), or by directly modifying -the filter query that is performed to filter your search results. This -enables you to create more complex filters that are based on multiple fields. - -. To edit the filter query, first click the edit button for the filter, then -click *Edit Query DSL*. -+ -image::images/edit_filter_query.png[] -. You can then edit the query for the filter. -+ -image::images/edit_filter_query_json.png[] +=== Modify the filter query -For example, you could use a -{ref}/query-dsl-bool-query.html[bool query] to create a filter for the -sample log data that displays the hits that originated from Canada or China that resulted in a 404 error: +You can directly modify +the query that filters your search results. This enables you +to create more complex filters using multiple fields. +. Click the filter tag, and then select *Edit > Edit Query DSL*. + +. Edit the query for the filter. ++ +//// +image::images/edit_filter_query_json.png[] ++ +//// +For example, if you are using the sample log data, you can use the +{ref}/query-dsl-bool-query.html[bool query] to create a filter +that displays the hits that originated from Canada or China that resulted in a 404 error: ++ ========== [source,json] { diff --git a/docs/discover/images/move-icon.png b/docs/discover/images/move-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa1f9e2f1a59b40c9315862c8074090a89e3a04 GIT binary patch literal 1497 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 wrC7p3m4;%af_cdQ0JVp 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 PqJH|1jCG;f&N2T3A#$Jx literal 107911 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 diff --git a/docs/images/Discover-Start.png b/docs/images/Discover-Start.png index 680aa3767bdf079e90bbf349315f9a84a969904b..27e7a2c7285976cbca378fff118071fbfc5f3f46 100644 GIT binary patch literal 209454 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�qX8vw>Bew#u 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 Nex@N`_0;0c{{ZLR)r9~6 literal 393829 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 z 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

UBUgc{O$jrPp^k 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

+_t=+b)^b2x7>8V@URr|>jnt-%XT53*1p$)(= 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 literal 78411 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. -You can submit search queries, filter the search results, and view document data. -You can also see the number of documents that match the search query and get field value statistics. -If a time field is configured for the selected index pattern, the distribution of -documents over time is displayed in a histogram at the top of the page. +When you know what your data includes, you can create visualizations +that best display that data and build better dashboards. +*Discover* enables you to explore your data, find +hidden insights and relationships, and get answers to your questions. + +With *Discover*, you can: + +* Access every document in every index that matches your selected index pattern +* Search your data and filter the search results +* Get field-level details about the documents that match your search +* View the events that occurred just before and after a document [role="screenshot"] image::images/Discover-Start.png[Discover] + + +[float] +=== Set up your index pattern + +The first thing to do in *Discover* is to select an <>, which +defines the data you want to explore and visualize. The current index pattern is in the upper left. +If you haven't yet created an index pattern, you can add a <>, +which has a pre-built index pattern. + +[float] +=== Set a time filter + +By default, *Discover* shows data for the last 15 minutes. +If you have a time-based index, and no data displays, +you might need to increase the time range. Using the <> in the upper right, +you can specify a common or recently-used time range, a relative time +from now, or an absolute time range. + +[float] +=== Search your data + +Now that you have your data and set the time span, you can start asking your questions. +You can search your data using the <>, +which offers a simplified query syntax. +For example, if +you search for `day_of_week : Friday`, you'll get a list of all documents +in which `day_of_week` is set to `Friday`. If you prefer +<>, you can access it from the KQL menu. + +[float] +=== Filter your search results + +Next, you'll want narrow your search results to a more manageable data set. +When you click on a name in the field list, you'll see +the top five values for the field, the number of documents that contain the field, +and the percentage of documents that contain each value. From this view, you can +use the (+) magnifier icon to quickly find all +documents that have that value, or (-) to exclude all +documents with that value. For more filter options, see <>. + +[role="screenshot"] +image::images/filter-field.png[height=317] + + +[float] +=== Add and remove fields + +The sortable documents table +lists the documents that match your search. +By default, the table includes columns for the time field and the document `_source`. +To zero in on a specific field, click *add* next to the field name in the left sidebar. +For example, if you add the `currency`, `customer_last_name`, and `day_of_week` fields, +the document table includes columns for those three fields. + +[float] +=== Examine document contents + +From the documents table, you can expand a document to +examine its field data in either table or JSON format. +The table view provides yet another filtering option—filtering for whether the field +is present. See <> for details. + +[float] +=== View a document in context + +Suppose you're troubleshooting your data, and you've narrowed down your results to a single document. +Now you want to to see the events that occurred just before and after the +document that you are looking at. You can do that by expanding the document and +clicking <>. + +[float] +=== Save and share your search + +Finally, its time to save and share your data. You can export your data as a CSV file +or create a direct link to share. The *Save* and *Share* actions are in the menu bar. + + + + -- include::{kib-repo-dir}/discover/set-time-filter.asciidoc[] From cf8cb62bf58a56906b5845d14155b4632ab33a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Tue, 17 Dec 2019 15:51:40 -0500 Subject: [PATCH 26/60] Update codeowners to include functional tests (#53045) --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3142e0ff977495..53270e45171921 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -109,6 +109,9 @@ /x-pack/legacy/plugins/alerting @elastic/kibana-alerting-services /x-pack/legacy/plugins/actions @elastic/kibana-alerting-services /x-pack/legacy/plugins/task_manager @elastic/kibana-alerting-services +/x-pack/test/alerting_api_integration @elastic/kibana-alerting-services +/x-pack/test/plugin_api_integration/plugins/task_manager @elastic/kibana-alerting-services +/x-pack/test/plugin_api_integration/test_suites/task_manager @elastic/kibana-alerting-services # Design **/*.scss @elastic/kibana-design From 75447e5ae1a45958d2b77e97e28374827ff5c707 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Tue, 17 Dec 2019 15:54:47 -0500 Subject: [PATCH 27/60] [Monitoring] Add error state for unstructured logs (#53299) * Add error state for unstructured logs * Fix tests --- .../logs/__snapshots__/reason.test.js.snap | 34 +++++++++++++++++-- .../public/components/logs/reason.js | 30 ++++++++++++++-- .../public/components/logs/reason.test.js | 7 ++++ .../server/lib/logs/detect_reason.js | 13 +++++++ .../monitoring/cluster/fixtures/overview.json | 3 +- .../elasticsearch/fixtures/index_detail.json | 1 + .../elasticsearch/fixtures/node_detail.json | 1 + .../fixtures/overview_green_platinum.json | 1 + .../fixtures/overview_red_platinum.json | 1 + .../fixtures/overview_shards_relocating.json | 1 + .../logs/fixtures/multiple_clusters.json | 1 + .../standalone_cluster/fixtures/cluster.json | 1 + 12 files changed, 87 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap index cd317dee65c333..de4b888a48545c 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap @@ -67,7 +67,7 @@ exports[`Logs should render with a no cluster found reason 1`] = ` values={ Object { "link": setup @@ -92,7 +92,7 @@ exports[`Logs should render with a no index found reason 1`] = ` values={ Object { "link": setup @@ -142,7 +142,7 @@ exports[`Logs should render with a no node found reason 1`] = ` values={ Object { "link": setup @@ -154,6 +154,34 @@ exports[`Logs should render with a no node found reason 1`] = ` `; +exports[`Logs should render with a no structured logs reason 1`] = ` + +

+ + points to JSON logs + , + "varPaths": + var.paths + , + } + } + /> +

+ +`; + exports[`Logs should render with a no type found reason 1`] = ` { let title = i18n.translate('xpack.monitoring.logs.reason.defaultTitle', { @@ -91,6 +92,29 @@ export const Reason = ({ reason }) => { }} /> ); + } else if (false === reason.usingStructuredLogs) { + title = i18n.translate('xpack.monitoring.logs.reason.notUsingStructuredLogsTitle', { + defaultMessage: 'No structured logs found', + }); + message = ( + var.paths, + link: ( + + {i18n.translate('xpack.monitoring.logs.reason.notUsingStructuredLogsLink', { + defaultMessage: 'points to JSON logs', + })} + + ), + }} + /> + ); } else if (false === reason.clusterExists) { title = i18n.translate('xpack.monitoring.logs.reason.noClusterTitle', { defaultMessage: 'No logs for this cluster', @@ -103,7 +127,7 @@ export const Reason = ({ reason }) => { link: ( {i18n.translate('xpack.monitoring.logs.reason.noClusterLink', { defaultMessage: 'setup', @@ -125,7 +149,7 @@ export const Reason = ({ reason }) => { link: ( {i18n.translate('xpack.monitoring.logs.reason.noNodeLink', { defaultMessage: 'setup', @@ -147,7 +171,7 @@ export const Reason = ({ reason }) => { link: ( {i18n.translate('xpack.monitoring.logs.reason.noIndexLink', { defaultMessage: 'setup', diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.test.js b/x-pack/legacy/plugins/monitoring/public/components/logs/reason.test.js index 2957de26f7189b..c8ed05bd73aded 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.test.js +++ b/x-pack/legacy/plugins/monitoring/public/components/logs/reason.test.js @@ -29,6 +29,13 @@ describe('Logs', () => { expect(component).toMatchSnapshot(); }); + it('should render with a no structured logs reason', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); + it('should render with a no cluster found reason', () => { const component = shallow( diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason.js b/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason.js index 16bd9d506dd0f1..b3b835d6ba9872 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason.js +++ b/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason.js @@ -16,6 +16,7 @@ async function doesFilebeatIndexExist( const filter = [createTimeFilter({ start, end, metric })]; const typeFilter = { term: { 'service.type': 'elasticsearch' } }; + const structuredLogsFilter = { exists: { field: 'elasticsearch.cluster' } }; const clusterFilter = { term: { 'elasticsearch.cluster.uuid': clusterUuid } }; const nodeFilter = { term: { 'elasticsearch.node.id': nodeUuid } }; const indexFilter = { term: { 'elasticsearch.index.name': indexUuid } }; @@ -44,6 +45,14 @@ async function doesFilebeatIndexExist( }, }; + const usingStructuredLogsQuery = { + query: { + bool: { + filter: [...filter, typeFilter, structuredLogsFilter], + }, + }, + }; + const clusterExistsQuery = { query: { bool: { @@ -81,6 +90,8 @@ async function doesFilebeatIndexExist( { ...defaultParams, ...typeExistsAtAnyTimeQuery }, { index: filebeatIndexPattern }, { ...defaultParams, ...typeExistsQuery }, + { index: filebeatIndexPattern }, + { ...defaultParams, ...usingStructuredLogsQuery }, ]; if (clusterUuid) { @@ -102,6 +113,7 @@ async function doesFilebeatIndexExist( indexPatternExistsInTimeRangeResponse, typeExistsAtAnyTimeResponse, typeExistsResponse, + usingStructuredLogsResponse, clusterExistsResponse, nodeExistsResponse, indexExistsResponse, @@ -114,6 +126,7 @@ async function doesFilebeatIndexExist( get(indexPatternExistsInTimeRangeResponse, 'hits.total.value', 0) > 0, typeExistsAtAnyTime: get(typeExistsAtAnyTimeResponse, 'hits.total.value', 0) > 0, typeExists: get(typeExistsResponse, 'hits.total.value', 0) > 0, + usingStructuredLogs: get(usingStructuredLogsResponse, 'hits.total.value', 0) > 0, clusterExists: clusterUuid ? get(clusterExistsResponse, 'hits.total.value', 0) > 0 : null, nodeExists: nodeUuid ? get(nodeExistsResponse, 'hits.total.value', 0) > 0 : null, indexExists: indexUuid ? get(indexExistsResponse, 'hits.total.value', 0) > 0 : null, diff --git a/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json b/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json index be87c3458453cc..49e80b244f7606 100644 --- a/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json +++ b/x-pack/test/api_integration/apis/monitoring/cluster/fixtures/overview.json @@ -69,7 +69,8 @@ "nodeExists": null, "indexExists": null, "typeExists": false, - "typeExistsAtAnyTime": false + "typeExistsAtAnyTime": false, + "usingStructuredLogs": false }, "types": [] } diff --git a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/index_detail.json b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/index_detail.json index 7aee56e697d9e5..04d56d5949d2c7 100644 --- a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/index_detail.json +++ b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/index_detail.json @@ -17,6 +17,7 @@ "indexPatternExists": false, "indexPatternInTimeRangeExists": false, "typeExistsAtAnyTime": false, + "usingStructuredLogs": false, "nodeExists": null, "indexExists": false, "typeExists": false diff --git a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/node_detail.json b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/node_detail.json index c2ee3a818fe143..0b8d26558e7fc5 100644 --- a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/node_detail.json +++ b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/node_detail.json @@ -18,6 +18,7 @@ "indexPatternExists": false, "indexPatternInTimeRangeExists": false, "typeExistsAtAnyTime": false, + "usingStructuredLogs": false, "nodeExists": false, "indexExists": null, "typeExists": false diff --git a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_green_platinum.json b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_green_platinum.json index 8f9b427d4466b7..9dd55cdd27edea 100644 --- a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_green_platinum.json +++ b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_green_platinum.json @@ -5757,6 +5757,7 @@ "indexPatternExists": false, "indexPatternInTimeRangeExists": false, "typeExistsAtAnyTime": false, + "usingStructuredLogs": false, "nodeExists": null, "indexExists": null, "typeExists": false diff --git a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_red_platinum.json b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_red_platinum.json index 8a9405abda8177..45f2a7e6581f99 100644 --- a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_red_platinum.json +++ b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_red_platinum.json @@ -22,6 +22,7 @@ "indexPatternExists": false, "indexPatternInTimeRangeExists": false, "typeExistsAtAnyTime": false, + "usingStructuredLogs": false, "nodeExists": null, "indexExists": null, "typeExists": false diff --git a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_shards_relocating.json b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_shards_relocating.json index 9c340ffb4cd50d..415ef5c589c1f5 100644 --- a/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_shards_relocating.json +++ b/x-pack/test/api_integration/apis/monitoring/elasticsearch/fixtures/overview_shards_relocating.json @@ -22,6 +22,7 @@ "indexPatternExists": false, "indexPatternInTimeRangeExists": false, "typeExistsAtAnyTime": false, + "usingStructuredLogs": false, "nodeExists": null, "indexExists": null, "typeExists": false diff --git a/x-pack/test/api_integration/apis/monitoring/logs/fixtures/multiple_clusters.json b/x-pack/test/api_integration/apis/monitoring/logs/fixtures/multiple_clusters.json index 37afc6acec0766..442f9cb38ae33c 100644 --- a/x-pack/test/api_integration/apis/monitoring/logs/fixtures/multiple_clusters.json +++ b/x-pack/test/api_integration/apis/monitoring/logs/fixtures/multiple_clusters.json @@ -5,6 +5,7 @@ "indexPatternExists": true, "indexPatternInTimeRangeExists": true, "typeExistsAtAnyTime": true, + "usingStructuredLogs": true, "typeExists": true, "clusterExists": false, "nodeExists": null, diff --git a/x-pack/test/api_integration/apis/monitoring/standalone_cluster/fixtures/cluster.json b/x-pack/test/api_integration/apis/monitoring/standalone_cluster/fixtures/cluster.json index ae61d289fe3388..802bd0c7fcd74e 100644 --- a/x-pack/test/api_integration/apis/monitoring/standalone_cluster/fixtures/cluster.json +++ b/x-pack/test/api_integration/apis/monitoring/standalone_cluster/fixtures/cluster.json @@ -16,6 +16,7 @@ "indexPatternExists": false, "indexPatternInTimeRangeExists": false, "typeExistsAtAnyTime": false, + "usingStructuredLogs": false, "nodeExists": null, "indexExists": null, "typeExists": false From b7ff35db2da5e47a8399b4b4b9f179a375988e0c Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 17 Dec 2019 16:25:15 -0500 Subject: [PATCH 28/60] [Uptime] Remove legacy es client (#51403) * Move a REST endpoint and the GQL endpoint to NP routing. * Delete obsolete REST endpoint. * Update remaining REST routes to work with NP router. * Remove obsolete code, update some unit tests. * Simplify route creation. * Remove tests of API decommissioned API endpoint. * Rename domain check. * Make return shape of index pattern endpoint correspond to required NP resp body. * Move validate to appropriate level of route definition object for monitor details endpoint. * Update snapshot count route. * Fix broken lint rule. * Move a REST endpoint and the GQL endpoint to NP routing. * Update remaining REST routes to work with NP router. * Update remaining REST routes to work with NP router. * Refactor query functions to accept new es client from request contexts. * WIP updating framework adapter. * Refactor remaining routes/resolvers to remove usage of legacy Elasticsearch client. * Fix broken unit tests. * Fix incorrect user usage for a REST endpoint. * Fix some broken imports and types. * Port monitor details REST endpoint to NP. * Remove some merge errors. * Update adapters to take a single options parameter. * Update broken test files. * Resolve typescript warnings. * Update resolver types. * Change GraphQL interface name for es client. * Delete unused code and fix incorrect type. * Rename type for REST endpoint creators. * Nest message values in body object for invalid response messages. * Reorganize a file and clean up some types. * Add wrapper function to reduce boilerplate route code. --- x-pack/legacy/plugins/uptime/index.ts | 3 +- .../graphql/monitor_states/resolvers.ts | 23 +- .../server/graphql/monitors/resolvers.ts | 54 ++-- .../uptime/server/graphql/pings/resolvers.ts | 16 +- .../plugins/uptime/server/graphql/types.ts | 12 +- .../lib/adapters/database/adapter_types.ts | 35 --- .../server/lib/adapters/database/index.ts | 7 - .../database/kibana_database_adapter.ts | 32 --- .../lib/adapters/framework/adapter_types.ts | 29 +- .../framework/kibana_framework_adapter.ts | 49 ++-- .../uptime/server/lib/adapters/index.ts | 1 - .../adapters/monitor_states/adapter_types.ts | 38 +-- .../elasticsearch_monitor_states_adapter.ts | 61 ++-- .../lib/adapters/monitor_states/index.ts | 2 +- .../search/__tests__/test_helpers.ts | 4 +- .../search/enrich_monitor_groups.ts | 4 +- .../search/find_potential_matches.ts | 2 +- .../search/refine_potential_matches.ts | 4 +- ...lasticsearch_monitors_adapter.test.ts.snap | 4 +- .../elasticsearch_monitors_adapter.test.ts | 60 ++-- .../lib/adapters/monitors/adapter_types.ts | 67 +++-- .../elasticsearch_monitors_adapter.ts | 97 ++----- .../server/lib/adapters/monitors/index.ts | 2 +- .../elasticsearch_pings_adapter.test.ts | 271 +++++++++--------- .../lib/adapters/pings/adapter_types.ts | 106 +++++-- .../pings/elasticsearch_pings_adapter.ts | 113 +++----- .../uptime/server/lib/adapters/pings/index.ts | 2 +- .../lib/adapters/saved_objects/index.ts | 2 +- .../kibana_saved_objects_adapter.ts | 21 +- .../lib/adapters/saved_objects/types.ts | 4 +- .../uptime/server/lib/compose/kibana.ts | 22 +- .../__snapshots__/license.test.ts.snap | 1 + .../lib/domains/__tests__/license.test.ts | 2 +- .../uptime/server/lib/domains/license.ts | 7 +- .../legacy/plugins/uptime/server/lib/lib.ts | 2 - .../server/rest_api/create_route_with_auth.ts | 32 ++- .../plugins/uptime/server/rest_api/index.ts | 5 +- .../index_pattern/get_index_pattern.ts | 8 +- .../rest_api/monitors/monitor_locations.ts | 13 +- .../rest_api/monitors/monitors_details.ts | 10 +- .../uptime/server/rest_api/pings/get_all.ts | 16 +- .../rest_api/snapshot/get_snapshot_count.ts | 14 +- .../rest_api/telemetry/log_monitor_page.ts | 6 +- .../rest_api/telemetry/log_overview_page.ts | 6 +- .../plugins/uptime/server/rest_api/types.ts | 82 +++++- .../server/rest_api/uptime_route_wrapper.ts | 18 ++ .../plugins/uptime/server/uptime_server.ts | 6 +- 47 files changed, 687 insertions(+), 688 deletions(-) delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/database/adapter_types.ts delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/database/index.ts delete mode 100644 x-pack/legacy/plugins/uptime/server/lib/adapters/database/kibana_database_adapter.ts create mode 100644 x-pack/legacy/plugins/uptime/server/rest_api/uptime_route_wrapper.ts diff --git a/x-pack/legacy/plugins/uptime/index.ts b/x-pack/legacy/plugins/uptime/index.ts index c8de623cb0a134..e090a2c85e1366 100644 --- a/x-pack/legacy/plugins/uptime/index.ts +++ b/x-pack/legacy/plugins/uptime/index.ts @@ -36,7 +36,7 @@ export const uptime = (kibana: any) => init(server: KibanaServer) { const initializerContext = {} as PluginInitializerContext; const { savedObjects } = server; - const { elasticsearch, xpack_main } = server.plugins; + const { xpack_main } = server.plugins; const { usageCollection } = server.newPlatform.setup.plugins; plugin(initializerContext).setup( @@ -44,7 +44,6 @@ export const uptime = (kibana: any) => route: server.newPlatform.setup.core.http.createRouter(), }, { - elasticsearch, savedObjects, usageCollection, xpack: xpack_main, diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/resolvers.ts b/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/resolvers.ts index 8fbf3529dbe24b..8ddb07b3093d01 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/resolvers.ts +++ b/x-pack/legacy/plugins/uptime/server/graphql/monitor_states/resolvers.ts @@ -39,9 +39,9 @@ export const createMonitorStatesResolvers: CreateUMGraphQLResolvers = ( return { Query: { async getMonitorStates( - resolver, + _resolver, { dateRangeStart, dateRangeEnd, filters, pagination, statusFilter }, - { req } + { APICaller } ): Promise { const decodedPagination = pagination ? JSON.parse(decodeURIComponent(pagination)) @@ -50,15 +50,18 @@ export const createMonitorStatesResolvers: CreateUMGraphQLResolvers = ( totalSummaryCount, { summaries, nextPagePagination, prevPagePagination }, ] = await Promise.all([ - libs.pings.getDocCount(req), - libs.monitorStates.getMonitorStates( - req, + libs.pings.getDocCount({ callES: APICaller }), + libs.monitorStates.getMonitorStates({ + callES: APICaller, dateRangeStart, dateRangeEnd, - decodedPagination, + pagination: decodedPagination, filters, - statusFilter - ), + // this is added to make typescript happy, + // this sort of reassignment used to be further downstream but I've moved it here + // because this code is going to be decomissioned soon + statusFilter: statusFilter || undefined, + }), ]); return { summaries, @@ -67,8 +70,8 @@ export const createMonitorStatesResolvers: CreateUMGraphQLResolvers = ( totalSummaryCount, }; }, - async getStatesIndexStatus(resolver, {}, { req }): Promise { - return await libs.monitorStates.statesIndexExists(req); + async getStatesIndexStatus(_resolver, {}, { APICaller }): Promise { + return await libs.monitorStates.statesIndexExists({ callES: APICaller }); }, }, }; diff --git a/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts b/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts index 415afc87e201e4..8b685d8e08a2bf 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts +++ b/x-pack/legacy/plugins/uptime/server/graphql/monitors/resolvers.ts @@ -71,54 +71,62 @@ export const createMonitorsResolvers: CreateUMGraphQLResolvers = ( } => ({ Query: { async getSnapshotHistogram( - resolver, + _resolver, { dateRangeStart, dateRangeEnd, filters, monitorId, statusFilter }, - { req } + { APICaller } ): Promise { - return await libs.pings.getPingHistogram( - req, + return await libs.pings.getPingHistogram({ + callES: APICaller, dateRangeStart, dateRangeEnd, filters, monitorId, - statusFilter - ); + statusFilter, + }); }, async getMonitorChartsData( - resolver, + _resolver, { monitorId, dateRangeStart, dateRangeEnd, location }, - { req } + { APICaller } ): Promise { - return await libs.monitors.getMonitorChartsData( - req, + return await libs.monitors.getMonitorChartsData({ + callES: APICaller, monitorId, dateRangeStart, dateRangeEnd, - location - ); + location, + }); }, async getLatestMonitors( - resolver, + _resolver, { dateRangeStart, dateRangeEnd, monitorId, location }, - { req } + { APICaller } ): Promise { - return await libs.pings.getLatestMonitorDocs( - req, + return await libs.pings.getLatestMonitorDocs({ + callES: APICaller, dateRangeStart, dateRangeEnd, monitorId, - location - ); + location, + }); }, - async getFilterBar(resolver, { dateRangeStart, dateRangeEnd }, { req }): Promise { - return await libs.monitors.getFilterBar(req, dateRangeStart, dateRangeEnd); + async getFilterBar( + _resolver, + { dateRangeStart, dateRangeEnd }, + { APICaller } + ): Promise { + return await libs.monitors.getFilterBar({ + callES: APICaller, + dateRangeStart, + dateRangeEnd, + }); }, async getMonitorPageTitle( - resolver: any, + _resolver: any, { monitorId }, - { req } + { APICaller } ): Promise { - return await libs.monitors.getMonitorPageTitle(req, monitorId); + return await libs.monitors.getMonitorPageTitle({ callES: APICaller, monitorId }); }, }, }); diff --git a/x-pack/legacy/plugins/uptime/server/graphql/pings/resolvers.ts b/x-pack/legacy/plugins/uptime/server/graphql/pings/resolvers.ts index 066080cec353f4..373e1467433a28 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/pings/resolvers.ts +++ b/x-pack/legacy/plugins/uptime/server/graphql/pings/resolvers.ts @@ -34,23 +34,23 @@ export const createPingsResolvers: CreateUMGraphQLResolvers = ( } => ({ Query: { async allPings( - resolver, + _resolver, { monitorId, sort, size, status, dateRangeStart, dateRangeEnd, location }, - { req } + { APICaller } ): Promise { - return await libs.pings.getAll( - req, + return await libs.pings.getAll({ + callES: APICaller, dateRangeStart, dateRangeEnd, monitorId, status, sort, size, - location - ); + location, + }); }, - async getDocCount(resolver, args, { req }): Promise { - return libs.pings.getDocCount(req); + async getDocCount(_resolver, _args, { APICaller }): Promise { + return libs.pings.getDocCount({ callES: APICaller }); }, }, }); diff --git a/x-pack/legacy/plugins/uptime/server/graphql/types.ts b/x-pack/legacy/plugins/uptime/server/graphql/types.ts index cb7634ff42b4cc..529ab41a62b3bd 100644 --- a/x-pack/legacy/plugins/uptime/server/graphql/types.ts +++ b/x-pack/legacy/plugins/uptime/server/graphql/types.ts @@ -4,12 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Request } from 'hapi'; +import { RequestHandlerContext, CallAPIOptions } from 'kibana/server'; import { UMServerLibs } from '../lib/lib'; -export interface UMContext { - req: Request; -} +export type UMContext = RequestHandlerContext & { + APICaller: ( + endpoint: string, + clientParams?: Record, + options?: CallAPIOptions | undefined + ) => Promise; +}; export interface UMGraphQLResolver { Query?: any; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/database/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/database/adapter_types.ts deleted file mode 100644 index ace86cf946043e..00000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/database/adapter_types.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 { CountParams, CountResponse } from 'elasticsearch'; - -export interface HistogramQueryResult { - key: number; - doc_count: number; - bucket_total: { - value: number; - }; - down: { - bucket_count: { - value: number; - }; - }; -} - -export interface UMESBucket { - key: number; -} - -export interface UMESHistogramBucket { - x: number; - x0: number; -} - -export interface DatabaseAdapter { - count(request: any, params: CountParams): Promise; - search(request: any, params: any): Promise; - head(request: any, params: any): Promise; -} diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/database/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/database/index.ts deleted file mode 100644 index 4e09b5d0e9e2df..00000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/database/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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 * from './adapter_types'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/database/kibana_database_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/database/kibana_database_adapter.ts deleted file mode 100644 index 4b2523503fc8fb..00000000000000 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/database/kibana_database_adapter.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 { DatabaseAdapter } from './adapter_types'; - -interface KibanaElasticsearchPlugin { - getCluster: (clusterName: 'admin' | 'data') => any; - callWithRequest: (request: any, action: string, params: any) => any; -} - -export class UMKibanaDatabaseAdapter implements DatabaseAdapter { - private elasticsearch: KibanaElasticsearchPlugin; - - constructor(kbnElasticsearch: KibanaElasticsearchPlugin) { - this.elasticsearch = kbnElasticsearch.getCluster('data'); - } - - public async search(request: any, params: any): Promise { - return this.elasticsearch.callWithRequest(request, 'search', params); - } - - public async count(request: any, params: any): Promise { - return this.elasticsearch.callWithRequest(request, 'count', params); - } - - public async head(request: any, params: { index: string }): Promise { - return this.elasticsearch.callWithRequest(request, 'indices.exists', params); - } -} diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts index e67f4fa59531c8..b490bf17e292c3 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/adapter_types.ts @@ -5,10 +5,16 @@ */ import { GraphQLSchema } from 'graphql'; -import { SavedObjectsLegacyService, RequestHandler, IRouter } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { + SavedObjectsLegacyService, + RequestHandler, + IRouter, + CallAPIOptions, + SavedObjectsClientContract, +} from 'src/core/server'; import { ObjectType } from '@kbn/config-schema'; -import { UMRouteDefinition } from '../../../rest_api'; +import { UMKibanaRoute } from '../../../rest_api'; export interface UMFrameworkRouteOptions< P extends ObjectType, @@ -22,19 +28,32 @@ export interface UMFrameworkRouteOptions< validate: any; } +type APICaller = ( + endpoint: string, + clientParams: Record, + options?: CallAPIOptions +) => Promise; + +export type UMElasticsearchQueryFn = ( + params: { callES: APICaller } & P +) => Promise | R; + +export type UMSavedObjectsQueryFn = ( + client: SavedObjectsClientContract, + params: P +) => Promise | T; + export interface UptimeCoreSetup { route: IRouter; } export interface UptimeCorePlugins { - elasticsearch: any; savedObjects: SavedObjectsLegacyService; usageCollection: UsageCollectionSetup; xpack: any; } export interface UMBackendFrameworkAdapter { - registerRoute(route: UMRouteDefinition): void; + registerRoute(route: UMKibanaRoute): void; registerGraphQLEndpoint(routePath: string, schema: GraphQLSchema): void; - getSavedObjectsClient(): any; } diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts index a46a7e11bd7382..7ac3db9d0f3d7f 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -7,20 +7,16 @@ import { GraphQLSchema } from 'graphql'; import { schema as kbnSchema } from '@kbn/config-schema'; import { runHttpQuery } from 'apollo-server-core'; -import { UptimeCorePlugins, UptimeCoreSetup } from './adapter_types'; +import { UptimeCoreSetup } from './adapter_types'; import { UMBackendFrameworkAdapter } from './adapter_types'; -import { UMRouteDefinition } from '../../../rest_api'; +import { UMKibanaRoute } from '../../../rest_api'; export class UMKibanaBackendFrameworkAdapter implements UMBackendFrameworkAdapter { - constructor( - private readonly server: UptimeCoreSetup, - private readonly plugins: UptimeCorePlugins - ) { + constructor(private readonly server: UptimeCoreSetup) { this.server = server; - this.plugins = plugins; } - public registerRoute({ handler, method, options, path, validate }: UMRouteDefinition) { + public registerRoute({ handler, method, options, path, validate }: UMKibanaRoute) { const routeDefinition = { path, validate, @@ -39,16 +35,6 @@ export class UMKibanaBackendFrameworkAdapter implements UMBackendFrameworkAdapte } public registerGraphQLEndpoint(routePath: string, schema: GraphQLSchema): void { - const options = { - graphQLOptions: (req: any) => ({ - context: { req }, - schema, - }), - path: routePath, - route: { - tags: ['access:uptime'], - }, - }; this.server.route.post( { path: routePath, @@ -64,6 +50,25 @@ export class UMKibanaBackendFrameworkAdapter implements UMBackendFrameworkAdapte }, }, async (context, request, resp): Promise => { + const { + core: { + elasticsearch: { + dataClient: { callAsCurrentUser }, + }, + }, + } = context; + const options = { + graphQLOptions: (_req: any) => { + return { + context: { ...context, APICaller: callAsCurrentUser }, + schema, + }; + }, + path: routePath, + route: { + tags: ['access:uptime'], + }, + }; try { const query = request.body as Record; @@ -91,12 +96,4 @@ export class UMKibanaBackendFrameworkAdapter implements UMBackendFrameworkAdapte } ); } - - public getSavedObjectsClient() { - const { elasticsearch, savedObjects } = this.plugins; - const { SavedObjectsClient, getSavedObjectsRepository } = savedObjects; - const { callWithInternalUser } = elasticsearch.getCluster('admin'); - const internalRepository = getSavedObjectsRepository(callWithInternalUser); - return new SavedObjectsClient(internalRepository); - } } diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts index 2a88df91adc29f..f5ff3b8c62ba99 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/index.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './database'; export * from './framework'; export * from './monitor_states'; export * from './monitors'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/adapter_types.ts index 57b1744f5d324c..4104a9287a28d1 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/adapter_types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/adapter_types.ts @@ -6,28 +6,32 @@ import { MonitorSummary, - StatesIndexStatus, CursorDirection, SortOrder, + StatesIndexStatus, } from '../../../../common/graphql/types'; +import { UMElasticsearchQueryFn } from '../framework'; +import { Snapshot } from '../../../../common/runtime_types'; + +export interface MonitorStatesParams { + dateRangeStart: string; + dateRangeEnd: string; + pagination?: CursorPagination; + filters?: string | null; + statusFilter?: string; +} + +export interface GetSnapshotCountParams { + dateRangeStart: string; + dateRangeEnd: string; + filters?: string | null; + statusFilter?: string; +} export interface UMMonitorStatesAdapter { - getMonitorStates( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - pagination?: CursorPagination, - filters?: string | null, - statusFilter?: string | null - ): Promise; - statesIndexExists(request: any): Promise; - getSnapshotCount( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - filters?: string, - statusFilter?: string - ): Promise; + getMonitorStates: UMElasticsearchQueryFn; + getSnapshotCount: UMElasticsearchQueryFn; + statesIndexExists: UMElasticsearchQueryFn<{}, StatesIndexStatus>; } export interface CursorPagination { diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/elasticsearch_monitor_states_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/elasticsearch_monitor_states_adapter.ts index c3593854fa53f6..d264da2e7ec0c6 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/elasticsearch_monitor_states_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/elasticsearch_monitor_states_adapter.ts @@ -4,18 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DatabaseAdapter } from '../database'; -import { UMMonitorStatesAdapter, GetMonitorStatesResult, CursorPagination } from './adapter_types'; -import { StatesIndexStatus } from '../../../../common/graphql/types'; +import { UMMonitorStatesAdapter, CursorPagination } from './adapter_types'; import { INDEX_NAMES, CONTEXT_DEFAULTS } from '../../../../common/constants'; import { fetchPage } from './search'; import { MonitorGroupIterator } from './search/monitor_group_iterator'; -import { Snapshot } from '../../../../common/runtime_types'; import { getSnapshotCountHelper } from './get_snapshot_helper'; export interface QueryContext { - database: any; - request: any; + count: (query: Record) => Promise; + search: (query: Record) => Promise; dateRangeStart: string; dateRangeEnd: string; pagination: CursorPagination; @@ -24,25 +21,23 @@ export interface QueryContext { statusFilter?: string; } -export class ElasticsearchMonitorStatesAdapter implements UMMonitorStatesAdapter { - constructor(private readonly database: DatabaseAdapter) { - this.database = database; - } - +export const elasticsearchMonitorStatesAdapter: UMMonitorStatesAdapter = { // Gets a page of monitor states. - public async getMonitorStates( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - pagination: CursorPagination = CONTEXT_DEFAULTS.CURSOR_PAGINATION, - filters?: string | null, - statusFilter?: string - ): Promise { + getMonitorStates: async ({ + callES, + dateRangeStart, + dateRangeEnd, + pagination, + filters, + statusFilter, + }) => { + pagination = pagination || CONTEXT_DEFAULTS.CURSOR_PAGINATION; + statusFilter = statusFilter === null ? undefined : statusFilter; const size = 10; const queryContext: QueryContext = { - database: this.database, - request, + count: (query: Record): Promise => callES('count', query), + search: (query: Record): Promise => callES('search', query), dateRangeStart, dateRangeEnd, pagination, @@ -58,18 +53,12 @@ export class ElasticsearchMonitorStatesAdapter implements UMMonitorStatesAdapter nextPagePagination: jsonifyPagination(page.nextPagePagination), prevPagePagination: jsonifyPagination(page.prevPagePagination), }; - } + }, - public async getSnapshotCount( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - filters?: string, - statusFilter?: string - ): Promise { + getSnapshotCount: async ({ callES, dateRangeStart, dateRangeEnd, filters, statusFilter }) => { const context: QueryContext = { - database: this.database, - request, + count: query => callES('count', query), + search: query => callES('search', query), dateRangeStart, dateRangeEnd, pagination: CONTEXT_DEFAULTS.CURSOR_PAGINATION, @@ -78,22 +67,22 @@ export class ElasticsearchMonitorStatesAdapter implements UMMonitorStatesAdapter statusFilter, }; return getSnapshotCountHelper(new MonitorGroupIterator(context)); - } + }, - public async statesIndexExists(request: any): Promise { + statesIndexExists: async ({ callES }) => { // TODO: adapt this to the states index in future release const { _shards: { total }, count, - } = await this.database.count(request, { index: INDEX_NAMES.HEARTBEAT }); + } = await callES('count', { index: INDEX_NAMES.HEARTBEAT }); return { indexExists: total > 0, docCount: { count, }, }; - } -} + }, +}; // To simplify the handling of the group of pagination vars they're passed back to the client as a string const jsonifyPagination = (p: any): string | null => { diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/index.ts index f23cacce7bbbef..a3fc71ad48cb30 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/index.ts @@ -5,4 +5,4 @@ */ export * from './adapter_types'; -export { ElasticsearchMonitorStatesAdapter } from './elasticsearch_monitor_states_adapter'; +export { elasticsearchMonitorStatesAdapter } from './elasticsearch_monitor_states_adapter'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/__tests__/test_helpers.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/__tests__/test_helpers.ts index 0c3572604879e6..d6fe5f82e735d8 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/__tests__/test_helpers.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/__tests__/test_helpers.ts @@ -24,12 +24,12 @@ export const nextPagination = (key: any): CursorPagination => { }; export const simpleQueryContext = (): QueryContext => { return { - database: undefined, + count: _query => new Promise(r => ({})), + search: _query => new Promise(r => ({})), dateRangeEnd: '', dateRangeStart: '', filterClause: undefined, pagination: nextPagination('something'), - request: undefined, size: 0, statusFilter: '', }; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/enrich_monitor_groups.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/enrich_monitor_groups.ts index 6b594d8b491182..093e105635c2c9 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/enrich_monitor_groups.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/enrich_monitor_groups.ts @@ -243,7 +243,7 @@ export const enrichMonitorGroups: MonitorEnricher = async ( }, }; - const items = await queryContext.database.search(queryContext.request, params); + const items = await queryContext.search(params); const monitorBuckets = get(items, 'aggregations.monitors.buckets', []); @@ -345,7 +345,7 @@ const getHistogramForMonitors = async ( }, }, }; - const result = await queryContext.database.search(queryContext.request, params); + const result = await queryContext.search(params); const buckets: any[] = get(result, 'aggregations.by_id.buckets', []); return buckets.reduce((map: { [key: string]: any }, item: any) => { diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/find_potential_matches.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/find_potential_matches.ts index 002dc2862fa1b0..8f5e26b75f56cd 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/find_potential_matches.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/find_potential_matches.ts @@ -62,7 +62,7 @@ const query = async (queryContext: QueryContext, searchAfter: any, size: number) body, }; - return await queryContext.database.search(queryContext.request, params); + return await queryContext.search(params); }; const queryBody = (queryContext: QueryContext, searchAfter: any, size: number) => { diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/refine_potential_matches.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/refine_potential_matches.ts index 3bdd6fe616f188..b0060cbee17bb7 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/refine_potential_matches.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitor_states/search/refine_potential_matches.ts @@ -95,7 +95,7 @@ const fullyMatchingIds = async ( export const mostRecentCheckGroups = async ( queryContext: QueryContext, potentialMatchMonitorIDs: string[] -) => { +): Promise => { const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -134,5 +134,5 @@ export const mostRecentCheckGroups = async ( }, }; - return await queryContext.database.search(queryContext.request, params); + return await queryContext.search(params); }; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/__snapshots__/elasticsearch_monitors_adapter.test.ts.snap b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/__snapshots__/elasticsearch_monitors_adapter.test.ts.snap index 99349f42d5750c..7f0eb86dae7517 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/__snapshots__/elasticsearch_monitors_adapter.test.ts.snap +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/__snapshots__/elasticsearch_monitors_adapter.test.ts.snap @@ -2,7 +2,7 @@ exports[`ElasticsearchMonitorsAdapter getMonitorChartsData will provide expected filters when a location is specified 1`] = ` Array [ - Object {}, + "search", Object { "body": Object { "aggs": Object { @@ -74,7 +74,7 @@ Array [ exports[`ElasticsearchMonitorsAdapter getMonitorChartsData will run expected parameters when no location is specified 1`] = ` Array [ - Object {}, + "search", Object { "body": Object { "aggs": Object { diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/elasticsearch_monitors_adapter.test.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/elasticsearch_monitors_adapter.test.ts index b21fb982bfb3bb..e3e81fe360718e 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/elasticsearch_monitors_adapter.test.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/__tests__/elasticsearch_monitors_adapter.test.ts @@ -5,38 +5,22 @@ */ import { get, set } from 'lodash'; -import { ElasticsearchMonitorsAdapter } from '../elasticsearch_monitors_adapter'; -import { CountParams, CountResponse } from 'elasticsearch'; +import { elasticsearchMonitorsAdapter as adapter } from '../elasticsearch_monitors_adapter'; import mockChartsData from './monitor_charts_mock.json'; import { assertCloseTo } from '../../../helper'; // FIXME: there are many untested functions in this adapter. They should be tested. describe('ElasticsearchMonitorsAdapter', () => { - let defaultCountResponse: CountResponse; - - beforeEach(() => { - defaultCountResponse = { - count: 0, - _shards: { - total: 0, - successful: 0, - failed: 0, - skipped: 0, - }, - }; - }); - it('getMonitorChartsData will run expected parameters when no location is specified', async () => { expect.assertions(3); const searchMock = jest.fn(); const search = searchMock.bind({}); - const database = { - search, - count: async (request: any, params: CountParams) => defaultCountResponse, - head: async (request: any, params: any) => null, - }; - const adapter = new ElasticsearchMonitorsAdapter(database); - await adapter.getMonitorChartsData({}, 'fooID', 'now-15m', 'now'); + await adapter.getMonitorChartsData({ + callES: search, + monitorId: 'fooID', + dateRangeStart: 'now-15m', + dateRangeEnd: 'now', + }); expect(searchMock).toHaveBeenCalledTimes(1); // protect against possible rounding errors polluting the snapshot comparison const fixedInterval = parseInt( @@ -66,13 +50,13 @@ describe('ElasticsearchMonitorsAdapter', () => { expect.assertions(3); const searchMock = jest.fn(); const search = searchMock.bind({}); - const database = { - search, - count: async (request: any, params: CountParams) => defaultCountResponse, - head: async (request: any, params: any) => null, - }; - const adapter = new ElasticsearchMonitorsAdapter(database); - await adapter.getMonitorChartsData({}, 'fooID', 'now-15m', 'now', 'Philadelphia'); + await adapter.getMonitorChartsData({ + callES: search, + monitorId: 'fooID', + dateRangeStart: 'now-15m', + dateRangeEnd: 'now', + location: 'Philadelphia', + }); expect(searchMock).toHaveBeenCalledTimes(1); // protect against possible rounding errors polluting the snapshot comparison const fixedInterval = parseInt( @@ -101,12 +85,14 @@ describe('ElasticsearchMonitorsAdapter', () => { it('inserts empty buckets for missing data', async () => { const searchMock = jest.fn(); searchMock.mockReturnValue(mockChartsData); - const database = { - search: searchMock, - count: jest.fn(), - head: jest.fn(), - }; - const adapter = new ElasticsearchMonitorsAdapter(database); - expect(await adapter.getMonitorChartsData({}, 'id', 'now-15m', 'now')).toMatchSnapshot(); + const search = searchMock.bind({}); + expect( + await adapter.getMonitorChartsData({ + callES: search, + monitorId: 'id', + dateRangeStart: 'now-15m', + dateRangeEnd: 'now', + }) + ).toMatchSnapshot(); }); }); diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts index 1191eb813a214e..b3d8cb855d55a1 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/adapter_types.ts @@ -5,22 +5,57 @@ */ import { MonitorChart, MonitorPageTitle } from '../../../../common/graphql/types'; +import { UMElasticsearchQueryFn } from '../framework'; +import { MonitorDetails, MonitorLocations } from '../../../../common/runtime_types'; + +export interface GetMonitorChartsDataParams { + /** @member monitorId ID value for the selected monitor */ + monitorId: string; + /** @member dateRangeStart timestamp bounds */ + dateRangeStart: string; + /** @member dateRangeEnd timestamp bounds */ + dateRangeEnd: string; + /** @member location optional location value for use in filtering*/ + location?: string | null; +} + +export interface GetFilterBarParams { + dateRangeStart: string; + /** @member dateRangeEnd timestamp bounds */ + dateRangeEnd: string; +} + +export interface GetMonitorDetailsParams { + monitorId: string; +} + +export interface GetMonitorPageTitleParams { + /** @member monitorId the ID to query */ + monitorId: string; +} + +/** + * Fetch data for the monitor page title. + */ +export interface GetMonitorLocationsParams { + /** + * @member monitorId the ID to query + */ + monitorId: string; + dateStart: string; + dateEnd: string; +} export interface UMMonitorsAdapter { - getMonitorChartsData( - request: any, - monitorId: string, - dateRangeStart: string, - dateRangeEnd: string, - location?: string | null - ): Promise; - getFilterBar(request: any, dateRangeStart: string, dateRangeEnd: string): Promise; - getMonitorPageTitle(request: any, monitorId: string): Promise; - getMonitorDetails(request: any, monitorId: string): Promise; - getMonitorLocations( - request: any, - monitorId: string, - dateStart: string, - dateEnd: string - ): Promise; + /** + * Fetches data used to populate monitor charts + */ + getMonitorChartsData: UMElasticsearchQueryFn; + getFilterBar: UMElasticsearchQueryFn; + /** + * Fetch data for the monitor page title. + */ + getMonitorPageTitle: UMElasticsearchQueryFn<{ monitorId: string }, MonitorPageTitle | null>; + getMonitorDetails: UMElasticsearchQueryFn; + getMonitorLocations: UMElasticsearchQueryFn; } diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts index 4009a4b1331fa3..b3352054589659 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts @@ -6,22 +6,10 @@ import { get } from 'lodash'; import { INDEX_NAMES } from '../../../../common/constants'; -import { - FilterBar, - MonitorChart, - MonitorPageTitle, - Ping, - LocationDurationLine, -} from '../../../../common/graphql/types'; +import { MonitorChart, Ping, LocationDurationLine } from '../../../../common/graphql/types'; import { getHistogramIntervalFormatted } from '../../helper'; -import { DatabaseAdapter } from '../database'; +import { MonitorError, MonitorLocation } from '../../../../common/runtime_types'; import { UMMonitorsAdapter } from './adapter_types'; -import { - MonitorDetails, - MonitorError, - MonitorLocations, - MonitorLocation, -} from '../../../../common/runtime_types'; const formatStatusBuckets = (time: any, buckets: any, docCount: any) => { let up = null; @@ -43,25 +31,8 @@ const formatStatusBuckets = (time: any, buckets: any, docCount: any) => { }; }; -export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { - constructor(private readonly database: DatabaseAdapter) { - this.database = database; - } - - /** - * Fetches data used to populate monitor charts - * @param request Kibana request - * @param monitorId ID value for the selected monitor - * @param dateRangeStart timestamp bounds - * @param dateRangeEnd timestamp bounds - */ - public async getMonitorChartsData( - request: any, - monitorId: string, - dateRangeStart: string, - dateRangeEnd: string, - location?: string | null - ): Promise { +export const elasticsearchMonitorsAdapter: UMMonitorsAdapter = { + getMonitorChartsData: async ({ callES, dateRangeStart, dateRangeEnd, monitorId, location }) => { const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -101,7 +72,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { }, }; - const result = await this.database.search(request, params); + const result = await callES('search', params); const dateHistogramBuckets = get(result, 'aggregations.timeseries.buckets', []); /** @@ -187,19 +158,9 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { }); return monitorChartsData; - } + }, - /** - * Fetch options for the filter bar. - * @param request Kibana request object - * @param dateRangeStart timestamp bounds - * @param dateRangeEnd timestamp bounds - */ - public async getFilterBar( - request: any, - dateRangeStart: string, - dateRangeEnd: string - ): Promise { + getFilterBar: async ({ callES, dateRangeStart, dateRangeEnd }) => { const fields: { [key: string]: string } = { ids: 'monitor.id', schemes: 'monitor.type', @@ -225,24 +186,16 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { }, {}), }, }; - const { aggregations } = await this.database.search(request, params); + const { aggregations } = await callES('search', params); return Object.keys(fields).reduce((acc: { [key: string]: any[] }, field) => { const bucketName = fields[field]; acc[field] = aggregations[bucketName].buckets.map((b: { key: string | number }) => b.key); return acc; }, {}); - } + }, - /** - * Fetch data for the monitor page title. - * @param request Kibana server request - * @param monitorId the ID to query - */ - public async getMonitorPageTitle( - request: any, - monitorId: string - ): Promise { + getMonitorPageTitle: async ({ callES, monitorId }) => { const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -266,7 +219,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { }, }; - const result = await this.database.search(request, params); + const result = await callES('search', params); const pageTitle: Ping | null = get(result, 'hits.hits[0]._source', null); if (pageTitle === null) { return null; @@ -276,14 +229,9 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { url: get(pageTitle, 'url.full', null), name: get(pageTitle, 'monitor.name', null), }; - } + }, - /** - * Fetch data for the monitor page title. - * @param request Kibana server request - * @param monitorId the ID to query - */ - public async getMonitorDetails(request: any, monitorId: string): Promise { + getMonitorDetails: async ({ callES, monitorId }) => { const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -317,7 +265,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { }, }; - const result = await this.database.search(request, params); + const result = await callES('search', params); const data = result.hits.hits[0]?._source; @@ -329,19 +277,14 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { error: monitorError, timestamp: errorTimeStamp, }; - } + }, /** * Fetch data for the monitor page title. * @param request Kibana server request - * @param monitorId the ID to query + * */ - public async getMonitorLocations( - request: any, - monitorId: string, - dateStart: string, - dateEnd: string - ): Promise { + getMonitorLocations: async ({ callES, monitorId, dateStart, dateEnd }) => { const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -394,7 +337,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { }, }; - const result = await this.database.search(request, params); + const result = await callES('search', params); const locations = result?.aggregations?.location?.buckets ?? []; const getGeo = (locGeo: any) => { @@ -425,5 +368,5 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { monitorId, locations: monLocs, }; - } -} + }, +}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/index.ts index e1cb06aa95dced..d02068a11e8d8f 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/index.ts @@ -5,4 +5,4 @@ */ export * from './adapter_types'; -export { ElasticsearchMonitorsAdapter } from './elasticsearch_monitors_adapter'; +export { elasticsearchMonitorsAdapter } from './elasticsearch_monitors_adapter'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts index 7b3c72f535401a..bd1c182e938a3f 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts @@ -5,14 +5,10 @@ */ import { set } from 'lodash'; -import { DatabaseAdapter } from '../../database'; -import { ElasticsearchPingsAdapter } from '../elasticsearch_pings_adapter'; +import { elasticsearchPingsAdapter as adapter } from '../elasticsearch_pings_adapter'; import { assertCloseTo } from '../../../helper'; describe('ElasticsearchPingsAdapter class', () => { - let database: DatabaseAdapter; - let adapter: ElasticsearchPingsAdapter; - let serverRequest: any; let mockHits: any[]; let mockEsSearchResult: any; let mockEsCountResult: any; @@ -77,22 +73,13 @@ describe('ElasticsearchPingsAdapter class', () => { mockEsCountResult = { count: mockHits.length, }; - database = { - search: async (request: any, params: any) => mockEsSearchResult, - count: async (request: any, params: any) => mockEsCountResult, - head: async (request: any, params: any) => null, - }; - adapter = new ElasticsearchPingsAdapter(database); - serverRequest = { - requestArgs: 'hello', - }; }); describe('getPingHistogram', () => { it('returns a single bucket if array has 1', async () => { expect.assertions(2); - const search = jest.fn(); - search.mockReturnValue({ + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue({ aggregations: { timeseries: { buckets: [ @@ -109,43 +96,41 @@ describe('ElasticsearchPingsAdapter class', () => { }, }, }); - const pingDatabase = { - search, - count: jest.fn(), - head: async (request: any, params: any) => null, - }; - const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); - const result = await pingAdapter.getPingHistogram(serverRequest, 'now-15m', 'now', null); + const result = await adapter.getPingHistogram({ + callES: mockEsClient, + dateRangeStart: 'now-15m', + dateRangeEnd: 'now', + filters: null, + }); assertCloseTo(result.interval, 36000, 100); result.interval = 36000; - expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); it('returns expected result for no status filter', async () => { expect.assertions(2); - const search = jest.fn(); + const mockEsClient = jest.fn(); - search.mockReturnValue(standardMockResponse); + mockEsClient.mockReturnValue(standardMockResponse); - const pingDatabase = { - search, - count: jest.fn(), - head: async (request: any, params: any) => null, - }; - const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); - const result = await pingAdapter.getPingHistogram(serverRequest, 'now-15m', 'now', null); + const result = await adapter.getPingHistogram({ + callES: mockEsClient, + dateRangeStart: 'now-15m', + dateRangeEnd: 'now', + filters: null, + }); assertCloseTo(result.interval, 36000, 100); result.interval = 36000; - expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); it('handles status + additional user queries', async () => { expect.assertions(2); - const search = jest.fn(); - search.mockReturnValue({ + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue({ aggregations: { timeseries: { buckets: [ @@ -188,31 +173,25 @@ describe('ElasticsearchPingsAdapter class', () => { ], }, }; - const pingDatabase = { - search, - count: jest.fn(), - head: async (request: any, params: any) => null, - }; - const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); - const result = await pingAdapter.getPingHistogram( - serverRequest, - '1234', - '5678', - JSON.stringify(searchFilter), - undefined, - 'down' - ); + const result = await adapter.getPingHistogram({ + callES: mockEsClient, + dateRangeStart: '1234', + dateRangeEnd: '5678', + filters: JSON.stringify(searchFilter), + monitorId: undefined, + statusFilter: 'down', + }); assertCloseTo(result.interval, 5609564928000, 1000); result.interval = 5609564928000; - expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); it('handles simple_text_query without issues', async () => { expect.assertions(2); - const search = jest.fn(); - search.mockReturnValue({ + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue({ aggregations: { timeseries: { buckets: [ @@ -247,89 +226,71 @@ describe('ElasticsearchPingsAdapter class', () => { }, }, }); - const searchFilter = `{"bool":{"must":[{"simple_query_string":{"query":"http"}}]}}`; - const pingDatabase = { - search, - count: jest.fn(), - head: async (request: any, params: any) => null, - }; - const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); - const result = await pingAdapter.getPingHistogram( - serverRequest, - 'now-15m', - 'now', - searchFilter - ); + const filters = `{"bool":{"must":[{"simple_query_string":{"query":"http"}}]}}`; + const result = await adapter.getPingHistogram({ + callES: mockEsClient, + dateRangeStart: 'now-15m', + dateRangeEnd: 'now', + filters, + }); assertCloseTo(result.interval, 36000, 100); result.interval = 36000; - expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); it('returns a down-filtered array for when filtered by down status', async () => { expect.assertions(2); - const search = jest.fn(); - search.mockReturnValue(standardMockResponse); - const pingDatabase = { - search, - count: jest.fn(), - head: async (request: any, params: any) => null, - }; - const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); - const result = await pingAdapter.getPingHistogram( - serverRequest, - '1234', - '5678', - '', - undefined, - 'down' - ); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(standardMockResponse); + const result = await adapter.getPingHistogram({ + callES: mockEsClient, + dateRangeStart: '1234', + dateRangeEnd: '5678', + filters: '', + monitorId: undefined, + statusFilter: 'down', + }); assertCloseTo(result.interval, 5609564928000, 1000); result.interval = 5609564928000; - expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); it('returns a down-filtered array for when filtered by up status', async () => { expect.assertions(2); - const search = jest.fn(); + const mockEsClient = jest.fn(); - search.mockReturnValue(standardMockResponse); + mockEsClient.mockReturnValue(standardMockResponse); - const pingDatabase = { - search, - count: jest.fn(), - head: async (request: any, params: any) => null, - }; - const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); - const result = await pingAdapter.getPingHistogram( - serverRequest, - '1234', - '5678', - '', - undefined, - 'up' - ); - - expect(pingDatabase.search).toHaveBeenCalledTimes(1); + const result = await adapter.getPingHistogram({ + callES: mockEsClient, + dateRangeStart: '1234', + dateRangeEnd: '5678', + filters: '', + monitorId: undefined, + statusFilter: 'up', + }); + + expect(mockEsClient).toHaveBeenCalledTimes(1); expect(result).toMatchSnapshot(); }); }); describe('getDocCount', () => { it('returns data in appropriate shape', async () => { - const { count } = await adapter.getDocCount(serverRequest); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(mockEsCountResult); + const { count } = await adapter.getDocCount({ callES: mockEsClient }); expect(count).toEqual(3); }); }); describe('getAll', () => { - let getAllSearchMock: (request: any, params: any) => Promise; let expectedGetAllParams: any; beforeEach(() => { - getAllSearchMock = jest.fn(async (request: any, params: any) => mockEsSearchResult); expectedGetAllParams = { index: 'heartbeat-8*', body: { @@ -354,15 +315,15 @@ describe('ElasticsearchPingsAdapter class', () => { }); it('returns data in the appropriate shape', async () => { - const result = await adapter.getAll( - serverRequest, - 'now-1h', - 'now', - undefined, - undefined, - 'asc', - 12 - ); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(mockEsSearchResult); + const result = await adapter.getAll({ + callES: mockEsClient, + dateRangeStart: 'now-1h', + dateRangeEnd: 'now', + sort: 'asc', + size: 12, + }); const count = 3; expect(result.total).toBe(count); @@ -372,57 +333,87 @@ describe('ElasticsearchPingsAdapter class', () => { expect(pings[0].timestamp).toBe('2018-10-30T18:51:59.792Z'); expect(pings[1].timestamp).toBe('2018-10-30T18:53:59.792Z'); expect(pings[2].timestamp).toBe('2018-10-30T18:55:59.792Z'); + expect(mockEsClient).toHaveBeenCalledTimes(1); }); it('creates appropriate sort and size parameters', async () => { - database.search = getAllSearchMock; - await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, undefined, 'asc', 12); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(mockEsSearchResult); + await adapter.getAll({ + callES: mockEsClient, + dateRangeStart: 'now-1h', + dateRangeEnd: 'now', + sort: 'asc', + size: 12, + }); set(expectedGetAllParams, 'body.sort[0]', { '@timestamp': { order: 'asc' } }); - expect(database.search).toHaveBeenCalledTimes(1); - expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); + expect(mockEsClient).toHaveBeenCalledTimes(1); + expect(mockEsClient).toHaveBeenCalledWith('search', expectedGetAllParams); }); it('omits the sort param when no sort passed', async () => { - database.search = getAllSearchMock; - await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, undefined, undefined, 12); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(mockEsSearchResult); + await adapter.getAll({ + callES: mockEsClient, + dateRangeStart: 'now-1h', + dateRangeEnd: 'now', + size: 12, + }); - expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); + expect(mockEsClient).toHaveBeenCalledWith('search', expectedGetAllParams); }); it('omits the size param when no size passed', async () => { - database.search = getAllSearchMock; - await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, undefined, 'desc'); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(mockEsSearchResult); + await adapter.getAll({ + callES: mockEsClient, + dateRangeStart: 'now-1h', + dateRangeEnd: 'now', + sort: 'desc', + }); delete expectedGetAllParams.body.size; set(expectedGetAllParams, 'body.sort[0].@timestamp.order', 'desc'); - expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); + expect(mockEsClient).toHaveBeenCalledWith('search', expectedGetAllParams); }); it('adds a filter for monitor ID', async () => { - database.search = getAllSearchMock; - await adapter.getAll(serverRequest, 'now-1h', 'now', 'testmonitorid'); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(mockEsSearchResult); + await adapter.getAll({ + callES: mockEsClient, + dateRangeStart: 'now-1h', + dateRangeEnd: 'now', + monitorId: 'testmonitorid', + }); delete expectedGetAllParams.body.size; expectedGetAllParams.body.query.bool.filter.push({ term: { 'monitor.id': 'testmonitorid' } }); - expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); + expect(mockEsClient).toHaveBeenCalledWith('search', expectedGetAllParams); }); it('adds a filter for monitor status', async () => { - database.search = getAllSearchMock; - await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, 'down'); + const mockEsClient = jest.fn(); + mockEsClient.mockReturnValue(mockEsSearchResult); + await adapter.getAll({ + callES: mockEsClient, + dateRangeStart: 'now-1h', + dateRangeEnd: 'now', + status: 'down', + }); delete expectedGetAllParams.body.size; expectedGetAllParams.body.query.bool.filter.push({ term: { 'monitor.status': 'down' } }); - expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); + expect(mockEsClient).toHaveBeenCalledWith('search', expectedGetAllParams); }); }); describe('getLatestMonitorDocs', () => { - let getLatestSearchMock: (request: any, params: any) => Promise; let expectedGetLatestSearchParams: any; beforeEach(() => { - getLatestSearchMock = jest.fn(async (request: any, params: any) => mockEsSearchResult); expectedGetLatestSearchParams = { index: 'heartbeat-8*', body: { @@ -491,19 +482,19 @@ describe('ElasticsearchPingsAdapter class', () => { }); it('returns data in expected shape', async () => { - database.search = getLatestSearchMock; - const result = await adapter.getLatestMonitorDocs( - serverRequest, - 'now-1h', - 'now', - 'testmonitor' - ); + const mockEsClient = jest.fn(async (_request: any, _params: any) => mockEsSearchResult); + const result = await adapter.getLatestMonitorDocs({ + callES: mockEsClient, + dateRangeStart: 'now-1h', + dateRangeEnd: 'now', + monitorId: 'testmonitor', + }); expect(result).toHaveLength(1); expect(result[0].timestamp).toBe(123456); expect(result[0].monitor).not.toBeFalsy(); // @ts-ignore monitor will be defined expect(result[0].monitor.id).toBe('testmonitor'); - expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetLatestSearchParams); + expect(mockEsClient).toHaveBeenCalledWith('search', expectedGetLatestSearchParams); }); }); }); diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/adapter_types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/adapter_types.ts index 1e0cf7ec406466..81df1c7c0f6312 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/adapter_types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/adapter_types.ts @@ -6,35 +6,83 @@ import { DocCount, Ping, PingResults } from '../../../../common/graphql/types'; import { HistogramResult } from '../../../../common/domain_types'; +import { UMElasticsearchQueryFn } from '../framework'; +export interface GetAllParams { + /** @member dateRangeStart timestamp bounds */ + dateRangeStart: string; + + /** @member dateRangeEnd timestamp bounds */ + dateRangeEnd: string; + + /** @member monitorId optional limit by monitorId */ + monitorId?: string | null; + + /** @member status optional limit by check statuses */ + status?: string | null; + + /** @member sort optional sort by timestamp */ + sort?: string | null; + + /** @member size optional limit query size */ + size?: number | null; + + /** @member location optional location value for use in filtering*/ + location?: string | null; +} + +export interface GetLatestMonitorDocsParams { + /** @member dateRangeStart timestamp bounds */ + dateRangeStart: string; + + /** @member dateRangeEnd timestamp bounds */ + dateRangeEnd: string; + + /** @member monitorId optional limit to monitorId */ + monitorId?: string | null; + + /** @member location optional location value for use in filtering*/ + location?: string | null; +} + +export interface GetPingHistogramParams { + /** @member dateRangeStart timestamp bounds */ + dateRangeStart: string; + /** @member dateRangeEnd timestamp bounds */ + dateRangeEnd: string; + /** @member filters user-defined filters */ + filters?: string | null; + /** @member monitorId optional limit to monitorId */ + monitorId?: string | null; + /** @member statusFilter special filter targeting the latest status of each monitor */ + statusFilter?: string | null; +} + +/** + * Count the number of documents in heartbeat indices + */ export interface UMPingsAdapter { - getAll( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - monitorId?: string | null, - status?: string | null, - sort?: string | null, - size?: number | null, - location?: string | null - ): Promise; - - getLatestMonitorDocs( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - monitorId?: string | null, - location?: string | null - ): Promise; - - getPingHistogram( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - filters?: string | null, - monitorId?: string | null, - statusFilter?: string | null - ): Promise; - - getDocCount(request: any): Promise; + getAll: UMElasticsearchQueryFn; + + getLatestMonitorDocs: UMElasticsearchQueryFn; + + getPingHistogram: UMElasticsearchQueryFn; + + /** + * Gets data used for a composite histogram for the currently-running monitors. + */ + getDocCount: UMElasticsearchQueryFn<{}, DocCount>; +} + +export interface HistogramQueryResult { + key: number; + doc_count: number; + bucket_total: { + value: number; + }; + down: { + bucket_count: { + value: number; + }; + }; } diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts index 6c71d917940036..6862bed8d2bdd5 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts @@ -6,41 +6,23 @@ import { get } from 'lodash'; import { INDEX_NAMES } from '../../../../common/constants'; -import { DocCount, HttpBody, Ping, PingResults } from '../../../../common/graphql/types'; +import { HttpBody, Ping, PingResults } from '../../../../common/graphql/types'; import { parseFilterQuery, getFilterClause, getHistogramIntervalFormatted } from '../../helper'; -import { DatabaseAdapter, HistogramQueryResult } from '../database'; -import { UMPingsAdapter } from './adapter_types'; +import { UMPingsAdapter, HistogramQueryResult } from './adapter_types'; import { getHistogramInterval } from '../../helper/get_histogram_interval'; -import { HistogramResult } from '../../../../common/domain_types'; -export class ElasticsearchPingsAdapter implements UMPingsAdapter { - private database: DatabaseAdapter; - - constructor(database: DatabaseAdapter) { - this.database = database; - } - - /** - * Fetches ping documents from ES - * @param request Kibana server request - * @param dateRangeStart timestamp bounds - * @param dateRangeEnd timestamp bounds - * @param monitorId optional limit by monitorId - * @param status optional limit by check statuses - * @param sort optional sort by timestamp - * @param size optional limit query size - */ - public async getAll( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - monitorId?: string | null, - status?: string | null, - sort: string | null = 'desc', - size?: number | null, - location?: string | null - ): Promise { - const sortParam = { sort: [{ '@timestamp': { order: sort } }] }; +export const elasticsearchPingsAdapter: UMPingsAdapter = { + getAll: async ({ + callES, + dateRangeStart, + dateRangeEnd, + monitorId, + status, + sort, + size, + location, + }) => { + const sortParam = { sort: [{ '@timestamp': { order: sort ?? 'desc' } }] }; const sizeParam = size ? { size } : undefined; const filter: any[] = [{ range: { '@timestamp': { gte: dateRangeStart, lte: dateRangeEnd } } }]; if (monitorId) { @@ -79,7 +61,7 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { const { hits: { hits, total }, aggregations: aggs, - } = await this.database.search(request, params); + } = await callES('search', params); const locations = get(aggs, 'locations', { buckets: [{ key: 'N/A', doc_count: 0 }] }); @@ -104,23 +86,9 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { }; return results; - } + }, - /** - * Fetch data to populate monitor status bar. - * @param request Kibana server request - * @param dateRangeStart timestamp bounds - * @param dateRangeEnd timestamp bounds - * @param monitorId optional limit to monitorId - */ - public async getLatestMonitorDocs( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - monitorId?: string | null, - location?: string | null - ): Promise { - // TODO: Write tests for this function + getLatestMonitorDocs: async ({ callES, dateRangeStart, dateRangeEnd, monitorId, location }) => { const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -162,10 +130,9 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { }, }; - const result = await this.database.search(request, params); + const result = await callES('search', params); const buckets: any[] = get(result, 'aggregations.by_id.buckets', []); - // @ts-ignore TODO fix destructuring implicit any return buckets.map( ({ latest: { @@ -179,24 +146,16 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { }; } ); - } - - /** - * Gets data used for a composite histogram for the currently-running monitors. - * @param request Kibana server request - * @param dateRangeStart timestamp bounds - * @param dateRangeEnd timestamp bounds - * @param filters user-defined filters - * @param statusFilter special filter targeting the latest status of each monitor - */ - public async getPingHistogram( - request: any, - dateRangeStart: string, - dateRangeEnd: string, - filters?: string | null, - monitorId?: string | null, - statusFilter?: string | null - ): Promise { + }, + + getPingHistogram: async ({ + callES, + dateRangeStart, + dateRangeEnd, + filters, + monitorId, + statusFilter, + }) => { const boolFilters = parseFilterQuery(filters); const additionaFilters = []; if (monitorId) { @@ -245,7 +204,7 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { }, }; - const result = await this.database.search(request, params); + const result = await callES('search', params); const buckets: HistogramQueryResult[] = get(result, 'aggregations.timeseries.buckets', []); const histogram = buckets.map(bucket => { const x: number = get(bucket, 'key'); @@ -262,15 +221,11 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { histogram, interval, }; - } + }, - /** - * Count the number of documents in heartbeat indices - * @param request Kibana server request - */ - public async getDocCount(request: any): Promise { - const { count } = await this.database.count(request, { index: INDEX_NAMES.HEARTBEAT }); + getDocCount: async ({ callES }) => { + const { count } = await callES('count', { index: INDEX_NAMES.HEARTBEAT }); return { count }; - } -} + }, +}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts index eee6aa279dd392..6d93785e01527b 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/pings/index.ts @@ -5,4 +5,4 @@ */ export * from './adapter_types'; -export { ElasticsearchPingsAdapter } from './elasticsearch_pings_adapter'; +export { elasticsearchPingsAdapter } from './elasticsearch_pings_adapter'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/index.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/index.ts index 86154d0ab80a41..bd86daba1bcb62 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/index.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/index.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { UMKibanaSavedObjectsAdapter } from './kibana_saved_objects_adapter'; +export { savedObjectsAdapter } from './kibana_saved_objects_adapter'; export { UMSavedObjectsAdapter } from './types'; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts index 1f10c2f7aeed13..7628c5bac0660f 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/kibana_saved_objects_adapter.ts @@ -4,24 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsLegacyService } from 'src/core/server'; import { UMSavedObjectsAdapter } from './types'; import uptimeIndexPattern from './heartbeat_index_pattern.json'; -export class UMKibanaSavedObjectsAdapter implements UMSavedObjectsAdapter { - private readonly savedObjectsClient: any; - constructor(savedObjects: SavedObjectsLegacyService, elasticsearch: any) { - const { SavedObjectsClient, getSavedObjectsRepository } = savedObjects; - const { callWithInternalUser } = elasticsearch.getCluster('admin'); - const internalRepository = getSavedObjectsRepository(callWithInternalUser); - this.savedObjectsClient = new SavedObjectsClient(internalRepository); - } - - public async getUptimeIndexPattern(): Promise { +export const savedObjectsAdapter: UMSavedObjectsAdapter = { + getUptimeIndexPattern: async client => { try { - return await this.savedObjectsClient.get('index-pattern', uptimeIndexPattern.id); + return await client.get('index-pattern', uptimeIndexPattern.id); } catch (error) { - return await this.savedObjectsClient.create( + return await client.create( 'index-pattern', { ...uptimeIndexPattern.attributes, @@ -30,5 +21,5 @@ export class UMKibanaSavedObjectsAdapter implements UMSavedObjectsAdapter { { id: uptimeIndexPattern.id, overwrite: false } ); } - } -} + }, +}; diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts index 4d11bd9f6053af..0fef1e1428e97b 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/saved_objects/types.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { UMSavedObjectsQueryFn } from '../framework'; + export interface UMSavedObjectsAdapter { - getUptimeIndexPattern: () => Promise; + getUptimeIndexPattern: UMSavedObjectsQueryFn; } diff --git a/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts b/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts index a7c370e03490b1..cc11bf90da5f3b 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/compose/kibana.ts @@ -4,32 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import { UMKibanaDatabaseAdapter } from '../adapters/database/kibana_database_adapter'; import { UMKibanaBackendFrameworkAdapter } from '../adapters/framework'; -import { ElasticsearchMonitorsAdapter } from '../adapters/monitors'; -import { ElasticsearchPingsAdapter } from '../adapters/pings'; +import { elasticsearchMonitorsAdapter } from '../adapters/monitors'; +import { elasticsearchPingsAdapter } from '../adapters/pings'; import { licenseCheck } from '../domains'; import { UMDomainLibs, UMServerLibs } from '../lib'; -import { ElasticsearchMonitorStatesAdapter } from '../adapters/monitor_states'; -import { UMKibanaSavedObjectsAdapter } from '../adapters/saved_objects/kibana_saved_objects_adapter'; +import { elasticsearchMonitorStatesAdapter } from '../adapters/monitor_states'; +import { savedObjectsAdapter } from '../adapters/saved_objects'; import { UptimeCorePlugins, UptimeCoreSetup } from '../adapters/framework'; export function compose(server: UptimeCoreSetup, plugins: UptimeCorePlugins): UMServerLibs { - const { elasticsearch, savedObjects } = plugins; - const framework = new UMKibanaBackendFrameworkAdapter(server, plugins); - const database = new UMKibanaDatabaseAdapter(elasticsearch); + const framework = new UMKibanaBackendFrameworkAdapter(server); const domainLibs: UMDomainLibs = { license: licenseCheck, - monitors: new ElasticsearchMonitorsAdapter(database), - monitorStates: new ElasticsearchMonitorStatesAdapter(database), - pings: new ElasticsearchPingsAdapter(database), - savedObjects: new UMKibanaSavedObjectsAdapter(savedObjects, elasticsearch), + monitors: elasticsearchMonitorsAdapter, + monitorStates: elasticsearchMonitorStatesAdapter, + pings: elasticsearchPingsAdapter, + savedObjects: savedObjectsAdapter, }; return { framework, - database, ...domainLibs, }; } diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap b/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap index ab791cbd243f8f..d03516d49f0898 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap +++ b/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/__snapshots__/license.test.ts.snap @@ -2,6 +2,7 @@ exports[`license check returns result for a valid license 1`] = ` Object { + "message": "License is valid and active", "statusCode": 200, } `; diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/license.test.ts b/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/license.test.ts index b26cb99cf9b6b2..8c340f5525a4c0 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/license.test.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/domains/__tests__/license.test.ts @@ -11,7 +11,7 @@ describe('license check', () => { let mockLicense: Pick; it('throws for null license', () => { - expect(licenseCheck(null)).toMatchSnapshot(); + expect(licenseCheck(undefined)).toMatchSnapshot(); }); it('throws for unsupported license type', () => { diff --git a/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts b/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts index 947bad75075ef9..24ce0205414fa4 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/domains/license.ts @@ -8,14 +8,14 @@ import { ILicense } from '../../../../../../plugins/licensing/server'; export interface UMLicenseStatusResponse { statusCode: number; - message?: string; + message: string; } export type UMLicenseCheck = ( - license: Pick | null + license?: Pick ) => UMLicenseStatusResponse; export const licenseCheck: UMLicenseCheck = license => { - if (license === null) { + if (license === undefined) { return { message: 'Missing license information', statusCode: 400, @@ -34,6 +34,7 @@ export const licenseCheck: UMLicenseCheck = license => { }; } return { + message: 'License is valid and active', statusCode: 200, }; }; diff --git a/x-pack/legacy/plugins/uptime/server/lib/lib.ts b/x-pack/legacy/plugins/uptime/server/lib/lib.ts index e68a6dd18ef5f2..da87c3ebfe3017 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/lib.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/lib.ts @@ -5,7 +5,6 @@ */ import { - DatabaseAdapter, UMBackendFrameworkAdapter, UMMonitorsAdapter, UMMonitorStatesAdapter, @@ -24,5 +23,4 @@ export interface UMDomainLibs { export interface UMServerLibs extends UMDomainLibs { framework: UMBackendFrameworkAdapter; - database?: DatabaseAdapter; } diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/create_route_with_auth.ts b/x-pack/legacy/plugins/uptime/server/rest_api/create_route_with_auth.ts index a1976ef046e8ee..41527d76432cb4 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/create_route_with_auth.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/create_route_with_auth.ts @@ -4,32 +4,36 @@ * you may not use this file except in compliance with the Elastic License. */ -import { RequestHandler } from 'kibana/server'; -import { ObjectType } from '@kbn/config-schema'; import { UMServerLibs } from '../lib/lib'; -import { UMRestApiRouteCreator, UMRouteDefinition } from './types'; +import { UptimeRoute, UMRestApiRouteFactory, UMRouteHandler } from './types'; export const createRouteWithAuth = ( libs: UMServerLibs, - routeCreator: UMRestApiRouteCreator -): UMRouteDefinition => { + routeCreator: UMRestApiRouteFactory +): UptimeRoute => { const restRoute = routeCreator(libs); const { handler, method, path, options, ...rest } = restRoute; - const authHandler: RequestHandler = async ( - context, - request, - response - ) => { - if (libs.license(context.licensing.license)) { - return await handler(context, request, response); + const licenseCheckHandler: UMRouteHandler = async (customParams, context, request, response) => { + const { statusCode, message } = libs.license(context.licensing.license); + if (statusCode === 200) { + return await handler(customParams, context, request, response); + } + switch (statusCode) { + case 400: + return response.badRequest({ body: { message } }); + case 401: + return response.unauthorized({ body: { message } }); + case 403: + return response.forbidden({ body: { message } }); + default: + return response.internalError(); } - return response.badRequest(); }; return { method, path, options, - handler: authHandler, + handler: licenseCheckHandler, ...rest, }; }; diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index.ts b/x-pack/legacy/plugins/uptime/server/rest_api/index.ts index f18b9e8e44c36b..4ab225076eff22 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/index.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/index.ts @@ -8,12 +8,13 @@ import { createGetAllRoute } from './pings'; import { createGetIndexPatternRoute } from './index_pattern'; import { createLogMonitorPageRoute, createLogOverviewPageRoute } from './telemetry'; import { createGetSnapshotCount } from './snapshot'; -import { UMRestApiRouteCreator } from './types'; +import { UMRestApiRouteFactory } from './types'; import { createGetMonitorDetailsRoute, createGetMonitorLocationsRoute } from './monitors'; export * from './types'; export { createRouteWithAuth } from './create_route_with_auth'; -export const restApiRoutes: UMRestApiRouteCreator[] = [ +export { uptimeRouteWrapper } from './uptime_route_wrapper'; +export const restApiRoutes: UMRestApiRouteFactory[] = [ createGetAllRoute, createGetIndexPatternRoute, createGetMonitorDetailsRoute, diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts b/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts index 55f0af57ed847e..f061307807a42d 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/index_pattern/get_index_pattern.ts @@ -5,20 +5,20 @@ */ import { UMServerLibs } from '../../lib/lib'; -import { UMRestApiRouteCreator } from '../types'; +import { UMRestApiRouteFactory } from '../types'; -export const createGetIndexPatternRoute: UMRestApiRouteCreator = (libs: UMServerLibs) => ({ +export const createGetIndexPatternRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', path: '/api/uptime/index_pattern', validate: false, options: { tags: ['access:uptime'], }, - handler: async (_context, _request, response): Promise => { + handler: async ({ savedObjectsClient: client }, _context, _request, response): Promise => { try { return response.ok({ body: { - ...(await libs.savedObjects.getUptimeIndexPattern()), + ...(await libs.savedObjects.getUptimeIndexPattern(client, undefined)), }, }); } catch (e) { diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitor_locations.ts b/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitor_locations.ts index 4a91255bd19f2b..b2356ae0a88bf1 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitor_locations.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitor_locations.ts @@ -6,9 +6,9 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; -import { UMRestApiRouteCreator } from '../types'; +import { UMRestApiRouteFactory } from '../types'; -export const createGetMonitorLocationsRoute: UMRestApiRouteCreator = (libs: UMServerLibs) => ({ +export const createGetMonitorLocationsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', path: '/api/uptime/monitor/locations', validate: { @@ -21,12 +21,17 @@ export const createGetMonitorLocationsRoute: UMRestApiRouteCreator = (libs: UMSe options: { tags: ['access:uptime'], }, - handler: async (_context, request, response): Promise => { + handler: async ({ callES }, _context, request, response): Promise => { const { monitorId, dateStart, dateEnd } = request.query; return response.ok({ body: { - ...(await libs.monitors.getMonitorLocations(request, monitorId, dateStart, dateEnd)), + ...(await libs.monitors.getMonitorLocations({ + callES, + monitorId, + dateStart, + dateEnd, + })), }, }); }, diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitors_details.ts b/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitors_details.ts index 00860248ff1538..a57e5ec469c59d 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitors_details.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/monitors/monitors_details.ts @@ -6,9 +6,9 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; -import { UMRestApiRouteCreator } from '../types'; +import { UMRestApiRouteFactory } from '../types'; -export const createGetMonitorDetailsRoute: UMRestApiRouteCreator = (libs: UMServerLibs) => ({ +export const createGetMonitorDetailsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', path: '/api/uptime/monitor/details', validate: { @@ -19,11 +19,13 @@ export const createGetMonitorDetailsRoute: UMRestApiRouteCreator = (libs: UMServ options: { tags: ['access:uptime'], }, - handler: async (_context, request, response): Promise => { + handler: async ({ callES }, _context, request, response): Promise => { const { monitorId } = request.query; return response.ok({ - body: { ...(await libs.monitors.getMonitorDetails(request, monitorId)) }, + body: { + ...(await libs.monitors.getMonitorDetails({ callES, monitorId })), + }, }); }, }); diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_all.ts b/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_all.ts index e2bdbca9fbfa07..824035954ea284 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_all.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/pings/get_all.ts @@ -6,9 +6,9 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; -import { UMRestApiRouteCreator } from '../types'; +import { UMRestApiRouteFactory } from '../types'; -export const createGetAllRoute: UMRestApiRouteCreator = (libs: UMServerLibs) => ({ +export const createGetAllRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', path: '/api/uptime/pings', validate: { @@ -25,19 +25,19 @@ export const createGetAllRoute: UMRestApiRouteCreator = (libs: UMServerLibs) => options: { tags: ['access:uptime'], }, - handler: async (_context, request, response): Promise => { - const { size, sort, dateRangeStart, dateRangeEnd, location, monitorId, status } = request.query; + handler: async ({ callES }, _context, request, response): Promise => { + const { dateRangeStart, dateRangeEnd, location, monitorId, size, sort, status } = request.query; - const result = await libs.pings.getAll( - request, + const result = await libs.pings.getAll({ + callES, dateRangeStart, dateRangeEnd, monitorId, status, sort, size, - location - ); + location, + }); return response.ok({ body: { diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts b/x-pack/legacy/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts index 9b2b26f52699e5..986ac797d63b62 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts @@ -6,9 +6,9 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; -import { UMRestApiRouteCreator } from '../types'; +import { UMRestApiRouteFactory } from '../types'; -export const createGetSnapshotCount: UMRestApiRouteCreator = (libs: UMServerLibs) => ({ +export const createGetSnapshotCount: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', path: '/api/uptime/snapshot/count', validate: { @@ -22,15 +22,15 @@ export const createGetSnapshotCount: UMRestApiRouteCreator = (libs: UMServerLibs options: { tags: ['access:uptime'], }, - handler: async (_context, request, response): Promise => { + handler: async ({ callES }, _context, request, response): Promise => { const { dateRangeStart, dateRangeEnd, filters, statusFilter } = request.query; - const result = await libs.monitorStates.getSnapshotCount( - request, + const result = await libs.monitorStates.getSnapshotCount({ + callES, dateRangeStart, dateRangeEnd, filters, - statusFilter - ); + statusFilter, + }); return response.ok({ body: { ...result, diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts b/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts index f3e926493143b8..fca1e6c8d5d46d 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_monitor_page.ts @@ -5,13 +5,13 @@ */ import { KibanaTelemetryAdapter } from '../../lib/adapters/telemetry'; -import { UMRestApiRouteCreator } from '../types'; +import { UMRestApiRouteFactory } from '../types'; -export const createLogMonitorPageRoute: UMRestApiRouteCreator = () => ({ +export const createLogMonitorPageRoute: UMRestApiRouteFactory = () => ({ method: 'POST', path: '/api/uptime/logMonitor', validate: false, - handler: async (_context, _request, response): Promise => { + handler: async (_customParams, _context, _request, response): Promise => { await KibanaTelemetryAdapter.countMonitor(); return response.ok(); }, diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts b/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts index 277ef2235fb69c..37ed2e5ff5c2cf 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/telemetry/log_overview_page.ts @@ -5,13 +5,13 @@ */ import { KibanaTelemetryAdapter } from '../../lib/adapters/telemetry'; -import { UMRestApiRouteCreator } from '../types'; +import { UMRestApiRouteFactory } from '../types'; -export const createLogOverviewPageRoute: UMRestApiRouteCreator = () => ({ +export const createLogOverviewPageRoute: UMRestApiRouteFactory = () => ({ method: 'POST', path: '/api/uptime/logOverview', validate: false, - handler: async (_context, _request, response): Promise => { + handler: async (_customParams, _context, _request, response): Promise => { await KibanaTelemetryAdapter.countOverview(); return response.ok(); }, diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/types.ts b/x-pack/legacy/plugins/uptime/server/rest_api/types.ts index b4d7e438f51be3..e0c8ba4a286cf6 100644 --- a/x-pack/legacy/plugins/uptime/server/rest_api/types.ts +++ b/x-pack/legacy/plugins/uptime/server/rest_api/types.ts @@ -5,15 +5,87 @@ */ import { ObjectType } from '@kbn/config-schema'; -import { RequestHandler, RouteConfig, RouteMethod } from 'kibana/server'; +import { + RequestHandler, + RouteConfig, + RouteMethod, + CallAPIOptions, + SavedObjectsClient, + RequestHandlerContext, + KibanaRequest, + KibanaResponseFactory, + IKibanaResponse, +} from 'kibana/server'; import { UMServerLibs } from '../lib/lib'; -export interface UMServerRoute { +/** + * Defines the basic properties employed by Uptime routes. + */ +export interface UMServerRoute { method: string; - handler: RequestHandler; + handler: T; } -export type UMRouteDefinition = UMServerRoute & +/** + * Merges basic uptime route properties with the route config type + * provided by Kibana core. + */ +export type UMRouteDefinition = UMServerRoute & RouteConfig; -export type UMRestApiRouteCreator = (libs: UMServerLibs) => UMRouteDefinition; +/** + * This type represents an Uptime route definition that corresponds to the contract + * provided by the Kibana platform. Route objects must conform to this type in order + * to successfully interact with the Kibana platform. + */ +export type UMKibanaRoute = UMRouteDefinition>; + +/** + * This is an abstraction over the default Kibana route type. This allows us to use custom + * arguments in our route handlers and impelement custom middleware. + */ +export type UptimeRoute = UMRouteDefinition; + +/** + * Functions of this type accept custom lib functions and outputs a route object. + */ +export type UMRestApiRouteFactory = (libs: UMServerLibs) => UptimeRoute; + +/** + * Functions of this type accept our internal route format and output a route + * object that the Kibana platform can consume. + */ +export type UMKibanaRouteWrapper = (uptimeRoute: UptimeRoute) => UMKibanaRoute; + +/** + * This type can store custom parameters used by the internal Uptime route handlers. + */ +export interface UMRouteParams { + callES: ( + endpoint: string, + clientParams?: Record, + options?: CallAPIOptions | undefined + ) => Promise; + savedObjectsClient: Pick< + SavedObjectsClient, + | 'errors' + | 'create' + | 'bulkCreate' + | 'delete' + | 'find' + | 'bulkGet' + | 'get' + | 'update' + | 'bulkUpdate' + >; +} + +/** + * This is the contract we specify internally for route handling. + */ +export type UMRouteHandler = ( + params: UMRouteParams, + context: RequestHandlerContext, + request: KibanaRequest, Record, Record>, + response: KibanaResponseFactory +) => IKibanaResponse | Promise>; diff --git a/x-pack/legacy/plugins/uptime/server/rest_api/uptime_route_wrapper.ts b/x-pack/legacy/plugins/uptime/server/rest_api/uptime_route_wrapper.ts new file mode 100644 index 00000000000000..fb874edebee609 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/server/rest_api/uptime_route_wrapper.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { UMKibanaRouteWrapper } from './types'; + +export const uptimeRouteWrapper: UMKibanaRouteWrapper = uptimeRoute => { + return { + ...uptimeRoute, + handler: async (context, request, response) => { + const { callAsCurrentUser: callES } = context.core.elasticsearch.dataClient; + const { client: savedObjectsClient } = context.core.savedObjects; + return await uptimeRoute.handler({ callES, savedObjectsClient }, context, request, response); + }, + }; +}; diff --git a/x-pack/legacy/plugins/uptime/server/uptime_server.ts b/x-pack/legacy/plugins/uptime/server/uptime_server.ts index a8058453f21668..4dfa1373db8d9a 100644 --- a/x-pack/legacy/plugins/uptime/server/uptime_server.ts +++ b/x-pack/legacy/plugins/uptime/server/uptime_server.ts @@ -7,10 +7,12 @@ import { makeExecutableSchema } from 'graphql-tools'; import { DEFAULT_GRAPHQL_PATH, resolvers, typeDefs } from './graphql'; import { UMServerLibs } from './lib/lib'; -import { createRouteWithAuth, restApiRoutes } from './rest_api'; +import { createRouteWithAuth, restApiRoutes, uptimeRouteWrapper } from './rest_api'; export const initUptimeServer = (libs: UMServerLibs) => { - restApiRoutes.forEach(route => libs.framework.registerRoute(createRouteWithAuth(libs, route))); + restApiRoutes.forEach(route => + libs.framework.registerRoute(uptimeRouteWrapper(createRouteWithAuth(libs, route))) + ); const graphQLSchema = makeExecutableSchema({ resolvers: resolvers.map(createResolversFn => createResolversFn(libs)), From 4a95aefa0432b33e3da617a236b8005492980987 Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Tue, 17 Dec 2019 22:46:18 +0100 Subject: [PATCH 29/60] [SIEM] Cleanup _g param from url (#53316) --- .../lib/ml_conditional_links/index.ts | 14 ++++----- .../integration/lib/url_state/index.ts | 8 ++--- .../ml_conditional_links.spec.ts | 26 ++++++++-------- .../components/ml/api/throw_if_not_ok.test.ts | 8 ++--- .../components/ml_popover/__mocks__/api.tsx | 30 +++++++++---------- .../components/url_state/index.test.tsx | 4 +-- .../url_state/index_mocked.test.tsx | 14 ++++----- .../components/url_state/test_dependencies.ts | 14 ++++----- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/x-pack/legacy/plugins/siem/cypress/integration/lib/ml_conditional_links/index.ts b/x-pack/legacy/plugins/siem/cypress/integration/lib/ml_conditional_links/index.ts index 8ba20b3ec0048c..655418fc98bf8e 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/lib/ml_conditional_links/index.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/lib/ml_conditional_links/index.ts @@ -49,28 +49,28 @@ export const mlNetworkKqlQuery = // Single host name with a null for the Query: export const mlHostSingleHostNullKqlQuery = - "/app/siem#/ml-hosts/siem-windows?_g=()&query=!n&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; + "/app/siem#/ml-hosts/siem-windows?query=!n&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; // Single host name with a variable in the Query: export const mlHostSingleHostKqlQueryVariable = - "/app/siem#/ml-hosts/siem-windows?_g=()&query=(language:kuery,query:'process.name%20:%20%22$process.name$%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; + "/app/siem#/ml-hosts/siem-windows?query=(language:kuery,query:'process.name%20:%20%22$process.name$%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; // Single host name with a value for Query: export const mlHostSingleHostKqlQuery = - "/app/siem#/ml-hosts/siem-windows?_g=()&query=(language:kuery,query:'process.name%20:%20%22conhost.exe,sc.exe%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; + "/app/siem#/ml-hosts/siem-windows?query=(language:kuery,query:'process.name%20:%20%22conhost.exe,sc.exe%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; // Multiple host names with null for Query: export const mlHostMultiHostNullKqlQuery = - "/app/siem#/ml-hosts/siem-windows,siem-suricata?_g=()&query=!n&&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; + "/app/siem#/ml-hosts/siem-windows,siem-suricata?query=!n&&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; // Multiple host names with a value for Query: export const mlHostMultiHostKqlQuery = - "/app/siem#/ml-hosts/siem-windows,siem-suricata?_g=()&query=(language:kuery,query:'process.name%20:%20%22conhost.exe,sc.exe%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; + "/app/siem#/ml-hosts/siem-windows,siem-suricata?query=(language:kuery,query:'process.name%20:%20%22conhost.exe,sc.exe%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; // Undefined/null host name with a null for the KQL: export const mlHostVariableHostNullKqlQuery = - "/app/siem#/ml-hosts/$host.name$?_g=()&query=!n&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; + "/app/siem#/ml-hosts/$host.name$?query=!n&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; // Undefined/null host name but with a value for Query: export const mlHostVariableHostKqlQuery = - "/app/siem#/ml-hosts/$host.name$?_g=()&query=(language:kuery,query:'process.name%20:%20%22conhost.exe,sc.exe%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; + "/app/siem#/ml-hosts/$host.name$?query=(language:kuery,query:'process.name%20:%20%22conhost.exe,sc.exe%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')),timeline:(linkTo:!(global),timerange:(from:'2019-06-06T06:00:00.000Z',kind:absolute,to:'2019-06-07T05:59:59.999Z')))"; diff --git a/x-pack/legacy/plugins/siem/cypress/integration/lib/url_state/index.ts b/x-pack/legacy/plugins/siem/cypress/integration/lib/url_state/index.ts index ef1892b3d382c0..99d90e3c42aca6 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/lib/url_state/index.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/lib/url_state/index.ts @@ -35,10 +35,10 @@ export const ABSOLUTE_DATE_RANGE = { urlUnlinked: '/app/siem#/network/?timerange=(global:(linkTo:!(),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(),timerange:(from:1564776209186,kind:absolute,to:1564779809186)))', - urlKqlNetworkNetwork: `/app/siem#/network/?_g=()&query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, - urlKqlNetworkHosts: `/app/siem#/network/?_g=()&query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, - urlKqlHostsNetwork: `/app/siem#/hosts/allHosts?_g=()&query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, - urlKqlHostsHosts: `/app/siem#/hosts/allHosts?_g=()&query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, + urlKqlNetworkNetwork: `/app/siem#/network/?query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, + urlKqlNetworkHosts: `/app/siem#/network/?query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, + urlKqlHostsNetwork: `/app/siem#/hosts/allHosts?query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, + urlKqlHostsHosts: `/app/siem#/hosts/allHosts?query=(language:kuery,query:'source.ip:%20"10.142.0.9"')&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`, urlHost: '/app/siem#/hosts/authentications?timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))', }; diff --git a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/ml_conditional_links/ml_conditional_links.spec.ts b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/ml_conditional_links/ml_conditional_links.spec.ts index a03ff0c1845f85..4c29c081b3e69e 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/ml_conditional_links/ml_conditional_links.spec.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/smoke_tests/ml_conditional_links/ml_conditional_links.spec.ts @@ -104,7 +104,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlNetworkSingleIpNullKqlQuery); cy.url().should( 'include', - '/app/siem#/network/ip/127.0.0.1?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))' + '/app/siem#/network/ip/127.0.0.1?timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))' ); }); @@ -112,7 +112,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlNetworkSingleIpKqlQuery); cy.url().should( 'include', - "/app/siem#/network/ip/127.0.0.1?_g=()&query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))" + "/app/siem#/network/ip/127.0.0.1?query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))" ); }); @@ -120,7 +120,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlNetworkMultipleIpNullKqlQuery); cy.url().should( 'include', - "app/siem#/network/flows?_g=()&query=(language:kuery,query:'((source.ip:%20%22127.0.0.1%22%20or%20destination.ip:%20%22127.0.0.1%22)%20or%20(source.ip:%20%22127.0.0.2%22%20or%20destination.ip:%20%22127.0.0.2%22))')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999))" + "app/siem#/network/flows?query=(language:kuery,query:'((source.ip:%20%22127.0.0.1%22%20or%20destination.ip:%20%22127.0.0.1%22)%20or%20(source.ip:%20%22127.0.0.2%22%20or%20destination.ip:%20%22127.0.0.2%22))')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999))" ); }); @@ -128,7 +128,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlNetworkMultipleIpKqlQuery); cy.url().should( 'include', - "/app/siem#/network/flows?_g=()&query=(language:kuery,query:'((source.ip:%20%22127.0.0.1%22%20or%20destination.ip:%20%22127.0.0.1%22)%20or%20(source.ip:%20%22127.0.0.2%22%20or%20destination.ip:%20%22127.0.0.2%22))%20and%20((process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22))')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))" + "/app/siem#/network/flows?query=(language:kuery,query:'((source.ip:%20%22127.0.0.1%22%20or%20destination.ip:%20%22127.0.0.1%22)%20or%20(source.ip:%20%22127.0.0.2%22%20or%20destination.ip:%20%22127.0.0.2%22))%20and%20((process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22))')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))" ); }); @@ -136,7 +136,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlNetworkNullKqlQuery); cy.url().should( 'include', - '/app/siem#/network/flows?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))' + '/app/siem#/network/flows?timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))' ); }); @@ -144,7 +144,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlNetworkKqlQuery); cy.url().should( 'include', - "/app/siem#/network/flows?_g=()&query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))" + "/app/siem#/network/flows?query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1566990000000,kind:absolute,to:1567000799999)),timeline:(linkTo:!(global),timerange:(from:1566990000000,kind:absolute,to:1567000799999)))" ); }); @@ -152,7 +152,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlHostSingleHostNullKqlQuery); cy.url().should( 'include', - '/app/siem#/hosts/siem-windows/anomalies?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))' + '/app/siem#/hosts/siem-windows/anomalies?timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))' ); }); @@ -160,7 +160,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlHostSingleHostKqlQueryVariable); cy.url().should( 'include', - '/app/siem#/hosts/siem-windows/anomalies?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))' + '/app/siem#/hosts/siem-windows/anomalies?timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))' ); }); @@ -168,7 +168,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlHostSingleHostKqlQuery); cy.url().should( 'include', - "/app/siem#/hosts/siem-windows/anomalies?_g=()&query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" + "/app/siem#/hosts/siem-windows/anomalies?query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" ); }); @@ -176,7 +176,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlHostMultiHostNullKqlQuery); cy.url().should( 'include', - "/app/siem#/hosts/anomalies?_g=()&query=(language:kuery,query:'(host.name:%20%22siem-windows%22%20or%20host.name:%20%22siem-suricata%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" + "/app/siem#/hosts/anomalies?query=(language:kuery,query:'(host.name:%20%22siem-windows%22%20or%20host.name:%20%22siem-suricata%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" ); }); @@ -184,7 +184,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlHostMultiHostKqlQuery); cy.url().should( 'include', - "/app/siem#/hosts/anomalies?_g=()&query=(language:kuery,query:'(host.name:%20%22siem-windows%22%20or%20host.name:%20%22siem-suricata%22)%20and%20((process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22))')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" + "/app/siem#/hosts/anomalies?query=(language:kuery,query:'(host.name:%20%22siem-windows%22%20or%20host.name:%20%22siem-suricata%22)%20and%20((process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22))')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" ); }); @@ -192,7 +192,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlHostVariableHostNullKqlQuery); cy.url().should( 'include', - '/app/siem#/hosts/anomalies?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))' + '/app/siem#/hosts/anomalies?timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))' ); }); @@ -200,7 +200,7 @@ describe('ml conditional links', () => { loginAndWaitForPage(mlHostVariableHostKqlQuery); cy.url().should( 'include', - "/app/siem#/hosts/anomalies?_g=()&query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" + "/app/siem#/hosts/anomalies?query=(language:kuery,query:'(process.name:%20%22conhost.exe%22%20or%20process.name:%20%22sc.exe%22)')&timerange=(global:(linkTo:!(timeline),timerange:(from:1559800800000,kind:absolute,to:1559887199999)),timeline:(linkTo:!(global),timerange:(from:1559800800000,kind:absolute,to:1559887199999)))" ); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/ml/api/throw_if_not_ok.test.ts b/x-pack/legacy/plugins/siem/public/components/ml/api/throw_if_not_ok.test.ts index cb1ed1bfe8e84c..9fd00105352031 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml/api/throw_if_not_ok.test.ts +++ b/x-pack/legacy/plugins/siem/public/components/ml/api/throw_if_not_ok.test.ts @@ -230,7 +230,7 @@ describe('throw_if_not_ok', () => { path: '/_ml/anomaly_detectors/siem-api-suspicious_login_activity_ecs', query: {}, body: - '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually high number of authentication attempts (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"high number of authentication attempts","function":"high_non_zero_count","partition_field_name":"host.name"}],"influencers":["host.name","user.name","source.ip"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"IP Address Details","url_value":"siem#/ml-network/ip/$source.ip$?_g=()&query=!n&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', + '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually high number of authentication attempts (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"high number of authentication attempts","function":"high_non_zero_count","partition_field_name":"host.name"}],"influencers":["host.name","user.name","source.ip"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"IP Address Details","url_value":"siem#/ml-network/ip/$source.ip$?query=!n&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index"}],"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index","caused_by":{"type":"illegal_argument_exception","reason":"mapper [multi_bucket_impact] of different type, current_type [keyword], merged_type [double]"}},"status":400}', @@ -245,7 +245,7 @@ describe('throw_if_not_ok', () => { path: '/_ml/anomaly_detectors/siem-api-rare_process_linux_ecs', query: {}, body: - '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually rare processes on Linux (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare process executions on Linux","function":"rare","by_field_name":"process.name","partition_field_name":"host.name"}],"influencers":["host.name","process.name","user.name"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?_g=()&query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?_g=()&query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?_g=()&query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?_g=()&query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', + '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually rare processes on Linux (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare process executions on Linux","function":"rare","by_field_name":"process.name","partition_field_name":"host.name"}],"influencers":["host.name","process.name","user.name"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index"}],"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index","caused_by":{"type":"illegal_argument_exception","reason":"mapper [multi_bucket_impact] of different type, current_type [keyword], merged_type [double]"}},"status":400}', @@ -320,7 +320,7 @@ describe('throw_if_not_ok', () => { path: '/_ml/anomaly_detectors/siem-api-suspicious_login_activity_ecs', query: {}, body: - '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually high number of authentication attempts (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"high number of authentication attempts","function":"high_non_zero_count","partition_field_name":"host.name"}],"influencers":["host.name","user.name","source.ip"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"IP Address Details","url_value":"siem#/ml-network/ip/$source.ip$?_g=()&query=!n,queryLocation:network.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', + '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually high number of authentication attempts (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"high number of authentication attempts","function":"high_non_zero_count","partition_field_name":"host.name"}],"influencers":["host.name","user.name","source.ip"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"IP Address Details","url_value":"siem#/ml-network/ip/$source.ip$?query=!n,queryLocation:network.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index"}],"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index","caused_by":{"type":"illegal_argument_exception","reason":"mapper [multi_bucket_impact] of different type, current_type [keyword], merged_type [double]"}},"status":400}', @@ -335,7 +335,7 @@ describe('throw_if_not_ok', () => { path: '/_ml/anomaly_detectors/siem-api-rare_process_linux_ecs', query: {}, body: - '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually rare processes on Linux (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare process executions on Linux","function":"rare","by_field_name":"process.name","partition_field_name":"host.name"}],"influencers":["host.name","process.name","user.name"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?_g=()&query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?_g=()&query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?_g=()&query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?_g=()&query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', + '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Detect unusually rare processes on Linux (beta)","groups":["siem"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare process executions on Linux","function":"rare","by_field_name":"process.name","partition_field_name":"host.name"}],"influencers":["host.name","process.name","user.name"]},"analysis_limits":{"model_memory_limit":"256mb"},"data_description":{"time_field":"@timestamp","time_format":"epoch_ms"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?query=(query:\'process.name%20:%20%22$process.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?query=(query:\'user.name%20:%20%22$user.name$%22\',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]}}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index"}],"type":"status_exception","reason":"This job would cause a mapping clash with existing field [multi_bucket_impact] - avoid the clash by assigning a dedicated results index","caused_by":{"type":"illegal_argument_exception","reason":"mapper [multi_bucket_impact] of different type, current_type [keyword], merged_type [double]"}},"status":400}', diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/__mocks__/api.tsx b/x-pack/legacy/plugins/siem/public/components/ml_popover/__mocks__/api.tsx index 76c276cf69b637..54bb0a96207e14 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/__mocks__/api.tsx +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/__mocks__/api.tsx @@ -145,22 +145,22 @@ export const mockGetModuleResponse: Module[] = [ { url_name: 'Host Details by process name', url_value: - "siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Host Details by user name', url_value: - "siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Hosts Overview by process name', url_value: - "siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts?kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Hosts Overview by user name', url_value: - "siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts?kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, ], }, @@ -221,22 +221,22 @@ export const mockGetModuleResponse: Module[] = [ { url_name: 'Host Details by process name', url_value: - "siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Host Details by user name', url_value: - "siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Hosts Overview by process name', url_value: - "siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts?kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Hosts Overview by user name', url_value: - "siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts?kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, ], }, @@ -268,22 +268,22 @@ export const mockGetModuleResponse: Module[] = [ { url_name: 'Host Details by process name', url_value: - "siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Host Details by user name', url_value: - "siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Hosts Overview by process name', url_value: - "siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts?kqlQuery=(filterQuery:(expression:'process.name%20:%20%22$process.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, { url_name: 'Hosts Overview by user name', url_value: - "siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", + "siem#/ml-hosts?kqlQuery=(filterQuery:(expression:'user.name%20:%20%22$user.name$%22',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))", }, ], }, @@ -360,7 +360,7 @@ export const mockSetupMlJobAllError: SetupMlResponse = { path: '/_ml/anomaly_detectors/linux_anomalous_network_url_activity_ecs', query: {}, body: - '{"job_type":"anomaly_detector","groups":["siem","auditbeat","process"],"description":"SIEM Auditbeat: Looks for an unusual web URL request from a Linux instance. Curl and wget web request activity is very common but unusual web requests from a Linux server can sometimes be malware delivery or execution (beta)","analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare by \\"process.title\\"","function":"rare","by_field_name":"process.title"}],"influencers":["host.name","destination.ip","destination.port"]},"analysis_limits":{"model_memory_limit":"32mb"},"data_description":{"time_field":"@timestamp"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details","url_value":"siem#/ml-hosts/$host.name$?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]},"results_index_name":"linux_anomalous_network_url_activity_ecs"}', + '{"job_type":"anomaly_detector","groups":["siem","auditbeat","process"],"description":"SIEM Auditbeat: Looks for an unusual web URL request from a Linux instance. Curl and wget web request activity is very common but unusual web requests from a Linux server can sometimes be malware delivery or execution (beta)","analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare by \\"process.title\\"","function":"rare","by_field_name":"process.title"}],"influencers":["host.name","destination.ip","destination.port"]},"analysis_limits":{"model_memory_limit":"32mb"},"data_description":{"time_field":"@timestamp"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details","url_value":"siem#/ml-hosts/$host.name$?timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]},"results_index_name":"linux_anomalous_network_url_activity_ecs"}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"resource_already_exists_exception","reason":"The job cannot be created with the Id \'linux_anomalous_network_url_activity_ecs\'. The Id is already used."}],"type":"resource_already_exists_exception","reason":"The job cannot be created with the Id \'linux_anomalous_network_url_activity_ecs\'. The Id is already used."},"status":400}', @@ -375,7 +375,7 @@ export const mockSetupMlJobAllError: SetupMlResponse = { path: '/_ml/anomaly_detectors/linux_anomalous_network_port_activity_ecs', query: {}, body: - '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Looks for unusual destination port activity that could indicate command-and-control, persistence mechanism, or data exfiltration activity (beta)","groups":["siem","auditbeat","process"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare by \\"destination.port\\"","function":"rare","by_field_name":"destination.port"}],"influencers":["host.name","process.name","user.name","destination.ip"]},"analysis_limits":{"model_memory_limit":"32mb"},"data_description":{"time_field":"@timestamp"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]},"results_index_name":"linux_anomalous_network_port_activity_ecs"}', + '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Looks for unusual destination port activity that could indicate command-and-control, persistence mechanism, or data exfiltration activity (beta)","groups":["siem","auditbeat","process"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare by \\"destination.port\\"","function":"rare","by_field_name":"destination.port"}],"influencers":["host.name","process.name","user.name","destination.ip"]},"analysis_limits":{"model_memory_limit":"32mb"},"data_description":{"time_field":"@timestamp"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]},"results_index_name":"linux_anomalous_network_port_activity_ecs"}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"resource_already_exists_exception","reason":"The job cannot be created with the Id \'linux_anomalous_network_port_activity_ecs\'. The Id is already used."}],"type":"resource_already_exists_exception","reason":"The job cannot be created with the Id \'linux_anomalous_network_port_activity_ecs\'. The Id is already used."},"status":400}', @@ -430,7 +430,7 @@ export const mockSetupMlJobSingleErrorSingleSuccess: SetupMlResponse = { path: '/_ml/anomaly_detectors/linux_anomalous_network_activity_ecs', query: {}, body: - '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Looks for unusual processes using the network which could indicate command-and-control, lateral movement, persistence, or data exfiltration activity (beta)","groups":["siem","auditbeat","network"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare by \\"process.name\\"","function":"rare","by_field_name":"process.name"}],"influencers":["host.name","process.name","user.name","destination.ip"]},"analysis_limits":{"model_memory_limit":"64mb"},"data_description":{"time_field":"@timestamp"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?_g=()&kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?_g=()&kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]},"results_index_name":"linux_anomalous_network_activity_ecs"}', + '{"job_type":"anomaly_detector","description":"SIEM Auditbeat: Looks for unusual processes using the network which could indicate command-and-control, lateral movement, persistence, or data exfiltration activity (beta)","groups":["siem","auditbeat","network"],"analysis_config":{"bucket_span":"15m","detectors":[{"detector_description":"rare by \\"process.name\\"","function":"rare","by_field_name":"process.name"}],"influencers":["host.name","process.name","user.name","destination.ip"]},"analysis_limits":{"model_memory_limit":"64mb"},"data_description":{"time_field":"@timestamp"},"custom_settings":{"created_by":"ml-module-siem-auditbeat","custom_urls":[{"url_name":"Host Details by process name","url_value":"siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Host Details by user name","url_value":"siem#/ml-hosts/$host.name$?kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.details,type:details)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by process name","url_value":"siem#/ml-hosts?kqlQuery=(filterQuery:(expression:\'process.name%20:%20%22$process.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"},{"url_name":"Hosts Overview by user name","url_value":"siem#/ml-hosts?kqlQuery=(filterQuery:(expression:\'user.name%20:%20%22$user.name$%22\',kind:kuery),queryLocation:hosts.page,type:page)&timerange=(global:(linkTo:!(timeline),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')),timeline:(linkTo:!(global),timerange:(from:\'$earliest$\',kind:absolute,to:\'$latest$\')))"}]},"results_index_name":"linux_anomalous_network_activity_ecs"}', statusCode: 400, response: '{"error":{"root_cause":[{"type":"resource_already_exists_exception","reason":"The job cannot be created with the Id \'linux_anomalous_network_activity_ecs\'. The Id is already used."}],"type":"resource_already_exists_exception","reason":"The job cannot be created with the Id \'linux_anomalous_network_activity_ecs\'. The Id is already used."},"status":400}', diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx index 5697a8c3a0e596..63412302fedfb4 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.test.tsx @@ -146,8 +146,8 @@ describe('UrlStateContainer', () => { hash: '', pathname: examplePath, search: [CONSTANTS.overviewPage, CONSTANTS.timelinePage].includes(page) - ? '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))' - : `?_g=()&query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))`, + ? '?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))' + : `?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))`, state: '', }); } diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx index d20a4257a44726..705b2106be3157 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index_mocked.test.tsx @@ -76,7 +76,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => hash: '', pathname: '/network', search: - "?_g=()&query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)),timeline:(linkTo:!(global),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)))", + "?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)),timeline:(linkTo:!(global),timerange:(from:0,fromStr:now-24h,kind:relative,to:1,toStr:now)))", state: '', }); }); @@ -107,7 +107,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => hash: '', pathname: '/network', search: - "?_g=()&query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))", + "?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))", state: '', }); }); @@ -140,7 +140,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => hash: '', pathname: '/network', search: - '?_g=()&timeline=(id:hello_timeline_id,isOpen:!t)&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))', + '?timeline=(id:hello_timeline_id,isOpen:!t)&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))', state: '', }); }); @@ -159,7 +159,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => expect(mockHistory.replace.mock.calls[0][0]).toEqual({ hash: '', pathname: examplePath, - search: '?_g=()', + search: '?', state: '', }); @@ -169,7 +169,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => hash: '', pathname: examplePath, search: - '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))', + '?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))', state: '', }); } @@ -197,7 +197,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => expect( mockHistory.replace.mock.calls[mockHistory.replace.mock.calls.length - 1][0].search ).toEqual( - '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))' + '?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))' ); wrapper.setProps({ hookProps: updatedProps }); @@ -206,7 +206,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () => expect( mockHistory.replace.mock.calls[mockHistory.replace.mock.calls.length - 1][0].search ).toEqual( - "?_g=()&query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))" + "?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))" ); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts b/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts index d58295de5ce9d9..4dd92ac58b0a34 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts +++ b/x-pack/legacy/plugins/siem/public/components/url_state/test_dependencies.ts @@ -171,7 +171,7 @@ export const getMockPropsObj = ({ { hash: '', pathname: examplePath, - search: '?_g=()', + search: '?', state: '', }, page, @@ -183,7 +183,7 @@ export const getMockPropsObj = ({ { hash: '', pathname: examplePath, - search: '?_g=()', + search: '?', state: '', }, page, @@ -197,7 +197,7 @@ export const getMockPropsObj = ({ { hash: '', pathname: examplePath, - search: `?_g=()&query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(),timerange:(from:1558591200000,fromStr:now-1d%2Fd,kind:relative,to:1558677599999,toStr:now-1d%2Fd)),timeline:(linkTo:!(),timerange:(from:1558732849370,fromStr:now-15m,kind:relative,to:1558733749370,toStr:now)))`, + search: `?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(),timerange:(from:1558591200000,fromStr:now-1d%2Fd,kind:relative,to:1558677599999,toStr:now-1d%2Fd)),timeline:(linkTo:!(),timerange:(from:1558732849370,fromStr:now-15m,kind:relative,to:1558733749370,toStr:now)))`, state: '', }, page, @@ -209,7 +209,7 @@ export const getMockPropsObj = ({ { hash: '', pathname: examplePath, - search: `?_g=()&query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(),timerange:(from:1558591200000,fromStr:now-1d%2Fd,kind:relative,to:1558677599999,toStr:now-1d%2Fd)),timeline:(linkTo:!(),timerange:(from:1558732849370,fromStr:now-15m,kind:relative,to:1558733749370,toStr:now)))`, + search: `?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(),timerange:(from:1558591200000,fromStr:now-1d%2Fd,kind:relative,to:1558677599999,toStr:now-1d%2Fd)),timeline:(linkTo:!(),timerange:(from:1558732849370,fromStr:now-15m,kind:relative,to:1558733749370,toStr:now)))`, state: '', }, page, @@ -224,7 +224,7 @@ export const getMockPropsObj = ({ hash: '', pathname: examplePath, search: - '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1556736012685,kind:absolute,to:1556822416082)),timeline:(linkTo:!(global),timerange:(from:1556736012685,kind:absolute,to:1556822416082)))', + '?timerange=(global:(linkTo:!(timeline),timerange:(from:1556736012685,kind:absolute,to:1556822416082)),timeline:(linkTo:!(global),timerange:(from:1556736012685,kind:absolute,to:1556822416082)))', state: '', }, page, @@ -237,7 +237,7 @@ export const getMockPropsObj = ({ hash: '', pathname: examplePath, search: - '?_g=()&timerange=(global:(linkTo:!(timeline),timerange:(from:1556736012685,kind:absolute,to:1556822416082)),timeline:(linkTo:!(global),timerange:(from:1556736012685,kind:absolute,to:1556822416082)))', + '?timerange=(global:(linkTo:!(timeline),timerange:(from:1556736012685,kind:absolute,to:1556822416082)),timeline:(linkTo:!(global),timerange:(from:1556736012685,kind:absolute,to:1556822416082)))', state: '', }, page, @@ -251,7 +251,7 @@ export const getMockPropsObj = ({ { hash: '', pathname: examplePath, - search: `?_g=()&query=(query:'host.name:%22siem-es%22',language:kuery)&timerange=(global:(linkTo:!(),timerange:(from:1558591200000,fromStr:now-1d%2Fd,kind:relative,to:1558677599999,toStr:now-1d%2Fd)),timeline:(linkTo:!(),timerange:(from:1558732849370,fromStr:now-15m,kind:relative,to:1558733749370,toStr:now)))`, + search: `?query=(query:'host.name:%22siem-es%22',language:kuery)&timerange=(global:(linkTo:!(),timerange:(from:1558591200000,fromStr:now-1d%2Fd,kind:relative,to:1558677599999,toStr:now-1d%2Fd)),timeline:(linkTo:!(),timerange:(from:1558732849370,fromStr:now-15m,kind:relative,to:1558733749370,toStr:now)))`, state: '', }, page, From 022e6c4b9776081fd68ffcabfe883866cbd3a286 Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Tue, 17 Dec 2019 22:51:32 +0100 Subject: [PATCH 30/60] [SIEM] Fix eslint errors from jsx-no-bind #1 (#52856) --- .../flow_controls/flow_target_select.tsx | 39 +++--- .../siem/public/components/inspect/index.tsx | 131 +++++++++--------- .../components/matrix_histogram/index.tsx | 11 +- .../components/ml/score/draggable_score.tsx | 74 +++++----- .../jobs_table/filters/jobs_table_filters.tsx | 31 +++-- .../ml_popover/jobs_table/job_switch.tsx | 14 +- .../navigation/tab_navigation/index.test.tsx | 20 +-- .../navigation/tab_navigation/index.tsx | 93 +++++++++---- .../navigation/tab_navigation/types.ts | 9 ++ .../components/notes/add_note/index.tsx | 70 +++++----- .../hosts/authentications_table/index.tsx | 62 +++++---- .../page/hosts/host_overview/index.tsx | 10 +- .../page/hosts/hosts_table/index.tsx | 40 +++--- .../hosts/uncommon_process_table/index.tsx | 62 +++++---- .../page/network/ip_overview/index.tsx | 11 +- .../page/network/network_dns_table/index.tsx | 42 +++--- .../page/network/network_http_table/index.tsx | 77 +++++----- .../network_top_countries_table/index.tsx | 101 ++++++++------ .../network_top_n_flow_table/index.tsx | 77 +++++----- .../page/network/tls_table/index.tsx | 41 +++--- .../page/network/users_table/index.tsx | 40 +++--- .../page/overview/overview_host/index.tsx | 7 +- .../page/overview/overview_network/index.tsx | 7 +- .../__snapshots__/index.test.tsx.snap | 4 +- .../components/paginated_table/index.test.tsx | 54 ++++---- .../components/paginated_table/index.tsx | 8 +- .../public/components/stat_items/index.tsx | 7 +- .../rules/activity_monitor/index.tsx | 15 +- .../rules/all_rules/columns.tsx | 26 ++-- .../rules/components/rule_switch/index.tsx | 52 ++++--- .../plugins/siem/public/pages/home/index.tsx | 2 +- .../pages/hosts/details/details_tabs.test.tsx | 2 +- .../pages/hosts/details/details_tabs.tsx | 4 +- .../siem/public/pages/hosts/details/index.tsx | 14 +- .../plugins/siem/public/pages/hosts/hosts.tsx | 12 +- .../siem/public/pages/network/index.tsx | 18 ++- .../public/pages/network/ip_details/index.tsx | 13 +- .../network/navigation/network_routes.tsx | 4 +- .../siem/public/pages/network/network.tsx | 12 +- 39 files changed, 760 insertions(+), 556 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx b/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx index b1c463fdc32f40..f5dd4650159cd3 100644 --- a/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx +++ b/x-pack/legacy/plugins/siem/public/components/flow_controls/flow_target_select.tsx @@ -5,7 +5,7 @@ */ import { EuiSuperSelect } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback } from 'react'; import { ActionCreator } from 'typescript-fsa'; import { FlowDirection, FlowTarget } from '../../graphql/types'; @@ -65,22 +65,27 @@ export const FlowTargetSelect = React.memo( selectedTarget, displayTextOverride = [], updateFlowTargetAction, - }) => ( - - option.directions.includes(selectedDirection) - ) - : toggleTargetOptions(id, displayTextOverride) - } - valueOfSelected={selectedTarget} - onChange={(newFlowTarget: FlowTarget) => - onChangeTarget(newFlowTarget, updateFlowTargetAction) - } - isLoading={isLoading} - /> - ) + }) => { + const handleChange = useCallback( + (newFlowTarget: FlowTarget) => onChangeTarget(newFlowTarget, updateFlowTargetAction), + [updateFlowTargetAction] + ); + + return ( + + option.directions.includes(selectedDirection) + ) + : toggleTargetOptions(id, displayTextOverride) + } + valueOfSelected={selectedTarget} + onChange={handleChange} + isLoading={isLoading} + /> + ); + } ); FlowTargetSelect.displayName = 'FlowTargetSelect'; diff --git a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx index 6908aba542e4ca..04d6d94d6624d6 100644 --- a/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/inspect/index.tsx @@ -6,7 +6,7 @@ import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; import { getOr } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; import styled from 'styled-components'; @@ -72,72 +72,71 @@ const InspectButtonComponent = React.memo( setIsInspected, show, title = '', - }: InspectButtonProps) => ( - - {inputId === 'timeline' && !compact && ( - { - setIsInspected({ - id: queryId, - inputId, - isInspected: true, - selectedInspectIndex: inspectIndex, - }); - }} - > - {i18n.INSPECT} - - )} - {(inputId === 'global' || compact) && ( - { - setIsInspected({ - id: queryId, - inputId, - isInspected: true, - selectedInspectIndex: inspectIndex, - }); - }} - /> - )} - { - if (onCloseInspect != null) { - onCloseInspect(); + }: InspectButtonProps) => { + const handleClick = useCallback(() => { + setIsInspected({ + id: queryId, + inputId, + isInspected: true, + selectedInspectIndex: inspectIndex, + }); + }, [setIsInspected, queryId, inputId, inspectIndex]); + + const handleCloseModal = useCallback(() => { + if (onCloseInspect != null) { + onCloseInspect(); + } + setIsInspected({ + id: queryId, + inputId, + isInspected: false, + selectedInspectIndex: inspectIndex, + }); + }, [onCloseInspect, setIsInspected, queryId, inputId, inspectIndex]); + + return ( + + {inputId === 'timeline' && !compact && ( + + {i18n.INSPECT} + + )} + {(inputId === 'global' || compact) && ( + + )} + 0 ? inspect.dsl[inspectIndex] : null} + response={ + inspect != null && inspect.response.length > 0 ? inspect.response[inspectIndex] : null } - setIsInspected({ - id: queryId, - inputId, - isInspected: false, - selectedInspectIndex: inspectIndex, - }); - }} - isShowing={!loading && selectedInspectIndex === inspectIndex && isInspected} - request={inspect != null && inspect.dsl.length > 0 ? inspect.dsl[inspectIndex] : null} - response={ - inspect != null && inspect.response.length > 0 ? inspect.response[inspectIndex] : null - } - title={title} - data-test-subj="inspect-modal" - /> - - ) + title={title} + data-test-subj="inspect-modal" + /> + + ); + } ); InspectButtonComponent.displayName = 'InspectButtonComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx b/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx index f79c61a29c26b4..e1ccfd79a89a0b 100644 --- a/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { ScaleType } from '@elastic/charts'; import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; @@ -54,14 +54,17 @@ export const MatrixHistogram = ({ if (totalCount >= 0 && loadingInitial) { setLoadingInitial(false); } - }, [loading]); + }, [loading, loadingInitial, totalCount]); + + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); return ( setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} > ( - - snapshot.isDragging ? ( - - - - ) : ( - <> - {index !== 0 && ( - <> - {','} - - - )} - {getScoreString(score.severity)} - - ) - } - /> -); +}): JSX.Element => { + const scoreString = getScoreString(score.severity); + + return ( + + snapshot.isDragging ? ( + + + + ) : ( + <> + {index !== 0 && ( + <> + {','} + + + )} + {scoreString} + + ) + } + /> + ); +}; DraggableScoreComponent.displayName = 'DraggableScoreComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx index 74e61f27fb2d19..551ed5f08bd76e 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import React, { Dispatch, SetStateAction, useEffect, useState, useCallback } from 'react'; import { EuiFilterButton, @@ -40,7 +40,22 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab // Propagate filter changes to parent useEffect(() => { onFilterChanged({ filterQuery, showCustomJobs, showElasticJobs, selectedGroups }); - }, [filterQuery, selectedGroups.sort().join(), showCustomJobs, showElasticJobs]); + }, [filterQuery, selectedGroups, showCustomJobs, showElasticJobs, onFilterChanged]); + + const handleChange = useCallback( + (query: EuiSearchBarQuery) => setFilterQuery(query.queryText.trim()), + [setFilterQuery] + ); + + const handleElasticJobsClick = useCallback(() => { + setShowElasticJobs(!showElasticJobs); + setShowCustomJobs(false); + }, [setShowElasticJobs, showElasticJobs, setShowCustomJobs]); + + const handleCustomJobsClick = useCallback(() => { + setShowCustomJobs(!showCustomJobs); + setShowElasticJobs(false); + }, [setShowElasticJobs, showCustomJobs, setShowCustomJobs]); return ( @@ -51,7 +66,7 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab placeholder: i18n.FILTER_PLACEHOLDER, incremental: true, }} - onChange={(query: EuiSearchBarQuery) => setFilterQuery(query.queryText.trim())} + onChange={handleChange} />

sinT3o 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 diff --git a/docs/images/Expanded-Document.png b/docs/images/Expanded-Document.png index ad2f0db1a7ff907448795060d8506b35e4a01b29..4fa255e79a8add80dbf11898c7dac9490e4feb6f 100644 GIT binary patch literal 141385 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

@@ -65,10 +80,7 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab { - setShowElasticJobs(!showElasticJobs); - setShowCustomJobs(false); - }} + onClick={handleElasticJobsClick} data-test-subj="show-elastic-jobs-filter-button" withNext > @@ -76,10 +88,7 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab { - setShowCustomJobs(!showCustomJobs); - setShowElasticJobs(false); - }} + onClick={handleCustomJobsClick} data-test-subj="show-custom-jobs-filter-button" > {i18n.SHOW_CUSTOM_JOBS} diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx index c915bf04126ec4..0d503e2db3d9d1 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/jobs_table/job_switch.tsx @@ -5,7 +5,7 @@ */ import styled from 'styled-components'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSwitch } from '@elastic/eui'; import { SiemJob } from '../types'; @@ -47,6 +47,13 @@ export const JobSwitchComponent = ({ onJobStateChange, }: JobSwitchProps) => { const [isLoading, setIsLoading] = useState(false); + const handleChange = useCallback( + e => { + setIsLoading(true); + onJobStateChange(job, job.latestTimestampMs || 0, e.target.checked); + }, + [job, setIsLoading, onJobStateChange] + ); return ( @@ -58,10 +65,7 @@ export const JobSwitchComponent = ({ data-test-subj="job-switch" disabled={isFailure(job.jobState, job.datafeedState)} checked={isChecked(job.jobState, job.datafeedState)} - onChange={e => { - setIsLoading(true); - onJobStateChange(job, job.latestTimestampMs || 0, e.target.checked); - }} + onChange={handleChange} showLabel={false} label="" /> diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.test.tsx index 00b1d4c066d4a2..840e2bf3f42dcd 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.test.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount, shallow } from 'enzyme'; +import { mount } from 'enzyme'; import * as React from 'react'; import { navTabs } from '../../../pages/home/home_navigations'; @@ -62,13 +62,13 @@ describe('Tab Navigation', () => { }, }; test('it mounts with correct tab highlighted', () => { - const wrapper = shallow(); - const hostsTab = wrapper.find('[data-test-subj="navigation-hosts"]'); + const wrapper = mount(); + const hostsTab = wrapper.find('EuiTab[data-test-subj="navigation-hosts"]'); expect(hostsTab.prop('isSelected')).toBeTruthy(); }); test('it changes active tab when nav changes by props', () => { const wrapper = mount(); - const networkTab = () => wrapper.find('[data-test-subj="navigation-network"]').first(); + const networkTab = () => wrapper.find('EuiTab[data-test-subj="navigation-network"]').first(); expect(networkTab().prop('isSelected')).toBeFalsy(); wrapper.setProps({ pageName: 'network', @@ -79,8 +79,8 @@ describe('Tab Navigation', () => { expect(networkTab().prop('isSelected')).toBeTruthy(); }); test('it carries the url state in the link', () => { - const wrapper = shallow(); - const firstTab = wrapper.find('[data-test-subj="navigation-network"]'); + const wrapper = mount(); + const firstTab = wrapper.find('EuiTab[data-test-subj="navigation-network"]'); expect(firstTab.props().href).toBe( "#/link-to/network?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))" ); @@ -126,9 +126,9 @@ describe('Tab Navigation', () => { }, }; test('it mounts with correct tab highlighted', () => { - const wrapper = shallow(); + const wrapper = mount(); const tableNavigationTab = wrapper.find( - `[data-test-subj="navigation-${HostsTableType.authentications}"]` + `EuiTab[data-test-subj="navigation-${HostsTableType.authentications}"]` ); expect(tableNavigationTab.prop('isSelected')).toBeTruthy(); @@ -147,9 +147,9 @@ describe('Tab Navigation', () => { expect(tableNavigationTab().prop('isSelected')).toBeTruthy(); }); test('it carries the url state in the link', () => { - const wrapper = shallow(); + const wrapper = mount(); const firstTab = wrapper.find( - `[data-test-subj="navigation-${HostsTableType.authentications}"]` + `EuiTab[data-test-subj="navigation-${HostsTableType.authentications}"]` ); expect(firstTab.props().href).toBe( `#/${pageName}/${hostName}/${HostsTableType.authentications}?query=(language:kuery,query:'host.name:%22siem-es%22')&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))` diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx index d405ec404b1112..b653624ec1f67f 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/index.tsx @@ -5,23 +5,52 @@ */ import { EuiTab, EuiTabs } from '@elastic/eui'; import { getOr } from 'lodash/fp'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useCallback, useMemo } from 'react'; import { trackUiAction as track, METRIC_TYPE, TELEMETRY_EVENT } from '../../../lib/track_usage'; import { getSearch } from '../helpers'; -import { TabNavigationProps } from './types'; +import { TabNavigationProps, TabNavigationItemProps } from './types'; + +const TabNavigationItemComponent = ({ + href, + hrefWithSearch, + id, + disabled, + name, + isSelected, +}: TabNavigationItemProps) => { + const handleClick = useCallback(() => { + track(METRIC_TYPE.CLICK, `${TELEMETRY_EVENT.TAB_CLICKED}${id}`); + }, [id]); + + return ( + + {name} + + ); +}; + +const TabNavigationItem = React.memo(TabNavigationItemComponent); export const TabNavigationComponent = (props: TabNavigationProps) => { const { display, navTabs, pageName, tabName } = props; - const mapLocationToTab = (): string => { - return getOr( - '', - 'id', - Object.values(navTabs).find(item => tabName === item.id || pageName === item.id) - ); - }; - + const mapLocationToTab = useCallback( + (): string => + getOr( + '', + 'id', + Object.values(navTabs).find(item => tabName === item.id || pageName === item.id) + ), + [pageName, tabName, navTabs] + ); const [selectedTabId, setSelectedTabId] = useState(mapLocationToTab()); useEffect(() => { const currentTabSelected = mapLocationToTab(); @@ -31,26 +60,30 @@ export const TabNavigationComponent = (props: TabNavigationProps) => { } // we do need navTabs in case the selectedTabId appears after initial load (ex. checking permissions for anomalies) - }, [pageName, tabName, navTabs]); - - const renderTabs = (): JSX.Element[] => - Object.values(navTabs).map(tab => ( - { - track(METRIC_TYPE.CLICK, `${TELEMETRY_EVENT.TAB_CLICKED}${tab.id}`); - }} - > - {tab.name} - - )); - - return {renderTabs()}; + }, [pageName, tabName, navTabs, mapLocationToTab, selectedTabId]); + + const renderTabs = useMemo( + () => + Object.values(navTabs).map(tab => { + const isSelected = selectedTabId === tab.id; + const hrefWithSearch = tab.href + getSearch(tab, props); + + return ( + + ); + }), + [navTabs, selectedTabId, props] + ); + + return {renderTabs}; }; TabNavigationComponent.displayName = 'TabNavigationComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts index 1283691e658065..3fac783b550479 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/tab_navigation/types.ts @@ -22,3 +22,12 @@ export interface TabNavigationProps extends SiemNavigationProps { [CONSTANTS.timerange]: UrlInputsModel; [CONSTANTS.timeline]: Timeline; } + +export interface TabNavigationItemProps { + href: string; + hrefWithSearch: string; + id: string; + disabled: boolean; + name: string; + isSelected: boolean; +} diff --git a/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx b/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx index 6e13538cf9beab..28cab2b46755f8 100644 --- a/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/notes/add_note/index.tsx @@ -5,7 +5,7 @@ */ import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import * as React from 'react'; +import React, { useCallback } from 'react'; import styled from 'styled-components'; import { MarkdownHint } from '../../markdown/markdown_hint'; @@ -49,38 +49,44 @@ export const AddNote = React.memo<{ onCancelAddNote?: () => void; updateNewNote: UpdateInternalNewNote; updateNote: UpdateNote; -}>(({ associateNote, getNewNoteId, newNote, onCancelAddNote, updateNewNote, updateNote }) => ( - - - - 0} /> - - - {onCancelAddNote != null ? ( +}>(({ associateNote, getNewNoteId, newNote, onCancelAddNote, updateNewNote, updateNote }) => { + const handleClick = useCallback( + () => + updateAndAssociateNode({ + associateNote, + getNewNoteId, + newNote, + updateNewNote, + updateNote, + }), + [associateNote, getNewNoteId, newNote, updateNewNote, updateNote] + ); + + return ( + + + + 0} /> + + + {onCancelAddNote != null ? ( + + + + ) : null} - + + {i18n.ADD_NOTE} + - ) : null} - - - updateAndAssociateNode({ - associateNote, - getNewNoteId, - newNote, - updateNewNote, - updateNote, - }) - } - > - {i18n.ADD_NOTE} - - - - -)); + + + ); +}); AddNote.displayName = 'AddNote'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx index 7efcde5b89c675..ad5755068e6625 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/authentications_table/index.tsx @@ -5,7 +5,7 @@ */ import { has } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; @@ -98,39 +98,49 @@ const AuthenticationTableComponent = React.memo( type, updateTableActivePage, updateTableLimit, - }) => ( - loadPage(newActivePage)} - pageOfItems={data} - showMorePagesIndicator={showMorePagesIndicator} - totalCount={fakeTotalCount} - updateLimitPagination={newLimit => + }) => { + const updateLimitPagination = useCallback( + newLimit => updateTableLimit({ hostsType: type, limit: newLimit, tableType, - }) - } - updateActivePage={newPage => + }), + [type, updateTableLimit] + ); + + const updateActivePage = useCallback( + newPage => updateTableActivePage({ activePage: newPage, hostsType: type, tableType, - }) - } - /> - ) + }), + [type, updateTableActivePage] + ); + + return ( + + ); + } ); AuthenticationTableComponent.displayName = 'AuthenticationTableComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx index ba953d8e74b29d..437d14edeb5c8d 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/host_overview/index.tsx @@ -8,7 +8,7 @@ import { EuiFlexItem } from '@elastic/eui'; import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; import { getOr } from 'lodash/fp'; -import React, { useContext, useState } from 'react'; +import React, { useContext, useState, useCallback } from 'react'; import { DEFAULT_DARK_MODE } from '../../../../../common/constants'; import { DescriptionList } from '../../../../../common/utility_types'; @@ -165,11 +165,11 @@ export const HostOverview = React.memo( ], ]; + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); + return ( - setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} - > + ( updateTableActivePage, updateTableLimit, }) => { + const updateLimitPagination = useCallback( + newLimit => + updateTableLimit({ + hostsType: type, + limit: newLimit, + tableType, + }), + [type, updateTableLimit] + ); + + const updateActivePage = useCallback( + newPage => + updateTableActivePage({ + activePage: newPage, + hostsType: type, + tableType, + }), + [type, updateTableActivePage] + ); + const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null) { @@ -130,7 +150,7 @@ const HostsTableComponent = React.memo( } } }, - [direction, sortField, type] + [direction, sortField, type, updateHostsSort] ); const hostsColumns = useMemo(() => getHostsColumns(), []); @@ -153,26 +173,14 @@ const HostsTableComponent = React.memo( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} sorting={sorting} totalCount={fakeTotalCount} - updateLimitPagination={newLimit => - updateTableLimit({ - hostsType: type, - limit: newLimit, - tableType, - }) - } - updateActivePage={newPage => - updateTableActivePage({ - activePage: newPage, - hostsType: type, - tableType, - }) - } + updateLimitPagination={updateLimitPagination} + updateActivePage={updateActivePage} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx index a4fd4d636b35e9..a8b9b2a1f61cea 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/uncommon_process_table/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; @@ -96,39 +96,49 @@ const UncommonProcessTableComponent = React.memo( updateTableActivePage, updateTableLimit, type, - }) => ( - loadPage(newActivePage)} - pageOfItems={data} - showMorePagesIndicator={showMorePagesIndicator} - totalCount={fakeTotalCount} - updateLimitPagination={newLimit => + }) => { + const updateLimitPagination = useCallback( + newLimit => updateTableLimit({ hostsType: type, limit: newLimit, tableType, - }) - } - updateActivePage={newPage => + }), + [type, updateTableLimit] + ); + + const updateActivePage = useCallback( + newPage => updateTableActivePage({ activePage: newPage, hostsType: type, tableType, - }) - } - /> - ) + }), + [type, updateTableActivePage] + ); + + return ( + + ); + } ); UncommonProcessTableComponent.displayName = 'UncommonProcessTableComponent'; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx index 70b4d033624389..8cb55f0d0fb589 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/ip_overview/index.tsx @@ -7,7 +7,7 @@ import { EuiFlexItem } from '@elastic/eui'; import darkTheme from '@elastic/eui/dist/eui_theme_dark.json'; import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; -import React, { useContext, useState } from 'react'; +import React, { useContext, useState, useCallback } from 'react'; import { DEFAULT_DARK_MODE } from '../../../../../common/constants'; import { DescriptionList } from '../../../../../common/utility_types'; @@ -139,11 +139,12 @@ export const IpOverview = React.memo( { title: i18n.REPUTATION, description: reputationRenderer(ip) }, ], ]; + + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); + return ( - setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} - > + ( type, updateNetworkTable, }) => { + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type, updateNetworkTable] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type, updateNetworkTable] + ); + const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null) { @@ -93,7 +113,7 @@ export const NetworkDnsTableComponent = React.memo( } } }, - [sort, type] + [sort, type, updateNetworkTable] ); const onChangePtrIncluded = useCallback( @@ -103,7 +123,7 @@ export const NetworkDnsTableComponent = React.memo( tableType, updates: { isPtrIncluded: !isPtrIncluded }, }), - [type, isPtrIncluded] + [type, updateNetworkTable, isPtrIncluded] ); return ( @@ -123,7 +143,7 @@ export const NetworkDnsTableComponent = React.memo( isInspect={isInspect} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} @@ -132,20 +152,8 @@ export const NetworkDnsTableComponent = React.memo( direction: sort.direction, }} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx index e5ad39b814caac..d25d94a06b8181 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_http_table/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; @@ -76,23 +76,50 @@ const NetworkHttpTableComponent = React.memo( type, updateNetworkTable, }) => { - const onChange = (criteria: Criteria, tableType: networkModel.HttpTableType) => { - if (criteria.sort != null && criteria.sort.direction !== sort.direction) { - updateNetworkTable({ - networkType: type, - tableType, - updates: { - sort: { - direction: criteria.sort.direction, - }, - }, - }); - } - }; const tableType = type === networkModel.NetworkType.page ? networkModel.NetworkTableType.http : networkModel.IpDetailsTableType.http; + + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type, updateNetworkTable, tableType] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type, updateNetworkTable, tableType] + ); + + const onChange = useCallback( + (criteria: Criteria) => { + if (criteria.sort != null && criteria.sort.direction !== sort.direction) { + updateNetworkTable({ + networkType: type, + tableType, + updates: { + sort: { + direction: criteria.sort.direction, + }, + }, + }); + } + }, + [tableType, sort.direction, type, updateNetworkTable] + ); + + const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }; + return ( ( isInspect={isInspect} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} - onChange={criteria => onChange(criteria, tableType)} + loadPage={loadPage} + onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} - sorting={{ field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }} + sorting={sorting} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx index 81a48ca162e156..8fd5cc9b3f3c08 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx @@ -5,7 +5,7 @@ */ import { isEqual, last } from 'lodash/fp'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; @@ -88,27 +88,6 @@ const NetworkTopCountriesTableComponent = React.memo { - const onChange = (criteria: Criteria, tableType: networkModel.TopCountriesTableType) => { - if (criteria.sort != null) { - const splitField = criteria.sort.field.split('.'); - const field = last(splitField); - const newSortDirection = field !== sort.field ? Direction.desc : criteria.sort.direction; // sort by desc on init click - const newTopCountriesSort: NetworkTopTablesSortField = { - field: field as NetworkTopTablesFields, - direction: newSortDirection, - }; - if (!isEqual(newTopCountriesSort, sort)) { - updateNetworkTable({ - networkType: type, - tableType, - updates: { - sort: newTopCountriesSort, - }, - }); - } - } - }; - let tableType: networkModel.TopCountriesTableType; const headerTitle: string = flowTargeted === FlowTargetSourceDest.source @@ -133,15 +112,61 @@ const NetworkTopCountriesTableComponent = React.memo + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type, updateNetworkTable, tableType] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type, updateNetworkTable, tableType] + ); + + const onChange = useCallback( + (criteria: Criteria) => { + if (criteria.sort != null) { + const splitField = criteria.sort.field.split('.'); + const lastField = last(splitField); + const newSortDirection = + lastField !== sort.field ? Direction.desc : criteria.sort.direction; // sort by desc on init click + const newTopCountriesSort: NetworkTopTablesSortField = { + field: lastField as NetworkTopTablesFields, + direction: newSortDirection, + }; + if (!isEqual(newTopCountriesSort, sort)) { + updateNetworkTable({ + networkType: type, + tableType, + updates: { + sort: newTopCountriesSort, + }, + }); + } + } + }, + [type, sort, tableType, updateNetworkTable] + ); + + const columns = useMemo( + () => + getCountriesColumnsCurated(indexPattern, flowTargeted, type, NetworkTopCountriesTableId), + [indexPattern, flowTargeted, type] + ); + return ( loadPage(newActivePage)} - onChange={criteria => onChange(criteria, tableType)} + loadPage={loadPage} + onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} sorting={{ field, direction: sort.direction }} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx index 12b87a517b4f77..c38d8094581633 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { isEqual, last } from 'lodash/fp'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { ActionCreator } from 'typescript-fsa'; @@ -87,8 +87,29 @@ const NetworkTopNFlowTableComponent = React.memo( type, updateNetworkTable, }) => { + const columns = useMemo( + () => getNFlowColumnsCurated(indexPattern, flowTargeted, type, NetworkTopNFlowTableId), + [indexPattern, flowTargeted, type] + ); + + let tableType: networkModel.TopNTableType; + const headerTitle: string = + flowTargeted === FlowTargetSourceDest.source ? i18n.SOURCE_IP : i18n.DESTINATION_IP; + + if (type === networkModel.NetworkType.page) { + tableType = + flowTargeted === FlowTargetSourceDest.source + ? networkModel.NetworkTableType.topNFlowSource + : networkModel.NetworkTableType.topNFlowDestination; + } else { + tableType = + flowTargeted === FlowTargetSourceDest.source + ? networkModel.IpDetailsTableType.topNFlowSource + : networkModel.IpDetailsTableType.topNFlowDestination; + } + const onChange = useCallback( - (criteria: Criteria, tableType: networkModel.TopNTableType) => { + (criteria: Criteria) => { if (criteria.sort != null) { const splitField = criteria.sort.field.split('.'); const field = last(splitField); @@ -108,35 +129,35 @@ const NetworkTopNFlowTableComponent = React.memo( } } }, - [sort, type] + [sort, type, tableType, updateNetworkTable] ); - let tableType: networkModel.TopNTableType; - const headerTitle: string = - flowTargeted === FlowTargetSourceDest.source ? i18n.SOURCE_IP : i18n.DESTINATION_IP; - - if (type === networkModel.NetworkType.page) { - tableType = - flowTargeted === FlowTargetSourceDest.source - ? networkModel.NetworkTableType.topNFlowSource - : networkModel.NetworkTableType.topNFlowDestination; - } else { - tableType = - flowTargeted === FlowTargetSourceDest.source - ? networkModel.IpDetailsTableType.topNFlowSource - : networkModel.IpDetailsTableType.topNFlowDestination; - } - const field = sort.field === NetworkTopTablesFields.bytes_out || sort.field === NetworkTopTablesFields.bytes_in ? `node.network.${sort.field}` : `node.${flowTargeted}.${sort.field}`; + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [updateNetworkTable, type, tableType] + ); + + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ networkType: type, tableType, updates: { limit: newLimit } }), + [updateNetworkTable, type, tableType] + ); + return ( ( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} - onChange={criteria => onChange(criteria, tableType)} + loadPage={loadPage} + onChange={onChange} pageOfItems={data} showMorePagesIndicator={showMorePagesIndicator} sorting={{ field, direction: sort.direction }} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ networkType: type, tableType, updates: { limit: newLimit } }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx index 7dd9ca0273c5b8..026ab9537d3d74 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/tls_table/index.tsx @@ -79,6 +79,26 @@ const TlsTableComponent = React.memo( ? networkModel.NetworkTableType.tls : networkModel.IpDetailsTableType.tls; + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type, updateNetworkTable, tableType] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type, updateNetworkTable, tableType] + ); + const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null) { @@ -96,8 +116,9 @@ const TlsTableComponent = React.memo( } } }, - [sort, type] + [sort, type, tableType, updateNetworkTable] ); + return ( ( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} sorting={getSortField(sort)} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx index 8da41fca8f3841..14fbf4860f7c03 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/users_table/index.tsx @@ -78,6 +78,26 @@ const UsersTableComponent = React.memo( updateNetworkTable, sort, }) => { + const updateLimitPagination = useCallback( + newLimit => + updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }), + [type, updateNetworkTable] + ); + + const updateActivePage = useCallback( + newPage => + updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }), + [type, updateNetworkTable] + ); + const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null) { @@ -95,7 +115,7 @@ const UsersTableComponent = React.memo( } } }, - [sort, type] + [sort, type, updateNetworkTable] ); return ( @@ -112,25 +132,13 @@ const UsersTableComponent = React.memo( itemsPerRow={rowItems} limit={limit} loading={loading} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} onChange={onChange} pageOfItems={data} sorting={getSortField(sort)} totalCount={fakeTotalCount} - updateActivePage={newPage => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }) - } - updateLimitPagination={newLimit => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }) - } + updateActivePage={updateActivePage} + updateLimitPagination={updateLimitPagination} /> ); } diff --git a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx index 077a2d9aebe527..302917c3de93e3 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/overview/overview_host/index.tsx @@ -6,7 +6,7 @@ import { EuiButton, EuiFlexItem, EuiPanel } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { HeaderSection } from '../../../header_section'; import { manageQuery } from '../../../page/manage_query'; @@ -38,9 +38,12 @@ const OverviewHostStatsManage = manageQuery(OverviewHostStats); type OverviewHostProps = OwnProps; export const OverviewHost = React.memo(({ endDate, startDate, setQuery }) => { const [isHover, setIsHover] = useState(false); + const handleMouseEnter = useCallback(() => setIsHover(true), [setIsHover]); + const handleMouseLeave = useCallback(() => setIsHover(false), [setIsHover]); + return ( - setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + (({ endDate, startDate, setQuery }) => { const [isHover, setIsHover] = useState(false); + const handleMouseEnter = useCallback(() => setIsHover(true), [setIsHover]); + const handleMouseLeave = useCallback(() => setIsHover(false), [setIsHover]); + return ( - setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx index 91ae271d1ccac5..0444360d2b965a 100644 --- a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.test.tsx @@ -48,11 +48,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -75,11 +75,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={true} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={[]} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -104,11 +104,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={true} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -131,7 +131,7 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} @@ -168,11 +168,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -199,11 +199,11 @@ describe('Paginated Table Component', () => { itemsPerRow={[]} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -233,7 +233,7 @@ describe('Paginated Table Component', () => { showMorePagesIndicator={true} sorting={{ direction: Direction.asc, field: 'node.host.name' }} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -256,11 +256,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={DEFAULT_MAX_TABLE_QUERY_SIZE * 3} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -286,11 +286,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={30} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -312,11 +312,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={1} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -340,11 +340,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={1} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -370,11 +370,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -408,11 +408,11 @@ describe('Paginated Table Component', () => { itemsPerRow: rowItems, limit: 1, loading: false, - loadPage: newActivePage => loadPage(newActivePage), + loadPage, pageOfItems: mockData.Hosts.edges, showMorePagesIndicator: true, totalCount: 10, - updateActivePage: activePage => updateActivePage(activePage), + updateActivePage, updateLimitPagination: limit => updateLimitPagination({ limit }), }; @@ -460,11 +460,11 @@ describe('Paginated Table Component', () => { itemsPerRow={rowItems} limit={2} loading={false} - loadPage={newActivePage => loadPage(newActivePage)} + loadPage={loadPage} pageOfItems={mockData.Hosts.edges} showMorePagesIndicator={true} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> @@ -503,7 +503,7 @@ describe('Paginated Table Component', () => { showMorePagesIndicator={true} sorting={{ direction: Direction.asc, field: 'node.host.name' }} totalCount={10} - updateActivePage={activePage => updateActivePage(activePage)} + updateActivePage={updateActivePage} updateLimitPagination={limit => updateLimitPagination({ limit })} /> diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx index aedec1a340bfde..7a7a8ee5dfa7d2 100644 --- a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx @@ -16,7 +16,7 @@ import { EuiPopover, } from '@elastic/eui'; import { noop } from 'lodash/fp'; -import React, { memo, useState, useEffect } from 'react'; +import React, { memo, useState, useEffect, useCallback } from 'react'; import styled from 'styled-components'; import { Direction } from '../../graphql/types'; @@ -226,13 +226,15 @@ export const PaginatedTable = memo( )); const PaginationWrapper = showMorePagesIndicator ? PaginationEuiFlexItem : EuiFlexItem; + const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); + const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); return ( setShowInspect(true)} - onMouseLeave={() => setShowInspect(false)} + onMouseEnter={handleOnMouseEnter} + onMouseLeave={handleOnMouseLeave} > ( to, }) => { const [isHover, setIsHover] = useState(false); + const handleMouseEnter = useCallback(() => setIsHover(true), [setIsHover]); + const handleMouseLeave = useCallback(() => setIsHover(false), [setIsHover]); const isBarChartDataAvailable = barChart && barChart.length && @@ -218,9 +220,10 @@ export const StatItemsComponent = React.memo( areaChart && areaChart.length && areaChart.every(item => item.value != null && item.value.length > 0); + return ( - setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx index d7306b8630bc2d..2d48d64acaecf7 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/activity_monitor/index.tsx @@ -5,7 +5,7 @@ */ import { EuiBasicTable, EuiPanel, EuiSpacer } from '@elastic/eui'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import { HeaderSection } from '../../../../components/header_section'; import { UtilityBar, @@ -278,6 +278,14 @@ export const ActivityMonitor = React.memo(() => { // const [selectedState, setSelectedState] = useState([]); const [sortState, setSortState] = useState({ field: 'ran', direction: 'desc' }); + const handleChange = useCallback( + ({ page, sort }: { page: PageTypes; sort: SortTypes }) => { + setPageState(page); + setSortState(sort); + }, + [setPageState, setSortState] + ); + return ( <> @@ -308,10 +316,7 @@ export const ActivityMonitor = React.memo(() => { isSelectable itemId="id" items={sampleTableData} - onChange={({ page, sort }: { page: PageTypes; sort: SortTypes }) => { - setPageState(page); - setSortState(sort); - }} + onChange={handleChange} pagination={{ pageIndex: pageState.index, pageSize: pageState.size, diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx index cae0fb3eaf9065..9575ee736dea3b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all_rules/columns.tsx @@ -21,7 +21,7 @@ import { Action } from './reducer'; import { TableData } from '../types'; import * as i18n from '../translations'; import { PreferenceFormattedDate } from '../../../../components/formatted_date'; -import { RuleSwitch } from '../components/rule_switch'; +import { RuleSwitch, RuleStateChangeCallback } from '../components/rule_switch'; const getActions = (dispatch: React.Dispatch, kbnVersion: string) => [ { @@ -147,16 +147,20 @@ export const getColumns = (dispatch: React.Dispatch, kbnVersion: string) align: 'center', field: 'activate', name: i18n.COLUMN_ACTIVATE, - render: (value: TableData['activate'], item: TableData) => ( - { - await enableRulesAction([id], enabled, dispatch, kbnVersion); - }} - /> - ), + render: (value: TableData['activate'], item: TableData) => { + const handleRuleStateChange: RuleStateChangeCallback = async (enabled, id) => { + await enableRulesAction([id], enabled, dispatch, kbnVersion); + }; + + return ( + + ); + }, sortable: true, width: '85px', }, diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx index 19523752f4f4a9..6d9b0a36f8548b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx @@ -5,7 +5,7 @@ */ import styled from 'styled-components'; -import React from 'react'; +import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSwitch } from '@elastic/eui'; const StaticSwitch = styled(EuiSwitch)` @@ -17,11 +17,13 @@ const StaticSwitch = styled(EuiSwitch)` StaticSwitch.displayName = 'StaticSwitch'; +export type RuleStateChangeCallback = (isEnabled: boolean, id: string) => void; + export interface RuleSwitchProps { id: string; enabled: boolean; isLoading: boolean; - onRuleStateChange: (isEnabled: boolean, id: string) => void; + onRuleStateChange: RuleStateChangeCallback; } /** @@ -32,26 +34,32 @@ export const RuleSwitchComponent = ({ enabled, isLoading, onRuleStateChange, -}: RuleSwitchProps) => ( - - - {isLoading ? ( - - ) : ( - { - onRuleStateChange(e.target.checked!, id); - }} - /> - )} - - -); +}: RuleSwitchProps) => { + const handleChange = useCallback( + e => { + onRuleStateChange(e.target.checked!, id); + }, + [onRuleStateChange, id] + ); + return ( + + + {isLoading ? ( + + ) : ( + + )} + + + ); +}; export const RuleSwitch = React.memo(RuleSwitchComponent); diff --git a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx index 97f0a21928a8af..a545be447796dc 100644 --- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as React from 'react'; +import React from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; import styled from 'styled-components'; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx index febf9630e968a5..8d45bbbe34d33d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.test.tsx @@ -63,7 +63,7 @@ describe('body', () => { from={0} isInitializing={false} detailName={'host-1'} - setQuery={() => {}} + setQuery={jest.fn()} to={0} setAbsoluteRangeDatePicker={(jest.fn() as unknown) as SetAbsoluteRangeDatePicker} hostDetailsPagePath={hostDetailsPagePath} diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx index 1252c7031e8a5f..a09e21f2d1a352 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx @@ -45,14 +45,14 @@ const HostDetailsTabs = React.memo( to: fromTo.to, }); }, - [setAbsoluteRangeDatePicker, scoreIntervalToDateTime] + [setAbsoluteRangeDatePicker] ); const updateDateRange = useCallback( (min: number, max: number) => { setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); }, - [setAbsoluteRangeDatePicker, scoreIntervalToDateTime] + [setAbsoluteRangeDatePicker] ); const tabProps = { diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx index d30665c5a21426..d8bcc6fe3c294d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx @@ -5,7 +5,7 @@ */ import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; -import React, { useContext, useEffect } from 'react'; +import React, { useContext, useEffect, useCallback } from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; import { compose } from 'redux'; @@ -61,9 +61,15 @@ const HostDetailsComponent = React.memo( }) => { useEffect(() => { setHostDetailsTablesActivePageToZero(null); - }, [detailName]); + }, [setHostDetailsTablesActivePageToZero, detailName]); const capabilities = useContext(MlCapabilitiesContext); const core = useKibanaCore(); + const narrowDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); return ( <> @@ -176,9 +182,7 @@ const HostDetailsComponent = React.memo( refetch={refetch} setQuery={setQuery} to={to} - narrowDateRange={(min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }} + narrowDateRange={narrowDateRange} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx index 4ff666464404e2..0c058f25854c01 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -5,7 +5,7 @@ */ import { EuiSpacer } from '@elastic/eui'; -import * as React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; import { compose } from 'redux'; @@ -52,6 +52,12 @@ const HostsComponent = React.memo( }) => { const capabilities = React.useContext(MlCapabilitiesContext); const core = useKibanaCore(); + const narrowDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); return ( <> @@ -93,9 +99,7 @@ const HostsComponent = React.memo( refetch={refetch} setQuery={setQuery} to={to} - narrowDateRange={(min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }} + narrowDateRange={narrowDateRange} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/network/index.tsx b/x-pack/legacy/plugins/siem/public/pages/network/index.tsx index 009a89bb3889f6..1bc3d9a054bb89 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext } from 'react'; +import React, { useContext, useMemo } from 'react'; import { Redirect, Route, Switch, RouteComponentProps } from 'react-router-dom'; import { MlCapabilitiesContext } from '../../components/ml/permissions/ml_capabilities_provider'; @@ -24,6 +24,14 @@ const ipDetailsPagePath = `${networkPagePath}/ip/:detailName`; export const NetworkContainer = React.memo(() => { const capabilities = useContext(MlCapabilitiesContext); + const capabilitiesFetched = capabilities.capabilitiesFetched; + const userHasMlUserPermissions = useMemo(() => hasMlUserPermissions(capabilities), [ + capabilities, + ]); + const networkRoutePath = useMemo( + () => getNetworkRoutePath(networkPagePath, capabilitiesFetched, userHasMlUserPermissions), + [capabilitiesFetched, userHasMlUserPermissions] + ); return ( @@ -31,11 +39,7 @@ export const NetworkContainer = React.memo(() => { ( (() => { deleteQuery={deleteQuery} isInitializing={isInitializing} capabilitiesFetched={capabilities.capabilitiesFetched} - hasMlUserPermissions={hasMlUserPermissions(capabilities)} + hasMlUserPermissions={userHasMlUserPermissions} /> )} /> diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx index 75ca5a5dfe1a68..97db422b539e84 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/index.tsx @@ -68,13 +68,13 @@ export const IPDetailsComponent = ({ to: fromTo.to, }); }, - [scoreIntervalToDateTime, setAbsoluteRangeDatePicker] + [setAbsoluteRangeDatePicker] ); const core = useKibanaCore(); useEffect(() => { setIpDetailsTablesActivePageToZero(null); - }, [detailName]); + }, [detailName, setIpDetailsTablesActivePageToZero]); return ( <> @@ -134,14 +134,7 @@ export const IPDetailsComponent = ({ setQuery={setQuery} startDate={from} endDate={to} - narrowDateRange={(score, interval) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }} + narrowDateRange={narrowDateRange} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx index 681e1f8e1e34d7..d1c792ade09852 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx @@ -42,13 +42,13 @@ export const NetworkRoutes = ({ to: fromTo.to, }); }, - [scoreIntervalToDateTime, setAbsoluteRangeDatePicker] + [setAbsoluteRangeDatePicker] ); const updateDateRange = useCallback( (min: number, max: number) => { setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); }, - [from, to] + [setAbsoluteRangeDatePicker] ); const networkAnomaliesFilterQuery = { diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx index aa7572e5741bda..116664fef6ddcc 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx @@ -5,7 +5,7 @@ */ import { EuiSpacer } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; @@ -49,6 +49,12 @@ const NetworkComponent = React.memo( capabilitiesFetched, }) => { const core = useKibanaCore(); + const narrowDateRange = useCallback( + (min: number, max: number) => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, + [setAbsoluteRangeDatePicker] + ); return ( <> @@ -101,9 +107,7 @@ const NetworkComponent = React.memo( loading={loading} from={from} to={to} - narrowDateRange={(min: number, max: number) => { - setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); - }} + narrowDateRange={narrowDateRange} /> )} From 69570cde7e7489af39a5134a96a5b87ff3e09e1f Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 17 Dec 2019 15:48:19 -0700 Subject: [PATCH 31/60] [Metrics UI] Display data label on inventory based on data interval (#53054) --- .../infra/common/http_api/snapshot_api.ts | 1 + .../public/components/inventory/layout.tsx | 3 +- .../components/nodes_overview/index.tsx | 7 +- .../public/containers/waffle/use_snaphot.ts | 1 + .../utils/convert_interval_to_string.ts | 112 ++++++++++++++++++ .../infra/server/lib/snapshot/snapshot.ts | 7 +- .../infra/server/routes/snapshot/index.ts | 5 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 9 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/utils/convert_interval_to_string.ts diff --git a/x-pack/legacy/plugins/infra/common/http_api/snapshot_api.ts b/x-pack/legacy/plugins/infra/common/http_api/snapshot_api.ts index 3e6aec4bad9726..0b5b023f630236 100644 --- a/x-pack/legacy/plugins/infra/common/http_api/snapshot_api.ts +++ b/x-pack/legacy/plugins/infra/common/http_api/snapshot_api.ts @@ -34,6 +34,7 @@ export const SnapshotNodeRT = rt.type({ export const SnapshotNodeResponseRT = rt.type({ nodes: rt.array(SnapshotNodeRT), + interval: rt.string, }); export const InfraTimerangeInputRT = rt.type({ diff --git a/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx b/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx index d6827aa9c5d2dc..60f23854772624 100644 --- a/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx +++ b/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx @@ -37,7 +37,7 @@ export interface LayoutProps { export const Layout = (props: LayoutProps) => { const { accounts, regions } = useInventoryMeta(props.sourceId, props.nodeType); - const { loading, nodes, reload } = useSnapshot( + const { loading, nodes, reload, interval } = useSnapshot( props.filterQuery, props.metric, props.groupBy, @@ -62,6 +62,7 @@ export const Layout = (props: LayoutProps) => { view={props.view} autoBounds={props.autoBounds} boundsOverride={props.boundsOverride} + interval={interval} /> diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx index edf1b228b278a5..21db0c73f612ae 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx @@ -21,6 +21,7 @@ import { Map } from '../waffle/map'; import { ViewSwitcher } from '../waffle/view_switcher'; import { TableView } from './table'; import { SnapshotNode } from '../../../common/http_api/snapshot_api'; +import { convertIntervalToString } from '../../utils/convert_interval_to_string'; interface Props { options: InfraWaffleMapOptions; @@ -34,6 +35,7 @@ interface Props { view: string; boundsOverride: InfraWaffleMapBounds; autoBounds: boolean; + interval: string; } interface MetricFormatter { @@ -121,6 +123,7 @@ export const NodesOverview = class extends React.Component { view, currentTime, options, + interval, } = this.props; if (loading) { return ( @@ -153,6 +156,7 @@ export const NodesOverview = class extends React.Component { } const dataBounds = calculateBoundsFromNodes(nodes); const bounds = autoBounds ? dataBounds : boundsOverride; + const intervalAsString = convertIntervalToString(interval); return ( @@ -165,7 +169,8 @@ export const NodesOverview = class extends React.Component {

diff --git a/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts b/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts index 1a46c6269af1ec..1ff75120802747 100644 --- a/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts +++ b/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts @@ -65,6 +65,7 @@ export function useSnapshot( error: (error && error.message) || null, loading, nodes: response ? response.nodes : [], + interval: response ? response.interval : '60s', reload: makeRequest, }; } diff --git a/x-pack/legacy/plugins/infra/public/utils/convert_interval_to_string.ts b/x-pack/legacy/plugins/infra/public/utils/convert_interval_to_string.ts new file mode 100644 index 00000000000000..a125360235755a --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/utils/convert_interval_to_string.ts @@ -0,0 +1,112 @@ +/* + * 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 dateMath from '@elastic/datemath'; +import moment from 'moment'; +import { i18n } from '@kbn/i18n'; +import * as rt from 'io-ts'; + +export const INTERVAL_STRING_RE = new RegExp(`^([\\d\\.]+)\\s*(${dateMath.units.join('|')})$`); + +export const parseInterval = (intervalString: string) => { + if (intervalString) { + const matches = intervalString.match(INTERVAL_STRING_RE); + if (matches) { + const value = Number(matches[1]); + const unit = matches[2]; + return { value, unit }; + } + } + throw new Error( + i18n.translate('xpack.infra.parseInterval.errorMessage', { + defaultMessage: '{value} is not an interval string', + values: { + value: intervalString, + }, + }) + ); +}; + +const ValidUnitRT = rt.keyof({ + seconds: null, + minutes: null, + hours: null, + days: null, + weeks: null, + months: null, + years: null, +}); +type ValidUnit = rt.TypeOf; +const UNITS = ['seconds', 'minutes', 'hours', 'days', 'weeks', 'months', 'years'] as ValidUnit[]; + +const DISPLAY_STRINGS_FOR_UNITS_PLURAL = { + seconds: i18n.translate('xpack.infra.durationUnits.seconds.plural', { + defaultMessage: 'seconds', + }), + minutes: i18n.translate('xpack.infra.durationUnits.minutes.plural', { + defaultMessage: 'minutes', + }), + hours: i18n.translate('xpack.infra.durationUnits.hours.plural', { + defaultMessage: 'hours', + }), + days: i18n.translate('xpack.infra.durationUnits.days.plural', { + defaultMessage: 'days', + }), + weeks: i18n.translate('xpack.infra.durationUnits.weeks.plural', { + defaultMessage: 'weeks', + }), + months: i18n.translate('xpack.infra.durationUnits.months.plural', { + defaultMessage: 'months', + }), + years: i18n.translate('xpack.infra.durationUnits.years.plural', { + defaultMessage: 'years', + }), +}; + +const DISPLAY_STRINGS_FOR_UNITS_SINGULAR = { + seconds: i18n.translate('xpack.infra.durationUnits.seconds.singular', { + defaultMessage: 'second', + }), + minutes: i18n.translate('xpack.infra.durationUnits.minutes.singular', { + defaultMessage: 'minute', + }), + hours: i18n.translate('xpack.infra.durationUnits.hours.singular', { + defaultMessage: 'hour', + }), + days: i18n.translate('xpack.infra.durationUnits.days.singular', { + defaultMessage: 'day', + }), + weeks: i18n.translate('xpack.infra.durationUnits.weeks.singular', { + defaultMessage: 'week', + }), + months: i18n.translate('xpack.infra.durationUnits.months.singular', { + defaultMessage: 'month', + }), + years: i18n.translate('xpack.infra.durationUnits.years.singular', { + defaultMessage: 'year', + }), +}; + +const getDisplayableUnit = (value: number, unit: ValidUnit) => { + return Math.floor(value) === 1 + ? DISPLAY_STRINGS_FOR_UNITS_SINGULAR[unit] + : DISPLAY_STRINGS_FOR_UNITS_PLURAL[unit]; +}; + +export const convertIntervalToString = (input: string) => { + const interval = parseInterval(input); + if (interval?.unit === 's') { + const duration = moment.duration(interval.value, interval.unit); + const targetUnit = UNITS.reduce((answer, unit) => { + if (duration.as(unit) >= 1) { + return unit; + } + return answer; + }, 'seconds'); + const durationAsUnit = duration.as(targetUnit); + return `${Math.floor(durationAsUnit)} ${getDisplayableUnit(durationAsUnit, targetUnit)}`; + } +}; diff --git a/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts b/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts index d1db0ef07b3384..d5e10ecdce486e 100644 --- a/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts +++ b/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts @@ -37,7 +37,7 @@ export class InfraSnapshot { public async getNodes( requestContext: RequestHandlerContext, options: InfraSnapshotRequestOptions - ): Promise { + ): Promise<{ nodes: InfraSnapshotNode[]; interval: string }> { // Both requestGroupedNodes and requestNodeMetrics may send several requests to elasticsearch // in order to page through the results of their respective composite aggregations. // Both chains of requests are supposed to run in parallel, and their results be merged @@ -61,7 +61,10 @@ export class InfraSnapshot { const groupedNodeBuckets = await groupedNodesPromise; const nodeMetricBuckets = await nodeMetricsPromise; - return mergeNodeBuckets(groupedNodeBuckets, nodeMetricBuckets, options); + return { + nodes: mergeNodeBuckets(groupedNodeBuckets, nodeMetricBuckets, options), + interval: timeRangeWithIntervalApplied.interval, + }; } } diff --git a/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts b/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts index ae707bae79b9ea..dffeb04c92a8a1 100644 --- a/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts +++ b/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts @@ -47,10 +47,9 @@ export const initSnapshotRoute = (libs: InfraBackendLibs) => { metric: metric as InfraSnapshotMetricInput, timerange, }; + const nodesWithInterval = await libs.snapshot.getNodes(requestContext, options); return response.ok({ - body: SnapshotNodeResponseRT.encode({ - nodes: await libs.snapshot.getNodes(requestContext, options), - }), + body: SnapshotNodeResponseRT.encode(nodesWithInterval), }); } catch (error) { return response.internalError({ diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 413e0a9a4cc505..a3c2d21960c8e4 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5838,7 +5838,6 @@ "xpack.infra.homePage.noMetricsIndicesInstructionsActionLabel": "セットアップの手順を表示", "xpack.infra.homePage.noMetricsIndicesTitle": "メトリックインデックスがないようです。", "xpack.infra.homePage.toolbar.kqlSearchFieldPlaceholder": "インフラストラクチャーデータを検索… (例: host.name:host-1)", - "xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "指定期間の最後の 1 分間のデータを表示中", "xpack.infra.infrastructureDescription": "インフラストラクチャーを閲覧します", "xpack.infra.infrastructureMetricsExplorerPage.documentTitle": "{previousTitle} | メトリックエクスプローラー", "xpack.infra.infrastructureSnapshotPage.documentTitle": "{previousTitle} | インベントリ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0f6d03e7fb68d7..02e6022fff7861 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5840,7 +5840,6 @@ "xpack.infra.homePage.noMetricsIndicesInstructionsActionLabel": "查看设置说明", "xpack.infra.homePage.noMetricsIndicesTitle": "似乎您没有任何指标索引。", "xpack.infra.homePage.toolbar.kqlSearchFieldPlaceholder": "搜索基础设施数据……(例如 host.name:host-1)", - "xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "在选定时间显示过去 1 分钟的数据", "xpack.infra.infrastructureDescription": "浏览您的基础设施", "xpack.infra.infrastructureMetricsExplorerPage.documentTitle": "{previousTitle} | 指标浏览器", "xpack.infra.infrastructureSnapshotPage.documentTitle": "{previousTitle} | 库存", From e29a936daa450434232ba4134aa75612065fe6d0 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Tue, 17 Dec 2019 15:56:19 -0700 Subject: [PATCH 32/60] [SIEM][Detection Engine] Adds prepackaging rules capability ## Summary * Adds pre-packaging rules capability * Adds pre-packaged rules * Adds conversion script for saved searches to pre-package then edit workflow * Adds an auto-incrementing numbered versioning * Adds `immutability` as a filterable internal tag Screen Shot 2019-12-14 at 12 21 07 AM Screen Shot 2019-12-14 at 12 23 40 AM Usage/Testing: ```sh PUT /api/detection_engine/rules/prepackaged ``` script: ```sh ./scripts/add_prepackaged_rules.sh ``` When you create a new rule now (regardless of if it is immutable or not), you automatically get a version number returned back starting at the number 1. If you update the rule then it will automatically update the version number by incrementing it by 1 for convenience. However if you create a rule _and_ add in the version number during the creation of the rule then it will take that version number. If you update a rule you can optionally send in the version which will also update it there. ### Checklist Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. ~~- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~~ ~~- [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)~~ ~~- [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~~ - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios ~~- [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~~ ### For maintainers ~~- [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~ - [x] This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process) --- .../legacy/plugins/siem/common/constants.ts | 2 + .../scripts/convert_saved_search_to_rules.js | 134 +- .../plugins/siem/server/kibana.index.ts | 3 + .../routes/__mocks__/request_responses.ts | 66 +- .../rules/add_prepackaged_rules_route.ts | 76 ++ .../routes/rules/create_rules_route.ts | 1 + .../routes/rules/update_rules_route.ts | 2 + .../routes/rules/utils.test.ts | 10 + .../detection_engine/routes/rules/utils.ts | 1 + .../add_prepackaged_rules_schema.test.ts | 1101 +++++++++++++++++ .../schemas/add_prepackaged_rules_schema.ts | 75 ++ .../routes/schemas/create_rules_schema.ts | 2 + .../routes/schemas/schemas.ts | 2 + .../routes/schemas/update_rules_schema.ts | 2 + .../lib/detection_engine/routes/utils.test.ts | 12 + .../lib/detection_engine/routes/utils.ts | 4 + .../rules/add_rule_id_to_tags.test.ts | 35 - .../rules/add_rule_id_to_tags.ts | 15 - .../detection_engine/rules/add_tags.test.ts | 75 ++ .../lib/detection_engine/rules/add_tags.ts | 28 + .../detection_engine/rules/create_rules.ts | 6 +- .../get_existing_prepackaged_rules.test.ts | 114 ++ .../rules/get_existing_prepackaged_rules.ts | 60 + .../rules/get_prepackaged_rules.test.ts | 25 + .../rules/get_prepackaged_rules.ts | 38 + .../rules/get_rules_to_install.test.ts | 67 + .../rules/get_rules_to_install.ts | 17 + .../rules/get_rules_to_update.test.ts | 104 ++ .../rules/get_rules_to_update.ts | 21 + .../rules/install_prepacked_rules.ts | 75 ++ ...nd_shell_started_by_internet_explorer.json | 68 + .../command_shell_started_by_powershell.json | 68 + .../command_shell_started_by_svchost.json | 68 + .../rules/prepackaged_rules/index.ts | 294 +++++ .../linux_hping_activity.json | 68 + .../linux_iodine_activity.json | 68 + ...va_process_connecting_to_the_internet.json | 118 ++ .../linux_kernel_module_activity.json | 68 + .../linux_ldso_process_activity.json | 17 + ..._lzop_activity_possible_julianrunnels.json | 17 + .../linux_mknod_activity.json | 68 + .../linux_netcat_network_connection.json | 93 ++ ...k_anomalous_process_using_https_ports.json | 17 + .../linux_nmap_activity.json | 68 + .../linux_nping_activity.json | 68 + ...nux_process_started_in_temp_directory.json | 68 + .../linux_ptrace_activity.json | 43 + .../linux_rawshark_activity.json | 68 + .../linux_shell_activity_by_web_server.json | 17 + .../linux_strace_activity.json | 68 + .../linux_tcpdump_activity.json | 43 + .../linux_unusual_shell_activity.json | 93 ++ .../prepackaged_rules/linux_web_download.json | 43 + .../linux_whoami_commmand.json | 68 + .../network_dns_directly_to_the_internet.json | 17 + ...fer_protocol_activity_to_the_internet.json | 17 + ...hat_protocol_activity_to_the_internet.json | 17 + .../network_nat_traversal_port_activity.json | 17 + .../network_port_26_activity.json | 17 + .../network_port_8000_activity.json | 17 + ...rk_port_8000_activity_to_the_internet.json | 17 + ..._to_point_tunneling_protocol_activity.json | 17 + ...k_proxy_port_activity_to_the_internet.json | 17 + ...te_desktop_protocol_from_the_internet.json | 17 + ...mote_desktop_protocol_to_the_internet.json | 17 + ...mote_procedure_call_from_the_internet.json | 17 + ...remote_procedure_call_to_the_internet.json | 17 + ...file_sharing_activity_to_the_internet.json | 17 + .../network_smtp_to_the_internet.json | 17 + ..._server_port_activity_to_the_internet.json | 17 + ...rk_ssh_secure_shell_from_the_internet.json | 17 + ...work_ssh_secure_shell_to_the_internet.json | 17 + .../network_telnet_port_activity.json | 17 + .../network_tor_activity_to_the_internet.json | 17 + ...l_network_computing_from_the_internet.json | 17 + ...ual_network_computing_to_the_internet.json | 17 + .../powershell_network_connection.json | 68 + ...ed_by_acrobat_reader_possible_payload.json | 43 + ...by_ms_office_program_possible_payload.json | 43 + .../process_started_by_windows_defender.json | 17 + .../prepackaged_rules/psexec_activity.json | 17 + .../prepackaged_rules/search_windows_10.json | 66 + ...ed_invokecommand_powershell_execution.json | 17 + ...ncoded_newobject_powershell_execution.json | 17 + ...ded_startprocess_powershell_execution.json | 17 + ...baltstrike_artifact_in_an_dns_request.json | 17 + ...a_commonly_abused_dns_domain_detected.json | 17 + ...eversal_characters_in_an_http_request.json | 17 + ...traversal_characters_in_http_response.json | 17 + ...tory_traversal_in_downloaded_zip_file.json | 17 + ...icata_dns_traffic_on_unusual_tcp_port.json | 17 + ...icata_dns_traffic_on_unusual_udp_port.json | 17 + ...ta_double_encoded_characters_in_a_uri.json | 17 + ...le_encoded_characters_in_an_http_post.json | 17 + ..._eval_php_function_in_an_http_request.json | 17 + ..._on_unusual_port_internet_destination.json | 17 + ..._on_unusual_port_internet_destination.json | 17 + ..._on_unusual_port_internet_destination.json | 17 + ...cata_lazagne_artifact_in_an_http_post.json | 17 + ...ta_mimikatz_artifacts_in_an_http_post.json | 17 + ...katz_string_detected_in_http_response.json | 17 + ...uricata_nondns_traffic_on_tcp_port_53.json | 17 + ...uricata_nondns_traffic_on_udp_port_53.json | 17 + .../suricata_nonftp_traffic_on_port_21.json | 17 + ...ricata_nonhttp_traffic_on_tcp_port_80.json | 17 + ...ata_nonimap_traffic_on_port_1443_imap.json | 17 + ...ta_nonsmb_traffic_on_tcp_port_139_smb.json | 17 + .../suricata_nonssh_traffic_on_port_22.json | 17 + .../suricata_nontls_on_tls_port.json | 17 + ...alt_strike_malleable_c2_null_response.json | 17 + ...ion_sql_commands_in_http_transactions.json | 17 + .../suricata_rpc_traffic_on_http_ports.json | 17 + .../suricata_serialized_php_detected.json | 17 + ...ell_exec_php_function_in_an_http_post.json | 17 + ...c_not_on_port_22_internet_destination.json | 17 + ..._on_unusual_port_internet_destination.json | 17 + ...executable_served_by_jpeg_web_content.json | 17 + ...uspicious_process_started_by_a_script.json | 43 + ...rvice_bits_connecting_to_the_internet.json | 17 + .../windows_burp_ce_activity.json | 17 + ...s_certutil_connecting_to_the_internet.json | 17 + ...and_prompt_connecting_to_the_internet.json | 17 + .../windows_credential_dumping_commands.json | 17 + ...dows_credential_dumping_via_imageload.json | 17 + ..._credential_dumping_via_registry_save.json | 17 + ...ows_data_compression_using_powershell.json | 17 + ...fense_evasion_decoding_using_certutil.json | 17 + ...asion_or_persistence_via_hidden_files.json | 17 + ...ws_defense_evasion_via_filter_manager.json | 17 + ...e_evasion_via_windows_event_log_tools.json | 17 + ...dows_execution_via_compiled_html_file.json | 17 + ...dows_execution_via_connection_manager.json | 17 + ...on_via_microsoft_html_application_hta.json | 17 + ...dows_execution_via_net_com_assemblies.json | 17 + .../windows_execution_via_regsvr32.json | 17 + ...ution_via_trusted_developer_utilities.json | 17 + ...le_program_connecting_to_the_internet.json | 17 + ...dows_image_load_from_a_temp_directory.json | 43 + .../windows_indirect_command_execution.json | 17 + .../windows_iodine_activity.json | 17 + ...agement_instrumentation_wmi_execution.json | 17 + ...cation_hta_connecting_to_the_internet.json | 17 + .../windows_mimikatz_activity.json | 43 + ...isc_lolbin_connecting_to_the_internet.json | 17 + ...ommand_activity_by_the_system_account.json | 53 + .../windows_net_user_command_activity.json | 43 + .../windows_netcat_activity.json | 43 + .../windows_netcat_network_activity.json | 43 + ...ous_windows_process_using_https_ports.json | 17 + .../windows_nmap_activity.json | 43 + .../windows_nmap_scan_activity.json | 43 + ...dows_payload_obfuscation_via_certutil.json | 17 + ...stence_or_priv_escalation_via_hooking.json | 17 + ..._persistence_via_application_shimming.json | 17 + .../windows_persistence_via_bits_jobs.json | 17 + ..._via_modification_of_existing_service.json | 17 + ...s_persistence_via_netshell_helper_dll.json | 17 + ...powershell_connecting_to_the_internet.json | 17 + ...escalation_via_accessibility_features.json | 17 + ...rocess_discovery_via_tasklist_command.json | 17 + ...s_process_started_by_the_java_runtime.json | 43 + ...er_program_connecting_to_the_internet.json | 17 + .../windows_registry_query_local.json | 17 + .../windows_registry_query_network.json | 17 + .../windows_remote_management_execution.json | 17 + .../windows_scheduled_task_activity.json | 17 + ...nterpreter_connecting_to_the_internet.json | 17 + ...windows_signed_binary_proxy_execution.json | 17 + ...igned_binary_proxy_execution_download.json | 17 + .../windows_whoami_command_activity.json | 43 + .../windows_wireshark_activity.json | 17 + .../prepackaged_rules/windump_activity.json | 17 + .../rules/update_prepacked_rules.ts | 75 ++ .../rules/update_rules.test.ts | 20 +- .../detection_engine/rules/update_rules.ts | 38 +- .../rules/update_tags.test.ts | 35 - .../lib/detection_engine/rules/update_tags.ts | 16 - .../scripts/add_prepackaged_rules.sh | 17 + .../scripts/convert_saved_search_to_rules.sh | 4 +- .../scripts/find_rule_by_filter.sh | 22 +- .../rules/queries/query_with_everything.json | 3 +- .../rules/updates/update_immutable.json | 4 + .../rules/updates/update_interval.json | 4 + .../updates/update_query_everything.json | 3 +- .../scripts/rules/updates/update_version.json | 4 + .../signals/__mocks__/es_results.ts | 1 + .../signals/build_bulk_body.test.ts | 4 + .../signals/build_rule.test.ts | 3 + .../detection_engine/signals/build_rule.ts | 1 + .../signals/signal_rule_alert_type.ts | 1 + .../detection_engine/tags/read_tags.test.ts | 30 +- .../siem/server/lib/detection_engine/types.ts | 1 + 192 files changed, 6403 insertions(+), 189 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts delete mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts delete mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_internet_explorer.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_powershell.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_svchost.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/index.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_hping_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_iodine_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_java_process_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_kernel_module_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ldso_process_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_lzop_activity_possible_julianrunnels.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_mknod_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_netcat_network_connection.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_network_anomalous_process_using_https_ports.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nmap_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nping_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_process_started_in_temp_directory.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ptrace_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_rawshark_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_shell_activity_by_web_server.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_strace_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_tcpdump_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_unusual_shell_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_web_download.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_whoami_commmand.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_dns_directly_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ftp_file_transfer_protocol_activity_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_irc_internet_relay_chat_protocol_activity_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_nat_traversal_port_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_26_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_pptp_point_to_point_tunneling_protocol_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_proxy_port_activity_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_from_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_from_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smb_windows_file_sharing_activity_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smtp_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_sql_server_port_activity_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_from_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_telnet_port_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_tor_activity_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_from_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/powershell_network_connection.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_acrobat_reader_possible_payload.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_ms_office_program_possible_payload.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_windows_defender.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/psexec_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/search_windows_10.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_invokecommand_powershell_execution.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_newobject_powershell_execution.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_startprocess_powershell_execution.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_cobaltstrike_artifact_in_an_dns_request.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_commonly_abused_dns_domain_detected.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_reversal_characters_in_an_http_request.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_characters_in_http_response.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_in_downloaded_zip_file.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_tcp_port.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_udp_port.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_a_uri.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_an_http_post.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_eval_php_function_in_an_http_request.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ftp_traffic_on_unusual_port_internet_destination.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_http_traffic_on_unusual_port_internet_destination.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_imap_traffic_on_unusual_port_internet_destination.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_lazagne_artifact_in_an_http_post.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_artifacts_in_an_http_post.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_string_detected_in_http_response.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_tcp_port_53.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_udp_port_53.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonftp_traffic_on_port_21.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonhttp_traffic_on_tcp_port_80.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonimap_traffic_on_port_1443_imap.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonsmb_traffic_on_tcp_port_139_smb.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonssh_traffic_on_port_22.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nontls_on_tls_port.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_cobalt_strike_malleable_c2_null_response.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_sql_injection_sql_commands_in_http_transactions.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_rpc_traffic_on_http_ports.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_serialized_php_detected.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_shell_exec_php_function_in_an_http_post.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ssh_traffic_not_on_port_22_internet_destination.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_tls_traffic_on_unusual_port_internet_destination.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_windows_executable_served_by_jpeg_web_content.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_process_started_by_a_script.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_background_intelligent_transfer_service_bits_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_burp_ce_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_certutil_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_command_prompt_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_commands.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_imageload.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_registry_save.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_data_compression_using_powershell.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_decoding_using_certutil.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_or_persistence_via_hidden_files.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_filter_manager.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_windows_event_log_tools.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_compiled_html_file.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_connection_manager.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_microsoft_html_application_hta.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_net_com_assemblies.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_regsvr32.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_trusted_developer_utilities.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_html_help_executable_program_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_image_load_from_a_temp_directory.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_indirect_command_execution.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_iodine_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_management_instrumentation_wmi_execution.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_microsoft_html_application_hta_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_mimikatz_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_misc_lolbin_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_command_activity_by_the_system_account.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_user_command_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_network_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_network_anomalous_windows_process_using_https_ports.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_scan_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_payload_obfuscation_via_certutil.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_or_priv_escalation_via_hooking.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_application_shimming.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_bits_jobs.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_modification_of_existing_service.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_netshell_helper_dll.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_powershell_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_priv_escalation_via_accessibility_features.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_discovery_via_tasklist_command.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_started_by_the_java_runtime.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_register_server_program_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_local.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_network.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_remote_management_execution.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_scheduled_task_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_script_interpreter_connecting_to_the_internet.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution_download.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_whoami_command_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_wireshark_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windump_activity.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts delete mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts delete mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts create mode 100755 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/add_prepackaged_rules.sh create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_immutable.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_interval.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_version.json diff --git a/x-pack/legacy/plugins/siem/common/constants.ts b/x-pack/legacy/plugins/siem/common/constants.ts index 7b5015c34de14a..3b5cdec4dc4d9d 100644 --- a/x-pack/legacy/plugins/siem/common/constants.ts +++ b/x-pack/legacy/plugins/siem/common/constants.ts @@ -46,12 +46,14 @@ export const SIGNALS_ID = `${APP_ID}.signals`; */ export const INTERNAL_IDENTIFIER = '__internal'; export const INTERNAL_RULE_ID_KEY = `${INTERNAL_IDENTIFIER}_rule_id`; +export const INTERNAL_IMMUTABLE_KEY = `${INTERNAL_IDENTIFIER}_immutable`; /** * Detection engine routes */ export const DETECTION_ENGINE_URL = '/api/detection_engine'; export const DETECTION_ENGINE_RULES_URL = `${DETECTION_ENGINE_URL}/rules`; +export const DETECTION_ENGINE_PREPACKAGED_URL = `${DETECTION_ENGINE_RULES_URL}/prepackaged`; export const DETECTION_ENGINE_PRIVILEGES_URL = `${DETECTION_ENGINE_URL}/privileges`; export const DETECTION_ENGINE_INDEX_URL = `${DETECTION_ENGINE_URL}/index`; export const DETECTION_ENGINE_TAGS_URL = `${DETECTION_ENGINE_URL}/tags`; diff --git a/x-pack/legacy/plugins/siem/scripts/convert_saved_search_to_rules.js b/x-pack/legacy/plugins/siem/scripts/convert_saved_search_to_rules.js index b282a8bf1e861a..9e24e93b0c3911 100644 --- a/x-pack/legacy/plugins/siem/scripts/convert_saved_search_to_rules.js +++ b/x-pack/legacy/plugins/siem/scripts/convert_saved_search_to_rules.js @@ -8,6 +8,8 @@ require('../../../../../src/setup_node_env'); const fs = require('fs'); const path = require('path'); +// eslint-disable-next-line import/no-extraneous-dependencies +const uuid = require('uuid'); /* * This script is used to parse a set of saved searches on a file system @@ -36,8 +38,17 @@ const TO = 'now'; const IMMUTABLE = true; const RISK_SCORE = 50; const ENABLED = false; -let allRules = ''; -const allRulesNdJson = 'all_rules.ndjson'; +let allRules = `/* + * 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. + */ + +// Auto generated file from scripts/convert_saved_search_rules.js +// Do not hand edit. Run the script against a set of saved searches instead + +`; +const allRulesNdJson = 'index.ts'; // For converting, if you want to use these instead of rely on the defaults then // comment these in and use them for the script. Otherwise this is commented out @@ -62,14 +73,26 @@ const walk = dir => { //clean up the file system characters const cleanupFileName = file => { - return path - .basename(file, path.extname(file)) + const fileWithoutSpecialChars = file + .trim() + .replace(/\./g, '') + .replace(/\//g, '') .replace(/\s+/g, '_') .replace(/,/g, '') + .replace(/\[/g, '') + .replace(/\]/g, '') + .replace(/\(/g, '') + .replace(/\)/g, '') + .replace(/\@/g, '') + .replace(/\:/g, '') .replace(/\+s/g, '') .replace(/-/g, '') .replace(/__/g, '_') .toLowerCase(); + return path.basename( + fileWithoutSpecialChars.trim(), + path.extname(fileWithoutSpecialChars.trim()) + ); }; async function main() { @@ -89,22 +112,20 @@ async function main() { const savedSearchesParsed = savedSearchesJson.reduce((accum, json) => { const jsonFile = fs.readFileSync(json, 'utf8'); const jsonLines = jsonFile.split(/\r{0,1}\n/); - const parsedLines = jsonLines.reduce((accum, line, index) => { + const parsedLines = jsonLines.reduce((accum, line) => { try { const parsedLine = JSON.parse(line); - if (index !== 0) { - parsedLine._file = `${json.substring(0, json.length - '.ndjson'.length)}_${String( - index - )}.ndjson`; - } else { - parsedLine._file = json; + // don't try to parse out any exported count records + if (parsedLine.exportedCount != null) { + return accum; } + parsedLine._file = parsedLine.attributes.title; parsedLine.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.parse( parsedLine.attributes.kibanaSavedObjectMeta.searchSourceJSON ); return [...accum, parsedLine]; } catch (err) { - console.log('error parsing a line in this file:', json); + console.log('error parsing a line in this file:', json, line); return accum; } }, []); @@ -112,51 +133,64 @@ async function main() { }, []); savedSearchesParsed.forEach( - ({ - _file, - attributes: { - description, - title, - kibanaSavedObjectMeta: { - searchSourceJSON: { - query: { query, language }, - filter, + ( + { + _file, + attributes: { + description, + title, + kibanaSavedObjectMeta: { + searchSourceJSON: { + query: { query, language }, + filter, + }, }, }, }, - }) => { + index + ) => { const fileToWrite = cleanupFileName(_file); - if (query != null && query.trim() !== '') { - const outputMessage = { - rule_id: fileToWrite, - risk_score: RISK_SCORE, - description: description || title, - immutable: IMMUTABLE, - interval: INTERVAL, - name: title, - severity: SEVERITY, - type: TYPE, - from: FROM, - to: TO, - query, - language, - filters: filter, - enabled: ENABLED, - // comment these in if you want to use these for input output, otherwise - // with these two commented out, we will use the default saved objects from spaces. - // index: INDEX, - // output_index: OUTPUT_INDEX, - }; - - fs.writeFileSync( - `${outputDir}/${fileToWrite}.json`, - JSON.stringify(outputMessage, null, 2) - ); - allRules += `${JSON.stringify(outputMessage)}\n`; - } + // remove meta value from the filter + const filterWithoutMeta = filter.map(filterValue => { + filterValue.$state; + return filterValue; + }); + const outputMessage = { + rule_id: uuid.v4(), + risk_score: RISK_SCORE, + description: description || title, + immutable: IMMUTABLE, + interval: INTERVAL, + name: title, + severity: SEVERITY, + type: TYPE, + from: FROM, + to: TO, + query, + language, + filters: filterWithoutMeta, + enabled: ENABLED, + version: 1, + // comment these in if you want to use these for input output, otherwise + // with these two commented out, we will use the default saved objects from spaces. + // index: INDEX, + // output_index: OUTPUT_INDEX, + }; + + fs.writeFileSync( + `${outputDir}/${fileToWrite}.json`, + `${JSON.stringify(outputMessage, null, 2)}\n` + ); + allRules += `import rule${index + 1} from './${fileToWrite}.json';\n`; } ); + allRules += '\n'; + allRules += 'export const rawRules = [\n'; + savedSearchesParsed.forEach((_, index) => { + allRules += ` rule${index + 1},\n`; + }); + allRules += '];\n'; fs.writeFileSync(`${outputDir}/${allRulesNdJson}`, allRules); } diff --git a/x-pack/legacy/plugins/siem/server/kibana.index.ts b/x-pack/legacy/plugins/siem/server/kibana.index.ts index e90e6366dd9ecd..647894e9e71872 100644 --- a/x-pack/legacy/plugins/siem/server/kibana.index.ts +++ b/x-pack/legacy/plugins/siem/server/kibana.index.ts @@ -21,6 +21,7 @@ import { deleteIndexRoute } from './lib/detection_engine/routes/index/delete_ind import { isAlertExecutor } from './lib/detection_engine/signals/types'; import { readTagsRoute } from './lib/detection_engine/routes/tags/read_tags_route'; import { readPrivilegesRoute } from './lib/detection_engine/routes/privileges/read_privileges_route'; +import { addPrepackedRulesRoute } from './lib/detection_engine/routes/rules/add_prepackaged_rules_route'; const APP_ID = 'siem'; @@ -42,6 +43,7 @@ export const initServerWithKibana = (context: PluginInitializerContext, __legacy updateRulesRoute(__legacy); deleteRulesRoute(__legacy); findRulesRoute(__legacy); + addPrepackedRulesRoute(__legacy); // Detection Engine Signals routes that have the REST endpoints of /api/detection_engine/signals // POST /api/detection_engine/signals/status @@ -57,6 +59,7 @@ export const initServerWithKibana = (context: PluginInitializerContext, __legacy // Detection Engine tags routes that have the REST endpoints of /api/detection_engine/tags readTagsRoute(__legacy); + // Privileges API to get the generic user privileges readPrivilegesRoute(__legacy); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 6358a9b89c2a41..7d114178c6c929 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -13,14 +13,47 @@ import { DETECTION_ENGINE_PRIVILEGES_URL, DETECTION_ENGINE_QUERY_SIGNALS_URL, INTERNAL_RULE_ID_KEY, + INTERNAL_IMMUTABLE_KEY, } from '../../../../../common/constants'; import { RuleAlertType } from '../../rules/types'; import { RuleAlertParamsRest } from '../../types'; -// The Omit of filter is because of a Hapi Server Typing issue that I am unclear -// where it comes from. I would hope to remove the "filter" as an omit at some point -// when we upgrade and Hapi Server is ok with the filter. -export const typicalPayload = (): Partial> => ({ +export const fullRuleAlertParamsRest = (): RuleAlertParamsRest => ({ + rule_id: 'rule-1', + description: 'Detecting root and admin users', + index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + interval: '5m', + name: 'Detect Root/Admin Users', + output_index: '.siem-signals', + risk_score: 50, + type: 'query', + from: 'now-6m', + to: 'now', + severity: 'high', + query: 'user.name: root or user.name: admin', + language: 'kuery', + threats: [ + { + framework: 'fake', + tactic: { id: 'fakeId', name: 'fakeName', reference: 'fakeRef' }, + techniques: [{ id: 'techniqueId', name: 'techniqueName', reference: 'techniqueRef' }], + }, + ], + enabled: true, + filters: [], + immutable: false, + references: [], + meta: {}, + tags: [], + version: 1, + false_positives: [], + saved_id: 'some-id', + max_signals: 100, + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', +}); + +export const typicalPayload = (): Partial => ({ rule_id: 'rule-1', description: 'Detecting root and admin users', index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], @@ -109,12 +142,24 @@ export const getFindResultWithSingleHit = (): FindHit => ({ data: [getResult()], }); -export const getFindResultWithMultiHits = (data: RuleAlertType[]): FindHit => ({ - page: 1, - perPage: 1, - total: 2, +export const getFindResultWithMultiHits = ({ data, -}); + page = 1, + perPage = 1, + total, +}: { + data: RuleAlertType[]; + page?: number; + perPage?: number; + total?: number; +}) => { + return { + page, + perPage, + total: total != null ? total : data.length, + data, + }; +}; export const getDeleteRequest = (): ServerInjectOptions => ({ method: 'DELETE', @@ -172,7 +217,7 @@ export const createActionResult = (): ActionResult => ({ export const getResult = (): RuleAlertType => ({ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', name: 'Detect Root/Admin Users', - tags: [`${INTERNAL_RULE_ID_KEY}:rule-1`], + tags: [`${INTERNAL_RULE_ID_KEY}:rule-1`, `${INTERNAL_IMMUTABLE_KEY}:false`], alertTypeId: 'siem.signals', params: { createdAt: '2019-12-13T16:40:33.400Z', @@ -215,6 +260,7 @@ export const getResult = (): RuleAlertType => ({ }, ], references: ['http://www.example.com', 'https://ww.example.com'], + version: 1, }, interval: '5m', enabled: true, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts new file mode 100644 index 00000000000000..922b70e87467ed --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts @@ -0,0 +1,76 @@ +/* + * 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 Hapi from 'hapi'; +import { isFunction } from 'lodash/fp'; +import Boom from 'boom'; + +import { DETECTION_ENGINE_PREPACKAGED_URL } from '../../../../../common/constants'; +import { ServerFacade, RequestFacade } from '../../../../types'; +import { getIndexExists } from '../../index/get_index_exists'; +import { callWithRequestFactory, getIndex, transformError } from '../utils'; +import { getPrepackagedRules } from '../../rules/get_prepackaged_rules'; +import { installPrepackagedRules } from '../../rules/install_prepacked_rules'; +import { updatePrepackagedRules } from '../../rules/update_prepacked_rules'; +import { getRulesToInstall } from '../../rules/get_rules_to_install'; +import { getRulesToUpdate } from '../../rules/get_rules_to_update'; +import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules'; + +export const createAddPrepackedRulesRoute = (server: ServerFacade): Hapi.ServerRoute => { + return { + method: 'PUT', + path: DETECTION_ENGINE_PREPACKAGED_URL, + options: { + tags: ['access:siem'], + validate: { + options: { + abortEarly: false, + }, + }, + }, + async handler(request: RequestFacade, headers) { + const alertsClient = isFunction(request.getAlertsClient) ? request.getAlertsClient() : null; + const actionsClient = isFunction(request.getActionsClient) + ? request.getActionsClient() + : null; + + if (!alertsClient || !actionsClient) { + return headers.response().code(404); + } + + try { + const callWithRequest = callWithRequestFactory(request, server); + const rulesFromFileSystem = getPrepackagedRules(); + + const prepackedRules = await getExistingPrepackagedRules({ alertsClient }); + const rulesToInstall = getRulesToInstall(rulesFromFileSystem, prepackedRules); + const rulesToUpdate = getRulesToUpdate(rulesFromFileSystem, prepackedRules); + + const spaceIndex = getIndex(request, server); + if (rulesToInstall.length !== 0 || rulesToUpdate.length !== 0) { + const spaceIndexExists = await getIndexExists(callWithRequest, spaceIndex); + if (!spaceIndexExists) { + throw new Boom( + `Pre-packaged rules cannot be installed until the space index is created: ${spaceIndex}` + ); + } + } + await installPrepackagedRules(alertsClient, actionsClient, rulesToInstall, spaceIndex); + await updatePrepackagedRules(alertsClient, actionsClient, rulesToUpdate, spaceIndex); + return { + rules_installed: rulesToInstall.length, + rules_updated: rulesToUpdate.length, + }; + } catch (err) { + return transformError(err); + } + }, + }; +}; + +export const addPrepackedRulesRoute = (server: ServerFacade): void => { + server.route(createAddPrepackedRulesRoute(server)); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts index 8780a0c1c9d873..6fec45b024e845 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -114,6 +114,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute = threats, updatedAt, references, + version: 1, }); return transformOrError(createdRule); } catch (err) { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts index 2e7b48afbb5d94..154c8d7341ed32 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -52,6 +52,7 @@ export const createUpdateRulesRoute: Hapi.ServerRoute = { type, threats, references, + version, } = request.payload; const alertsClient = isFunction(request.getAlertsClient) ? request.getAlertsClient() : null; @@ -89,6 +90,7 @@ export const createUpdateRulesRoute: Hapi.ServerRoute = { type, threats, references, + version, }); if (rule != null) { return transformOrError(rule); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index d92c35e5ca0b22..e05bdf764a09c9 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -63,6 +63,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); @@ -109,6 +110,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); @@ -157,6 +159,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); @@ -205,6 +208,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); @@ -251,6 +255,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); @@ -300,6 +305,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); @@ -349,6 +355,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); @@ -398,6 +405,7 @@ describe('utils', () => { ], to: 'now', type: 'query', + version: 1, }); }); }); @@ -498,6 +506,7 @@ describe('utils', () => { ], }, ], + version: 1, }, ], }); @@ -554,6 +563,7 @@ describe('utils', () => { ], }, ], + version: 1, }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index fce709d1174351..a041a5665e79c1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -62,6 +62,7 @@ export const transformAlertToRule = (alert: RuleAlertType): Partial { + test('empty objects do not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({}).error + ).toBeTruthy(); + }); + + test('made up values do not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + madeUp: 'hi', + }).error + ).toBeTruthy(); + }); + + test('[rule_id] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, name] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + name: 'some-name', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, name, severity] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + name: 'some-name', + severity: 'severity', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, name, severity, type] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + name: 'some-name', + severity: 'severity', + type: 'query', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + name: 'some-name', + severity: 'severity', + type: 'query', + interval: '5m', + index: ['index-1'], + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, name, severity, type, query, index, interval, version] does validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + name: 'some-name', + severity: 'severity', + type: 'query', + query: 'some query', + index: ['index-1'], + interval: '5m', + version: 1, + }).error + ).toBeFalsy(); + }); + + test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does not validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some query', + language: 'kuery', + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, version] does validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some query', + language: 'kuery', + version: 1, + }).error + ).toBeFalsy(); + }); + + test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, output_index] does not validate because output_index is not allowed', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + output_index: '.siem-signals', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some query', + language: 'kuery', + version: 1, + }).error + ).toBeTruthy(); + }); + + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, version] does validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + risk_score: 50, + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You can send in an empty array to threats', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + threats: [], + version: 1, + }).error + ).toBeFalsy(); + }); + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, version, threats] does validate', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + threats: [ + { + framework: 'someFramework', + tactic: { + id: 'fakeId', + name: 'fakeName', + reference: 'fakeRef', + }, + techniques: [ + { + id: 'techniqueId', + name: 'techniqueName', + reference: 'techniqueRef', + }, + ], + }, + ], + version: 1, + }).error + ).toBeFalsy(); + }); + + test('allows references to be sent as valid', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + version: 1, + }).error + ).toBeFalsy(); + }); + + test('defaults references to an array', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some-query', + language: 'kuery', + version: 1, + }).value.references + ).toEqual([]); + }); + + test('defaults immutable to true', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some-query', + language: 'kuery', + version: 1, + }).value.immutable + ).toEqual(true); + }); + + test('defaults enabled to false', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some-query', + language: 'kuery', + version: 1, + }).value.enabled + ).toEqual(false); + }); + + test('rule_id is required', () => { + expect( + addPrepackagedRulesSchema.validate>({ + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some-query', + language: 'kuery', + version: 1, + }).error + ).toBeTruthy(); + }); + + test('references cannot be numbers', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { references: number[] } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some-query', + language: 'kuery', + references: [5], + version: 1, + }).error + ).toBeTruthy(); + }); + + test('indexes cannot be numbers', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { index: number[] } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: [5], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + query: 'some-query', + language: 'kuery', + version: 1, + }).error + ).toBeTruthy(); + }); + + test('defaults interval to 5 min', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + type: 'query', + version: 1, + }).value.interval + ).toEqual('5m'); + }); + + test('defaults max signals to 100', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + version: 1, + }).value.max_signals + ).toEqual(100); + }); + + test('saved_id is required when type is saved_query and will not validate without out', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'saved_query', + version: 1, + }).error + ).toBeTruthy(); + }); + + test('saved_id is required when type is saved_query and validates with it', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'saved_query', + saved_id: 'some id', + version: 1, + }).error + ).toBeFalsy(); + }); + + test('saved_query type can have filters with it', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'saved_query', + saved_id: 'some id', + filters: [], + version: 1, + }).error + ).toBeFalsy(); + }); + + test('filters cannot be a string', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial & { filters: string }> + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'saved_query', + saved_id: 'some id', + filters: 'some string', + version: 1, + }).error + ).toBeTruthy(); + }); + + test('language validates with kuery', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + version: 1, + }).error + ).toBeFalsy(); + }); + + test('language validates with lucene', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'lucene', + version: 1, + }).error + ).toBeFalsy(); + }); + + test('language does not validate with something made up', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'something-made-up', + version: 1, + }).error + ).toBeTruthy(); + }); + + test('max_signals cannot be negative', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: -1, + version: 1, + }).error + ).toBeTruthy(); + }); + + test('max_signals cannot be zero', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 0, + version: 1, + }).error + ).toBeTruthy(); + }); + + test('max_signals can be 1', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You can optionally send in an array of tags', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + tags: ['tag_1', 'tag_2'], + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You cannot send in an array of tags that are numbers', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { tags: number[] } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + tags: [0, 1, 2], + version: 1, + }).error + ).toBeTruthy(); + }); + + test('You cannot send in an array of threats that are missing "framework"', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + threats: Array>>; + } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + threats: [ + { + tactic: { + id: 'fakeId', + name: 'fakeName', + reference: 'fakeRef', + }, + techniques: [ + { + id: 'techniqueId', + name: 'techniqueName', + reference: 'techniqueRef', + }, + ], + }, + ], + version: 1, + }).error + ).toBeTruthy(); + }); + test('You cannot send in an array of threats that are missing "tactic"', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + threats: Array>>; + } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + threats: [ + { + framework: 'fake', + techniques: [ + { + id: 'techniqueId', + name: 'techniqueName', + reference: 'techniqueRef', + }, + ], + }, + ], + version: 1, + }).error + ).toBeTruthy(); + }); + test('You cannot send in an array of threats that are missing "techniques"', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { + threats: Array>>; + } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + threats: [ + { + framework: 'fake', + tactic: { + id: 'fakeId', + name: 'fakeName', + reference: 'fakeRef', + }, + }, + ], + version: 1, + }).error + ).toBeTruthy(); + }); + + test('You can optionally send in an array of false positives', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + false_positives: ['false_1', 'false_2'], + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You cannot send in an array of false positives that are numbers', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { false_positives: number[] } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + false_positives: [5, 4], + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeTruthy(); + }); + + test('You can optionally set the immutable to be true', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You cannot set the immutable to be a number', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial> & { immutable: number } + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: 5, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeTruthy(); + }); + + test('You cannot set the risk_score to 101', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 101, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeTruthy(); + }); + + test('You cannot set the risk_score to -1', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: -1, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeTruthy(); + }); + + test('You can set the risk_score to 0', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 0, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You can set the risk_score to 100', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 100, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You can set meta to any object you want', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + meta: { + somethingMadeUp: { somethingElse: true }, + }, + version: 1, + }).error + ).toBeFalsy(); + }); + + test('You cannot create meta as a string', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial & { meta: string }> + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + max_signals: 1, + meta: 'should not work', + version: 1, + }).error + ).toBeTruthy(); + }); + + test('You can omit the query string when filters are present', () => { + expect( + addPrepackagedRulesSchema.validate< + Partial & { meta: string }> + >({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + immutable: true, + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + language: 'kuery', + filters: [], + max_signals: 1, + version: 1, + }).error + ).toBeFalsy(); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts new file mode 100644 index 00000000000000..8a58f84f9e8481 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts @@ -0,0 +1,75 @@ +/* + * 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 Joi from 'joi'; + +/* eslint-disable @typescript-eslint/camelcase */ +import { + enabled, + description, + false_positives, + filters, + from, + immutable, + index, + rule_id, + interval, + query, + language, + saved_id, + meta, + risk_score, + max_signals, + name, + severity, + tags, + to, + type, + threats, + references, + version, +} from './schemas'; +/* eslint-enable @typescript-eslint/camelcase */ + +import { DEFAULT_MAX_SIGNALS } from '../../../../../common/constants'; + +/** + * Big differences between this schema and the createRulesSchema + * - rule_id is required here + * - output_index is not allowed (and instead the space index must be used) + * - immutable defaults to true instead of to false + * - enabled defaults to false instead of true + * - version is a required field that must exist + */ +export const addPrepackagedRulesSchema = Joi.object({ + description: description.required(), + enabled: enabled.default(false), + false_positives: false_positives.default([]), + filters, + from: from.required(), + rule_id: rule_id.required(), + immutable: immutable.default(true), + index, + interval: interval.default('5m'), + query: query.allow('').default(''), + language: language.default('kuery'), + saved_id: saved_id.when('type', { + is: 'saved_query', + then: Joi.required(), + otherwise: Joi.forbidden(), + }), + meta, + risk_score: risk_score.required(), + max_signals: max_signals.default(DEFAULT_MAX_SIGNALS), + name: name.required(), + severity: severity.required(), + tags: tags.default([]), + to: to.required(), + type: type.required(), + threats: threats.default([]), + references: references.default([]), + version: version.required(), +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts index ccda7256d2eebf..1814dc09b0c01d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts @@ -31,6 +31,7 @@ import { type, threats, references, + version, } from './schemas'; /* eslint-enable @typescript-eslint/camelcase */ @@ -64,4 +65,5 @@ export const createRulesSchema = Joi.object({ type: type.required(), threats: threats.default([]), references: references.default([]), + version: version.default(1), }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index 5ab8ea3b8af3ed..99450fd4c7b1b7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -77,3 +77,5 @@ export const threats = Joi.array().items( techniques: threat_techniques.required(), }) ); + +export const version = Joi.number().min(1); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts index 244d8d1f5cc77e..cdca17c4197f8d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts @@ -32,6 +32,7 @@ import { threats, references, id, + version, } from './schemas'; /* eslint-enable @typescript-eslint/camelcase */ @@ -60,4 +61,5 @@ export const updateRulesSchema = Joi.object({ type, threats, references, + version, }).xor('id', 'rule_id'); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts index 8ca5c24d881001..437c0a43624307 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.test.ts @@ -44,5 +44,17 @@ describe('utils', () => { const transformed = transformError(error); expect(Boom.isBoom(transformed)).toBe(false); }); + + test('it detects a TypeError and returns a Boom', () => { + const error: TypeError = new TypeError('I have a type error'); + const transformed = transformError(error); + expect(Boom.isBoom(transformed)).toBe(true); + }); + + test('it detects a TypeError and returns a Boom status of 400', () => { + const error: TypeError = new TypeError('I have a type error'); + const transformed = transformError(error) as Boom; + expect(transformed.output.statusCode).toBe(400); + }); }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts index aed0ced5cdeb55..62281c7ebaacb0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/utils.ts @@ -14,6 +14,10 @@ export const transformError = (err: Error & { statusCode?: number }) => { } else { if (err.statusCode != null) { return new Boom(err.message, { statusCode: err.statusCode }); + } else if (err instanceof TypeError) { + // allows us to throw type errors instead of booms in some conditions + // where we don't want to mingle Boom with the rest of the code + return new Boom(err.message, { statusCode: 400 }); } else { // natively return the err and allow the regular framework // to deal with the error when it is a non Boom diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts deleted file mode 100644 index 5a92c8ef42ed71..00000000000000 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 { addRuleIdToTags } from './add_rule_id_to_tags'; -import { INTERNAL_RULE_ID_KEY } from '../../../../common/constants'; - -describe('add_rule_id_to_tags', () => { - test('it should add a rule id as an internal structure to a single tag', () => { - const tags = addRuleIdToTags(['tag 1'], 'rule-1'); - expect(tags).toEqual(['tag 1', `${INTERNAL_RULE_ID_KEY}:rule-1`]); - }); - - test('it should add a rule id as an internal structure to two tags', () => { - const tags = addRuleIdToTags(['tag 1', 'tag 2'], 'rule-1'); - expect(tags).toEqual(['tag 1', 'tag 2', `${INTERNAL_RULE_ID_KEY}:rule-1`]); - }); - - test('it should add a rule id as an internal structure with empty tags', () => { - const tags = addRuleIdToTags([], 'rule-1'); - expect(tags).toEqual([`${INTERNAL_RULE_ID_KEY}:rule-1`]); - }); - - test('it should add not add an internal structure if rule id is undefined', () => { - const tags = addRuleIdToTags(['tag 1'], undefined); - expect(tags).toEqual(['tag 1']); - }); - - test('it should add not add an internal structure if rule id is null', () => { - const tags = addRuleIdToTags(['tag 1'], null); - expect(tags).toEqual(['tag 1']); - }); -}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.ts deleted file mode 100644 index 1cf97881d514bc..00000000000000 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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 { INTERNAL_RULE_ID_KEY } from '../../../../common/constants'; - -export const addRuleIdToTags = (tags: string[], ruleId: string | null | undefined): string[] => { - if (ruleId == null) { - return tags; - } else { - return [...tags, `${INTERNAL_RULE_ID_KEY}:${ruleId}`]; - } -}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.test.ts new file mode 100644 index 00000000000000..8bfd9bef637333 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.test.ts @@ -0,0 +1,75 @@ +/* + * 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 { addTags } from './add_tags'; +import { INTERNAL_RULE_ID_KEY, INTERNAL_IMMUTABLE_KEY } from '../../../../common/constants'; + +describe('add_tags', () => { + test('if given a null everything this returns a new array for tags', () => { + const tags = addTags(null, null, null); + expect(tags).toEqual([]); + }); + + test('if given a undefined everything this returns a new array for tags', () => { + const tags = addTags(undefined, undefined, undefined); + expect(tags).toEqual([]); + }); + + test('it should add a rule id as an internal structure to a single tag', () => { + const tags = addTags(['tag 1'], 'rule-1', null); + expect(tags).toEqual(['tag 1', `${INTERNAL_RULE_ID_KEY}:rule-1`]); + }); + + test('it should add a rule id as an internal structure to a single tag if the input tags is null', () => { + const tags = addTags(null, 'rule-1', null); + expect(tags).toEqual([`${INTERNAL_RULE_ID_KEY}:rule-1`]); + }); + + test('it should add a rule id as an internal structure to two tags', () => { + const tags = addTags(['tag 1', 'tag 2'], 'rule-1', null); + expect(tags).toEqual(['tag 1', 'tag 2', `${INTERNAL_RULE_ID_KEY}:rule-1`]); + }); + + test('it should add a rule id as an internal structure with empty tags', () => { + const tags = addTags([], 'rule-1', null); + expect(tags).toEqual([`${INTERNAL_RULE_ID_KEY}:rule-1`]); + }); + + test('it should add a immutable true as an internal structure with empty tags', () => { + const tags = addTags([], null, true); + expect(tags).toEqual([`${INTERNAL_IMMUTABLE_KEY}:true`]); + }); + + test('it should add a immutable false as an internal structure with empty tags', () => { + const tags = addTags([], null, false); + expect(tags).toEqual([`${INTERNAL_IMMUTABLE_KEY}:false`]); + }); + + test('it should add a rule id as an internal structure with immutable true', () => { + const tags = addTags([], 'rule-1', true); + expect(tags).toEqual([`${INTERNAL_RULE_ID_KEY}:rule-1`, `${INTERNAL_IMMUTABLE_KEY}:true`]); + }); + + test('it should add a rule id as an internal structure with immutable false', () => { + const tags = addTags([], 'rule-1', false); + expect(tags).toEqual([`${INTERNAL_RULE_ID_KEY}:rule-1`, `${INTERNAL_IMMUTABLE_KEY}:false`]); + }); + + test('it should add not add an internal structure if only a tag is given', () => { + const tags = addTags(['tag 1'], undefined, null); + expect(tags).toEqual(['tag 1']); + }); + + test('it should add not add an internal structure if everything is null', () => { + const tags = addTags(['tag 1'], null, null); + expect(tags).toEqual(['tag 1']); + }); + + test('it should add not add an internal structure if everything is undefined', () => { + const tags = addTags(['tag 1'], undefined, undefined); + expect(tags).toEqual(['tag 1']); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.ts new file mode 100644 index 00000000000000..f33f6ada83190c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_tags.ts @@ -0,0 +1,28 @@ +/* + * 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 { INTERNAL_RULE_ID_KEY, INTERNAL_IMMUTABLE_KEY } from '../../../../common/constants'; + +export const addTags = ( + tags: string[] | null | undefined, + ruleId: string | null | undefined, + immutable: boolean | null | undefined +): string[] => { + const defaultedTags = tags != null ? tags : []; + if (ruleId != null && immutable != null) { + return [ + ...defaultedTags, + `${INTERNAL_RULE_ID_KEY}:${ruleId}`, + `${INTERNAL_IMMUTABLE_KEY}:${immutable}`, + ]; + } else if (ruleId != null && immutable == null) { + return [...defaultedTags, `${INTERNAL_RULE_ID_KEY}:${ruleId}`]; + } else if (ruleId == null && immutable != null) { + return [...defaultedTags, `${INTERNAL_IMMUTABLE_KEY}:${immutable}`]; + } else { + return defaultedTags; + } +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index fbdc56dec1a696..d640aa05af5bf1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -6,7 +6,7 @@ import { SIGNALS_ID } from '../../../../common/constants'; import { RuleParams } from './types'; -import { addRuleIdToTags } from './add_rule_id_to_tags'; +import { addTags } from './add_tags'; export const createRules = async ({ alertsClient, @@ -34,11 +34,12 @@ export const createRules = async ({ to, type, references, + version, }: RuleParams) => { return alertsClient.create({ data: { name, - tags: addRuleIdToTags(tags, ruleId), + tags: addTags(tags, ruleId, immutable), alertTypeId: SIGNALS_ID, params: { createdAt: new Date().toISOString(), @@ -62,6 +63,7 @@ export const createRules = async ({ type, updatedAt: new Date().toISOString(), references, + version, }, interval, enabled, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.test.ts new file mode 100644 index 00000000000000..bb28a5575f51ee --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.test.ts @@ -0,0 +1,114 @@ +/* + * 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 { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock'; +import { AlertsClient } from '../../../../../alerting'; +import { + getResult, + getFindResultWithSingleHit, + getFindResultWithMultiHits, +} from '../routes/__mocks__/request_responses'; +import { getExistingPrepackagedRules } from './get_existing_prepackaged_rules'; + +describe('get_existing_prepackaged_rules', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('getExistingPrepackagedRules', () => { + test('should return a single item in a single page', async () => { + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const rules = await getExistingPrepackagedRules({ + alertsClient: unsafeCast, + }); + expect(rules).toEqual([getResult()]); + }); + + test('should return 2 items over two pages, one per page', async () => { + const alertsClient = alertsClientMock.create(); + + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + + alertsClient.find.mockResolvedValueOnce( + getFindResultWithMultiHits({ data: [result1], perPage: 1, page: 1, total: 2 }) + ); + alertsClient.find.mockResolvedValueOnce( + getFindResultWithMultiHits({ data: [result2], perPage: 1, page: 2, total: 2 }) + ); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const rules = await getExistingPrepackagedRules({ + alertsClient: unsafeCast, + }); + expect(rules).toEqual([result1, result2]); + }); + + test('should return 3 items with over 3 pages one per page', async () => { + const alertsClient = alertsClientMock.create(); + + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + + const result3 = getResult(); + result3.id = 'f3e1bf0b-b95f-43da-b1de-5d2f0af2287a'; + + alertsClient.find.mockResolvedValueOnce( + getFindResultWithMultiHits({ data: [result1], perPage: 1, page: 1, total: 3 }) + ); + + alertsClient.find.mockResolvedValueOnce( + getFindResultWithMultiHits({ data: [result2], perPage: 1, page: 2, total: 3 }) + ); + + alertsClient.find.mockResolvedValueOnce( + getFindResultWithMultiHits({ data: [result3], perPage: 1, page: 2, total: 3 }) + ); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const rules = await getExistingPrepackagedRules({ + alertsClient: unsafeCast, + }); + expect(rules).toEqual([result1, result2, result3]); + }); + + test('should return 3 items over 1 pages with all on one page', async () => { + const alertsClient = alertsClientMock.create(); + + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + + const result3 = getResult(); + result3.id = 'f3e1bf0b-b95f-43da-b1de-5d2f0af2287a'; + + alertsClient.find.mockResolvedValueOnce( + getFindResultWithMultiHits({ + data: [result1, result2, result3], + perPage: 3, + page: 1, + total: 3, + }) + ); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const rules = await getExistingPrepackagedRules({ + alertsClient: unsafeCast, + }); + expect(rules).toEqual([result1, result2, result3]); + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.ts new file mode 100644 index 00000000000000..fa2e2124d05390 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_existing_prepackaged_rules.ts @@ -0,0 +1,60 @@ +/* + * 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 { INTERNAL_IMMUTABLE_KEY } from '../../../../common/constants'; +import { AlertsClient } from '../../../../../alerting'; +import { RuleAlertType, isAlertTypes } from './types'; +import { findRules } from './find_rules'; + +export const DEFAULT_PER_PAGE: number = 100; + +export const getExistingPrepackagedRules = async ({ + alertsClient, + perPage = DEFAULT_PER_PAGE, +}: { + alertsClient: AlertsClient; + perPage?: number; +}): Promise => { + const firstPrepackedRules = await findRules({ + alertsClient, + filter: `alert.attributes.tags: "${INTERNAL_IMMUTABLE_KEY}:true"`, + perPage, + page: 1, + }); + const totalPages = Math.ceil(firstPrepackedRules.total / firstPrepackedRules.perPage); + if (totalPages <= 1) { + if (isAlertTypes(firstPrepackedRules.data)) { + return firstPrepackedRules.data; + } else { + // If this was ever true, you have a really messed up system. + // This is keep typescript happy since we have an unknown with data + return []; + } + } else { + const returnPrepackagedRules = await Array(totalPages - 1) + .fill({}) + .map((_, page) => { + // page index starts at 2 as we already got the first page and we have more pages to go + return findRules({ + alertsClient, + filter: `alert.attributes.tags: "${INTERNAL_IMMUTABLE_KEY}:true"`, + perPage, + page: page + 2, + }); + }) + .reduce>(async (accum, nextPage) => { + return [...(await accum), ...(await nextPage).data]; + }, Promise.resolve(firstPrepackedRules.data)); + + if (isAlertTypes(returnPrepackagedRules)) { + return returnPrepackagedRules; + } else { + // If this was ever true, you have a really messed up system. + // This is keep typescript happy since we have an unknown with data + return []; + } + } +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.test.ts new file mode 100644 index 00000000000000..24184b023bee3b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.test.ts @@ -0,0 +1,25 @@ +/* + * 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 { getPrepackagedRules } from './get_prepackaged_rules'; + +describe('get_existing_prepackaged_rules', () => { + test('should not throw any errors with the existing checked in pre-packaged rules', () => { + expect(() => getPrepackagedRules()).not.toThrow(); + }); + + test('should throw an exception if a pre-packaged rule is not valid', () => { + expect(() => getPrepackagedRules([{ not_valid_made_up_key: true }])).toThrow( + 'name: "(rule_name unknown)", rule_id: "(rule_id unknown)" within the folder rules/prepackaged_rules is not a valid detection engine rule. Expect the system to not work with pre-packaged rules until this rule is fixed or the file is removed. Error is: child "description" fails because ["description" is required]' + ); + }); + + test('should throw an exception with a message having rule_id and name in it', () => { + expect(() => getPrepackagedRules([{ name: 'rule name', rule_id: 'id-123' }])).toThrow( + 'name: "rule name", rule_id: "id-123" within the folder rules/prepackaged_rules is not a valid detection engine rule. Expect the system to not work with pre-packaged rules until this rule is fixed or the file is removed. Error is: child "description" fails because ["description" is required]' + ); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.ts new file mode 100644 index 00000000000000..376ad4eb287d5b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_prepackaged_rules.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 { RuleAlertParamsRest } from '../types'; +import { addPrepackagedRulesSchema } from '../routes/schemas/add_prepackaged_rules_schema'; +import { rawRules } from './prepackaged_rules'; + +/** + * Validate the rules from the file system and throw any errors indicating to the developer + * that they are adding incorrect schema rules. Also this will auto-flush in all the default + * aspects such as default interval of 5 minutes, default arrays, etc... + */ +export const validateAllPrepackagedRules = ( + rules: RuleAlertParamsRest[] +): RuleAlertParamsRest[] => { + return rules.map(rule => { + const validatedRule = addPrepackagedRulesSchema.validate(rule); + if (validatedRule.error != null) { + const ruleName = rule.name ? rule.name : '(rule_name unknown)'; + const ruleId = rule.rule_id ? rule.rule_id : '(rule_id unknown)'; + throw new TypeError( + `name: "${ruleName}", rule_id: "${ruleId}" within the folder rules/prepackaged_rules ` + + `is not a valid detection engine rule. Expect the system ` + + `to not work with pre-packaged rules until this rule is fixed ` + + `or the file is removed. Error is: ${validatedRule.error.message}` + ); + } else { + return validatedRule.value; + } + }); +}; + +export const getPrepackagedRules = (rules = rawRules): RuleAlertParamsRest[] => { + return validateAllPrepackagedRules(rules); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.test.ts new file mode 100644 index 00000000000000..1a2bd4a10ac2de --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.test.ts @@ -0,0 +1,67 @@ +/* + * 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 { getRulesToInstall } from './get_rules_to_install'; +import { getResult, fullRuleAlertParamsRest } from '../routes/__mocks__/request_responses'; + +describe('get_rules_to_install', () => { + test('should return empty array if both rule sets are empty', () => { + const update = getRulesToInstall([], []); + expect(update).toEqual([]); + }); + + test('should return empty array if the two rule ids match', () => { + const ruleFromFileSystem = fullRuleAlertParamsRest(); + ruleFromFileSystem.rule_id = 'rule-1'; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-1'; + const update = getRulesToInstall([ruleFromFileSystem], [installedRule]); + expect(update).toEqual([]); + }); + + test('should return the rule to install if the id of the two rules do not match', () => { + const ruleFromFileSystem = fullRuleAlertParamsRest(); + ruleFromFileSystem.rule_id = 'rule-1'; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-2'; + const update = getRulesToInstall([ruleFromFileSystem], [installedRule]); + expect(update).toEqual([ruleFromFileSystem]); + }); + + test('should return two rules to install if both the ids of the two rules do not match', () => { + const ruleFromFileSystem1 = fullRuleAlertParamsRest(); + ruleFromFileSystem1.rule_id = 'rule-1'; + + const ruleFromFileSystem2 = fullRuleAlertParamsRest(); + ruleFromFileSystem2.rule_id = 'rule-2'; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-3'; + const update = getRulesToInstall([ruleFromFileSystem1, ruleFromFileSystem2], [installedRule]); + expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]); + }); + + test('should return two rules of three to install if both the ids of the two rules do not match but the third does', () => { + const ruleFromFileSystem1 = fullRuleAlertParamsRest(); + ruleFromFileSystem1.rule_id = 'rule-1'; + + const ruleFromFileSystem2 = fullRuleAlertParamsRest(); + ruleFromFileSystem2.rule_id = 'rule-2'; + + const ruleFromFileSystem3 = fullRuleAlertParamsRest(); + ruleFromFileSystem3.rule_id = 'rule-3'; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-3'; + const update = getRulesToInstall( + [ruleFromFileSystem1, ruleFromFileSystem2, ruleFromFileSystem3], + [installedRule] + ); + expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.ts new file mode 100644 index 00000000000000..1c795941cbb837 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_install.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 { RuleAlertParamsRest } from '../types'; +import { RuleAlertType } from './types'; + +export const getRulesToInstall = ( + rulesFromFileSystem: RuleAlertParamsRest[], + installedRules: RuleAlertType[] +): RuleAlertParamsRest[] => { + return rulesFromFileSystem.filter( + rule => !installedRules.some(installedRule => installedRule.params.ruleId === rule.rule_id) + ); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.test.ts new file mode 100644 index 00000000000000..7f1b64d33cd9bf --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.test.ts @@ -0,0 +1,104 @@ +/* + * 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 { getRulesToUpdate } from './get_rules_to_update'; +import { getResult, fullRuleAlertParamsRest } from '../routes/__mocks__/request_responses'; + +describe('get_rules_to_update', () => { + test('should return empty array if both rule sets are empty', () => { + const update = getRulesToUpdate([], []); + expect(update).toEqual([]); + }); + + test('should return empty array if the id of the two rules do not match', () => { + const ruleFromFileSystem = fullRuleAlertParamsRest(); + ruleFromFileSystem.rule_id = 'rule-1'; + ruleFromFileSystem.version = 2; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-2'; + installedRule.params.version = 1; + const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]); + expect(update).toEqual([]); + }); + + test('should return empty array if the id of file system rule is less than the installed version', () => { + const ruleFromFileSystem = fullRuleAlertParamsRest(); + ruleFromFileSystem.rule_id = 'rule-1'; + ruleFromFileSystem.version = 1; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-1'; + installedRule.params.version = 2; + const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]); + expect(update).toEqual([]); + }); + + test('should return empty array if the id of file system rule is the same as the installed version', () => { + const ruleFromFileSystem = fullRuleAlertParamsRest(); + ruleFromFileSystem.rule_id = 'rule-1'; + ruleFromFileSystem.version = 1; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-1'; + installedRule.params.version = 1; + const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]); + expect(update).toEqual([]); + }); + + test('should return the rule to update if the id of file system rule is greater than the installed version', () => { + const ruleFromFileSystem = fullRuleAlertParamsRest(); + ruleFromFileSystem.rule_id = 'rule-1'; + ruleFromFileSystem.version = 2; + + const installedRule = getResult(); + installedRule.params.ruleId = 'rule-1'; + installedRule.params.version = 1; + const update = getRulesToUpdate([ruleFromFileSystem], [installedRule]); + expect(update).toEqual([ruleFromFileSystem]); + }); + + test('should return 1 rule out of 2 to update if the id of file system rule is greater than the installed version of just one', () => { + const ruleFromFileSystem = fullRuleAlertParamsRest(); + ruleFromFileSystem.rule_id = 'rule-1'; + ruleFromFileSystem.version = 2; + + const installedRule1 = getResult(); + installedRule1.params.ruleId = 'rule-1'; + installedRule1.params.version = 1; + + const installedRule2 = getResult(); + installedRule2.params.ruleId = 'rule-2'; + installedRule2.params.version = 1; + + const update = getRulesToUpdate([ruleFromFileSystem], [installedRule1, installedRule2]); + expect(update).toEqual([ruleFromFileSystem]); + }); + + test('should return 2 rules out of 2 to update if the id of file system rule is greater than the installed version of both', () => { + const ruleFromFileSystem1 = fullRuleAlertParamsRest(); + ruleFromFileSystem1.rule_id = 'rule-1'; + ruleFromFileSystem1.version = 2; + + const ruleFromFileSystem2 = fullRuleAlertParamsRest(); + ruleFromFileSystem2.rule_id = 'rule-2'; + ruleFromFileSystem2.version = 2; + + const installedRule1 = getResult(); + installedRule1.params.ruleId = 'rule-1'; + installedRule1.params.version = 1; + + const installedRule2 = getResult(); + installedRule2.params.ruleId = 'rule-2'; + installedRule2.params.version = 1; + + const update = getRulesToUpdate( + [ruleFromFileSystem1, ruleFromFileSystem2], + [installedRule1, installedRule2] + ); + expect(update).toEqual([ruleFromFileSystem1, ruleFromFileSystem2]); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.ts new file mode 100644 index 00000000000000..10b849493858a1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/get_rules_to_update.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 { RuleAlertParamsRest } from '../types'; +import { RuleAlertType } from './types'; + +export const getRulesToUpdate = ( + rulesFromFileSystem: RuleAlertParamsRest[], + installedRules: RuleAlertType[] +): RuleAlertParamsRest[] => { + return rulesFromFileSystem.filter(rule => + installedRules.some(installedRule => { + return ( + rule.rule_id === installedRule.params.ruleId && rule.version > installedRule.params.version + ); + }) + ); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts new file mode 100644 index 00000000000000..ec1e5eb6914e2d --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts @@ -0,0 +1,75 @@ +/* + * 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 { ActionsClient } from '../../../../../actions'; +import { AlertsClient } from '../../../../../alerting'; +import { createRules } from './create_rules'; +import { RuleAlertParamsRest } from '../types'; + +export const installPrepackagedRules = async ( + alertsClient: AlertsClient, + actionsClient: ActionsClient, + rules: RuleAlertParamsRest[], + outputIndex: string +): Promise => { + await rules.forEach(async rule => { + const { + description, + enabled, + false_positives: falsePositives, + from, + immutable, + query, + language, + saved_id: savedId, + meta, + filters, + rule_id: ruleId, + index, + interval, + max_signals: maxSignals, + risk_score: riskScore, + name, + severity, + tags, + to, + type, + threats, + references, + version, + } = rule; + createRules({ + alertsClient, + actionsClient, + description, + enabled, + falsePositives, + from, + immutable, + query, + language, + outputIndex, + savedId, + meta, + filters, + ruleId, + index, + interval, + maxSignals, + riskScore, + name, + severity, + tags, + to, + type, + threats, + references, + version, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }); + }); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_internet_explorer.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_internet_explorer.json new file mode 100644 index 00000000000000..1fd9fc0bb0d32c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_internet_explorer.json @@ -0,0 +1,68 @@ +{ + "rule_id": "a0b554d2-85ed-4998-ada3-4ca58b508b35", + "risk_score": 50, + "description": "Command shell started by Internet Explorer", + "immutable": true, + "interval": "5m", + "name": "Command shell started by Internet Explorer", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.parent.name:iexplore.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "process.name", + "value": "cmd.exe", + "params": { + "query": "cmd.exe" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "process.name": { + "query": "cmd.exe", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_powershell.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_powershell.json new file mode 100644 index 00000000000000..594e3d5f650f9d --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_powershell.json @@ -0,0 +1,68 @@ +{ + "rule_id": "ab4bbfa5-4127-40bf-852f-bdc6afdb2a06", + "risk_score": 50, + "description": "Command shell started by Powershell", + "immutable": true, + "interval": "5m", + "name": "Command shell started by Powershell", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.parent.name:powershell.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "process.name", + "value": "cmd.exe", + "params": { + "query": "cmd.exe" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "process.name": { + "query": "cmd.exe", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_svchost.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_svchost.json new file mode 100644 index 00000000000000..02f7516d5cd794 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/command_shell_started_by_svchost.json @@ -0,0 +1,68 @@ +{ + "rule_id": "2e4f8a5e-ce68-44e0-9243-1f57d44c4f30", + "risk_score": 50, + "description": "Command shell started by Svchost", + "immutable": true, + "interval": "5m", + "name": "Command shell started by Svchost", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.parent.name:svchost.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "process.name", + "value": "cmd.exe", + "params": { + "query": "cmd.exe" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "process.name": { + "query": "cmd.exe", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/index.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/index.ts new file mode 100644 index 00000000000000..406432bcbda001 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/index.ts @@ -0,0 +1,294 @@ +/* + * 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. + */ + +// Auto generated file from scripts/convert_saved_search_rules.js +// Do not hand edit. Run the script against a set of saved searches instead + +import rule1 from './windows_powershell_connecting_to_the_internet.json'; +import rule2 from './windows_net_user_command_activity.json'; +import rule3 from './windows_image_load_from_a_temp_directory.json'; +import rule4 from './network_ssh_secure_shell_to_the_internet.json'; +import rule5 from './suricata_nonhttp_traffic_on_tcp_port_80.json'; +import rule6 from './windows_misc_lolbin_connecting_to_the_internet.json'; +import rule7 from './linux_strace_activity.json'; +import rule8 from './suricata_directory_reversal_characters_in_an_http_request.json'; +import rule9 from './suricata_dns_traffic_on_unusual_udp_port.json'; +import rule10 from './network_telnet_port_activity.json'; +import rule11 from './suricata_directory_traversal_in_downloaded_zip_file.json'; +import rule12 from './windows_execution_via_microsoft_html_application_hta.json'; +import rule13 from './windows_credential_dumping_commands.json'; +import rule14 from './windows_net_command_activity_by_the_system_account.json'; +import rule15 from './windows_register_server_program_connecting_to_the_internet.json'; +import rule16 from './linux_java_process_connecting_to_the_internet.json'; +import rule17 from './suricata_imap_traffic_on_unusual_port_internet_destination.json'; +import rule18 from './suricata_double_encoded_characters_in_a_uri.json'; +import rule19 from './network_tor_activity_to_the_internet.json'; +import rule20 from './windows_registry_query_local.json'; +import rule21 from './linux_netcat_network_connection.json'; +import rule22 from './windows_defense_evasion_via_filter_manager.json'; +import rule23 from './suricata_nondns_traffic_on_udp_port_53.json'; +import rule24 from './suricata_double_encoded_characters_in_an_http_post.json'; +import rule25 from './command_shell_started_by_internet_explorer.json'; +import rule26 from './network_vnc_virtual_network_computing_from_the_internet.json'; +import rule27 from './windows_nmap_activity.json'; +import rule28 from './suspicious_process_started_by_a_script.json'; +import rule29 from './windows_network_anomalous_windows_process_using_https_ports.json'; +import rule30 from './powershell_network_connection.json'; +import rule31 from './windows_signed_binary_proxy_execution.json'; +import rule32 from './linux_kernel_module_activity.json'; +import rule33 from './network_vnc_virtual_network_computing_to_the_internet.json'; +import rule34 from './suricata_mimikatz_string_detected_in_http_response.json'; +import rule35 from './command_shell_started_by_svchost.json'; +import rule36 from './linux_tcpdump_activity.json'; +import rule37 from './process_started_by_ms_office_program_possible_payload.json'; +import rule38 from './windows_signed_binary_proxy_execution_download.json'; +import rule39 from './suricata_base64_encoded_startprocess_powershell_execution.json'; +import rule40 from './suricata_base64_encoded_invokecommand_powershell_execution.json'; +import rule41 from './suricata_directory_traversal_characters_in_http_response.json'; +import rule42 from './windows_microsoft_html_application_hta_connecting_to_the_internet.json'; +import rule43 from './suricata_tls_traffic_on_unusual_port_internet_destination.json'; +import rule44 from './process_started_by_acrobat_reader_possible_payload.json'; +import rule45 from './suricata_http_traffic_on_unusual_port_internet_destination.json'; +import rule46 from './windows_persistence_via_modification_of_existing_service.json'; +import rule47 from './windows_defense_evasion_or_persistence_via_hidden_files.json'; +import rule48 from './windows_execution_via_compiled_html_file.json'; +import rule49 from './linux_ptrace_activity.json'; +import rule50 from './suricata_nonimap_traffic_on_port_1443_imap.json'; +import rule51 from './windows_scheduled_task_activity.json'; +import rule52 from './suricata_ftp_traffic_on_unusual_port_internet_destination.json'; +import rule53 from './windows_wireshark_activity.json'; +import rule54 from './windows_execution_via_trusted_developer_utilities.json'; +import rule55 from './suricata_rpc_traffic_on_http_ports.json'; +import rule56 from './windows_process_discovery_via_tasklist_command.json'; +import rule57 from './suricata_cobaltstrike_artifact_in_an_dns_request.json'; +import rule58 from './suricata_serialized_php_detected.json'; +import rule59 from './windows_background_intelligent_transfer_service_bits_connecting_to_the_internet.json'; +import rule60 from './windows_registry_query_network.json'; +import rule61 from './windows_persistence_via_application_shimming.json'; +import rule62 from './network_proxy_port_activity_to_the_internet.json'; +import rule63 from './windows_whoami_command_activity.json'; +import rule64 from './suricata_shell_exec_php_function_in_an_http_post.json'; +import rule65 from './windump_activity.json'; +import rule66 from './windows_management_instrumentation_wmi_execution.json'; +import rule67 from './network_rdp_remote_desktop_protocol_from_the_internet.json'; +import rule68 from './windows_priv_escalation_via_accessibility_features.json'; +import rule69 from './psexec_activity.json'; +import rule70 from './linux_rawshark_activity.json'; +import rule71 from './suricata_nonftp_traffic_on_port_21.json'; +import rule72 from './network_ftp_file_transfer_protocol_activity_to_the_internet.json'; +import rule73 from './windows_certutil_connecting_to_the_internet.json'; +import rule74 from './suricata_nonsmb_traffic_on_tcp_port_139_smb.json'; +import rule75 from './network_rdp_remote_desktop_protocol_to_the_internet.json'; +import rule76 from './linux_whoami_commmand.json'; +import rule77 from './windows_persistence_or_priv_escalation_via_hooking.json'; +import rule78 from './linux_lzop_activity_possible_julianrunnels.json'; +import rule79 from './suricata_nontls_on_tls_port.json'; +import rule80 from './network_irc_internet_relay_chat_protocol_activity_to_the_internet.json'; +import rule81 from './linux_network_anomalous_process_using_https_ports.json'; +import rule82 from './windows_credential_dumping_via_registry_save.json'; +import rule83 from './network_rpc_remote_procedure_call_from_the_internet.json'; +import rule84 from './windows_credential_dumping_via_imageload.json'; +import rule85 from './windows_burp_ce_activity.json'; +import rule86 from './linux_hping_activity.json'; +import rule87 from './windows_command_prompt_connecting_to_the_internet.json'; +import rule88 from './network_nat_traversal_port_activity.json'; +import rule89 from './network_rpc_remote_procedure_call_to_the_internet.json'; +import rule90 from './suricata_possible_cobalt_strike_malleable_c2_null_response.json'; +import rule91 from './windows_remote_management_execution.json'; +import rule92 from './suricata_lazagne_artifact_in_an_http_post.json'; +import rule93 from './windows_netcat_network_activity.json'; +import rule94 from './windows_iodine_activity.json'; +import rule95 from './network_port_26_activity.json'; +import rule96 from './windows_execution_via_connection_manager.json'; +import rule97 from './linux_process_started_in_temp_directory.json'; +import rule98 from './suricata_eval_php_function_in_an_http_request.json'; +import rule99 from './linux_web_download.json'; +import rule100 from './suricata_ssh_traffic_not_on_port_22_internet_destination.json'; +import rule101 from './network_port_8000_activity.json'; +import rule102 from './windows_process_started_by_the_java_runtime.json'; +import rule103 from './suricata_possible_sql_injection_sql_commands_in_http_transactions.json'; +import rule104 from './network_smb_windows_file_sharing_activity_to_the_internet.json'; +import rule105 from './network_port_8000_activity_to_the_internet.json'; +import rule106 from './command_shell_started_by_powershell.json'; +import rule107 from './linux_nmap_activity.json'; +import rule108 from './search_windows_10.json'; +import rule109 from './network_smtp_to_the_internet.json'; +import rule110 from './windows_payload_obfuscation_via_certutil.json'; +import rule111 from './network_pptp_point_to_point_tunneling_protocol_activity.json'; +import rule112 from './linux_unusual_shell_activity.json'; +import rule113 from './linux_mknod_activity.json'; +import rule114 from './network_sql_server_port_activity_to_the_internet.json'; +import rule115 from './suricata_commonly_abused_dns_domain_detected.json'; +import rule116 from './linux_iodine_activity.json'; +import rule117 from './suricata_mimikatz_artifacts_in_an_http_post.json'; +import rule118 from './windows_execution_via_net_com_assemblies.json'; +import rule119 from './suricata_dns_traffic_on_unusual_tcp_port.json'; +import rule120 from './suricata_base64_encoded_newobject_powershell_execution.json'; +import rule121 from './windows_netcat_activity.json'; +import rule122 from './windows_persistence_via_bits_jobs.json'; +import rule123 from './linux_nping_activity.json'; +import rule124 from './windows_execution_via_regsvr32.json'; +import rule125 from './process_started_by_windows_defender.json'; +import rule126 from './windows_indirect_command_execution.json'; +import rule127 from './network_ssh_secure_shell_from_the_internet.json'; +import rule128 from './windows_html_help_executable_program_connecting_to_the_internet.json'; +import rule129 from './suricata_windows_executable_served_by_jpeg_web_content.json'; +import rule130 from './network_dns_directly_to_the_internet.json'; +import rule131 from './windows_defense_evasion_via_windows_event_log_tools.json'; +import rule132 from './suricata_nondns_traffic_on_tcp_port_53.json'; +import rule133 from './windows_persistence_via_netshell_helper_dll.json'; +import rule134 from './windows_script_interpreter_connecting_to_the_internet.json'; +import rule135 from './windows_defense_evasion_decoding_using_certutil.json'; +import rule136 from './linux_shell_activity_by_web_server.json'; +import rule137 from './linux_ldso_process_activity.json'; +import rule138 from './windows_mimikatz_activity.json'; +import rule139 from './suricata_nonssh_traffic_on_port_22.json'; +import rule140 from './windows_data_compression_using_powershell.json'; +import rule141 from './windows_nmap_scan_activity.json'; + +export const rawRules = [ + rule1, + rule2, + rule3, + rule4, + rule5, + rule6, + rule7, + rule8, + rule9, + rule10, + rule11, + rule12, + rule13, + rule14, + rule15, + rule16, + rule17, + rule18, + rule19, + rule20, + rule21, + rule22, + rule23, + rule24, + rule25, + rule26, + rule27, + rule28, + rule29, + rule30, + rule31, + rule32, + rule33, + rule34, + rule35, + rule36, + rule37, + rule38, + rule39, + rule40, + rule41, + rule42, + rule43, + rule44, + rule45, + rule46, + rule47, + rule48, + rule49, + rule50, + rule51, + rule52, + rule53, + rule54, + rule55, + rule56, + rule57, + rule58, + rule59, + rule60, + rule61, + rule62, + rule63, + rule64, + rule65, + rule66, + rule67, + rule68, + rule69, + rule70, + rule71, + rule72, + rule73, + rule74, + rule75, + rule76, + rule77, + rule78, + rule79, + rule80, + rule81, + rule82, + rule83, + rule84, + rule85, + rule86, + rule87, + rule88, + rule89, + rule90, + rule91, + rule92, + rule93, + rule94, + rule95, + rule96, + rule97, + rule98, + rule99, + rule100, + rule101, + rule102, + rule103, + rule104, + rule105, + rule106, + rule107, + rule108, + rule109, + rule110, + rule111, + rule112, + rule113, + rule114, + rule115, + rule116, + rule117, + rule118, + rule119, + rule120, + rule121, + rule122, + rule123, + rule124, + rule125, + rule126, + rule127, + rule128, + rule129, + rule130, + rule131, + rule132, + rule133, + rule134, + rule135, + rule136, + rule137, + rule138, + rule139, + rule140, + rule141, +]; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_hping_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_hping_activity.json new file mode 100644 index 00000000000000..92308283717a54 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_hping_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "90169566-2260-4824-b8e4-8615c3b4ed52", + "risk_score": 50, + "description": "Linux: Hping Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Hping Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: hping", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_iodine_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_iodine_activity.json new file mode 100644 index 00000000000000..ded4b72fcbfc48 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_iodine_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "041d4d41-9589-43e2-ba13-5680af75ebc2", + "risk_score": 50, + "description": "Linux: Iodine Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Iodine Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: (iodine or iodined)", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_java_process_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_java_process_connecting_to_the_internet.json new file mode 100644 index 00000000000000..aba4954e3552a6 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_java_process_connecting_to_the_internet.json @@ -0,0 +1,118 @@ +{ + "rule_id": "7f65b8c5-27ed-4cf6-a088-3a20d2f84bf5", + "risk_score": 50, + "description": "Linux: Java Process Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Linux: Java Process Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "not destination.ip: 10.0.0.0/8 and not 172.16.0.0/12", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "process.name", + "value": "java", + "params": { + "query": "java" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "process.name": { + "query": "java", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "socket_opened", + "params": { + "query": "socket_opened" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "socket_opened", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": true, + "type": "phrase", + "key": "destination.ip", + "value": "127.0.0.1", + "params": { + "query": "127.0.0.1" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index" + }, + "query": { + "match": { + "destination.ip": { + "query": "127.0.0.1", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": true, + "type": "phrase", + "key": "destination.ip", + "value": "::1", + "params": { + "query": "::1" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[3].meta.index" + }, + "query": { + "match": { + "destination.ip": { + "query": "::1", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_kernel_module_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_kernel_module_activity.json new file mode 100644 index 00000000000000..4564d1afccf79c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_kernel_module_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "81cc58f5-8062-49a2-ba84-5cc4b4d31c40", + "risk_score": 50, + "description": "Linux: Kernel Module Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Kernel Module Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: (insmod or kmod or modprobe or rmod)", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ldso_process_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ldso_process_activity.json new file mode 100644 index 00000000000000..2db76834061b96 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ldso_process_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "3f31a31c-f7cf-4268-a0df-ec1a98099e7f", + "risk_score": 50, + "description": "Linux ld.so process activity", + "immutable": true, + "interval": "5m", + "name": "Linux ld.so process activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:ld.so", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_lzop_activity_possible_julianrunnels.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_lzop_activity_possible_julianrunnels.json new file mode 100644 index 00000000000000..5b3a978813b79f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_lzop_activity_possible_julianrunnels.json @@ -0,0 +1,17 @@ +{ + "rule_id": "d89b05b1-9b2b-45ea-9876-4a74550af6a6", + "risk_score": 50, + "description": "Linux lzop activity - possible @JulianRunnels", + "immutable": true, + "interval": "5m", + "name": "Linux lzop activity - possible @JulianRunnels", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:lzop", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_mknod_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_mknod_activity.json new file mode 100644 index 00000000000000..04ddc409c1efe7 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_mknod_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "61c31c14-507f-4627-8c31-072556b89a9c", + "risk_score": 50, + "description": "Linux: Mknod Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Mknod Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: mknod", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_netcat_network_connection.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_netcat_network_connection.json new file mode 100644 index 00000000000000..1ba35bec8f5174 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_netcat_network_connection.json @@ -0,0 +1,93 @@ +{ + "rule_id": "adb961e0-cb74-42a0-af9e-29fc41f88f5f", + "risk_score": 50, + "description": "Linux: Netcat Network Connection", + "immutable": true, + "interval": "5m", + "name": "Linux: Netcat Network Connection", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: (nc or ncat or netcat or netcat.openbsd or netcat.traditional)", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "socket_opened", + "params": { + "query": "socket_opened" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "socket_opened", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": true, + "type": "phrase", + "key": "destination.ip", + "value": "127.0.0.1", + "params": { + "query": "127.0.0.1" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "destination.ip": { + "query": "127.0.0.1", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": true, + "type": "phrase", + "key": "destination.ip", + "value": "::1", + "params": { + "query": "::1" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index" + }, + "query": { + "match": { + "destination.ip": { + "query": "::1", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_network_anomalous_process_using_https_ports.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_network_anomalous_process_using_https_ports.json new file mode 100644 index 00000000000000..d5bf37daab0f48 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_network_anomalous_process_using_https_ports.json @@ -0,0 +1,17 @@ +{ + "rule_id": "be40c674-1799-4a00-934d-0b2d54495913", + "risk_score": 50, + "description": "Linux Network - Anomalous Process Using HTTP/S Ports", + "immutable": true, + "interval": "5m", + "name": "Linux Network - Anomalous Process Using HTTP/S Ports", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(destination.port:443 or destination.port:80) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16 and not process.name:curl and not process.name:http and not process.name:https and not process.name:nginx and not process.name:packetbeat and not process.name:python2 and not process.name:snapd and not process.name:wget", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nmap_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nmap_activity.json new file mode 100644 index 00000000000000..430d6b6984d6cd --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nmap_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "c87fca17-b3a9-4e83-b545-f30746c53920", + "risk_score": 50, + "description": "Linux: Nmap Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Nmap Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: nmap", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nping_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nping_activity.json new file mode 100644 index 00000000000000..a87f42f1774bf0 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_nping_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "0d69150b-96f8-467c-a86d-a67a3378ce77", + "risk_score": 50, + "description": "Linux: Nping Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Nping Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: nmap", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_process_started_in_temp_directory.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_process_started_in_temp_directory.json new file mode 100644 index 00000000000000..2a83ff8c5d2c66 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_process_started_in_temp_directory.json @@ -0,0 +1,68 @@ +{ + "rule_id": "df959768-b0c9-4d45-988c-5606a2be8e5a", + "risk_score": 50, + "description": "Linux: Process Started in Temp Directory", + "immutable": true, + "interval": "5m", + "name": "Linux: Process Started in Temp Directory", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.working_directory: /tmp", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ptrace_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ptrace_activity.json new file mode 100644 index 00000000000000..0ac4365ae8b7ea --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_ptrace_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "1bff9259-e160-4920-bf72-4c96b6dbb7af", + "risk_score": 50, + "description": "Linux: Ptrace Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Ptrace Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: ptrace", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_rawshark_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_rawshark_activity.json new file mode 100644 index 00000000000000..ff74ba8e51b87a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_rawshark_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "30eb2b9d-b53b-4ba5-bfab-7119a8b84029", + "risk_score": 50, + "description": "Linux: Rawshark Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Rawshark Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: rawshark", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_shell_activity_by_web_server.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_shell_activity_by_web_server.json new file mode 100644 index 00000000000000..7499f6bc17ac16 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_shell_activity_by_web_server.json @@ -0,0 +1,17 @@ +{ + "rule_id": "231876e7-4d1f-4d63-a47c-47dd1acdc1cb", + "risk_score": 50, + "description": "Linux: Shell Activity By Web Server", + "immutable": true, + "interval": "5m", + "name": "Linux: Shell Activity By Web Server", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: bash and (user.name: apache or www)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_strace_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_strace_activity.json new file mode 100644 index 00000000000000..5c813fbb62eb7e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_strace_activity.json @@ -0,0 +1,68 @@ +{ + "rule_id": "d6450d4e-81c6-46a3-bd94-079886318ed5", + "risk_score": 50, + "description": "Linux: Strace Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Strace Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: strace", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_tcpdump_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_tcpdump_activity.json new file mode 100644 index 00000000000000..1df4ad8b469b91 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_tcpdump_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "7a137d76-ce3d-48e2-947d-2747796a78c0", + "risk_score": 50, + "description": "Linux: Tcpdump Activity", + "immutable": true, + "interval": "5m", + "name": "Linux: Tcpdump Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: tcpdump", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_unusual_shell_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_unusual_shell_activity.json new file mode 100644 index 00000000000000..efa84c22f928c8 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_unusual_shell_activity.json @@ -0,0 +1,93 @@ +{ + "rule_id": "4cc78842-f8a9-4a20-b703-a596c4f24e4f", + "risk_score": 50, + "description": "Linux unusual shell activity", + "immutable": true, + "interval": "5m", + "name": "Linux unusual shell activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:*sh", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": true, + "type": "phrase", + "key": "process.name", + "value": "bash", + "params": { + "query": "bash" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "process.name": { + "query": "bash", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": true, + "type": "phrase", + "key": "process.executable", + "value": "/bin/dash", + "params": { + "query": "/bin/dash" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "process.executable": { + "query": "/bin/dash", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": true, + "type": "phrase", + "key": "process.name", + "value": "ReportCrash", + "params": { + "query": "ReportCrash" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[2].meta.index" + }, + "query": { + "match": { + "process.name": { + "query": "ReportCrash", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_web_download.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_web_download.json new file mode 100644 index 00000000000000..d9ee2ccc98f109 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_web_download.json @@ -0,0 +1,43 @@ +{ + "rule_id": "e8ec93a6-49d2-4467-8c12-81c435fcc519", + "risk_score": 50, + "description": "Linux: Web Download", + "immutable": true, + "interval": "5m", + "name": "Linux: Web Download", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: curl or wget", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "socket_opened", + "params": { + "query": "socket_opened" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "socket_opened", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_whoami_commmand.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_whoami_commmand.json new file mode 100644 index 00000000000000..47c01778786c27 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_whoami_commmand.json @@ -0,0 +1,68 @@ +{ + "rule_id": "120559c6-5e24-49f4-9e30-8ffe697df6b9", + "risk_score": 50, + "description": "Linux: Whoami Commmand", + "immutable": true, + "interval": "5m", + "name": "Linux: Whoami Commmand", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name: whoami", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "process_started", + "params": { + "query": "process_started" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "process_started", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.dataset", + "value": "process", + "params": { + "query": "process" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.dataset": { + "query": "process", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_dns_directly_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_dns_directly_to_the_internet.json new file mode 100644 index 00000000000000..3dfbb508b897f8 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_dns_directly_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "6ea71ff0-9e95-475b-9506-2580d1ce6154", + "risk_score": 50, + "description": "Network - DNS Directly to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - DNS Directly to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:53 and not destination.ip: 169.254.169.254/32 and not destination.ip:127.0.0.53/32 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ftp_file_transfer_protocol_activity_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ftp_file_transfer_protocol_activity_to_the_internet.json new file mode 100644 index 00000000000000..7462fd445d1ec1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ftp_file_transfer_protocol_activity_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "87ec6396-9ac4-4706-bcf0-2ebb22002f43", + "risk_score": 50, + "description": "Network - FTP (File Transfer Protocol) Activity to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - FTP (File Transfer Protocol) Activity to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(destination.port:20 or destination.port:21) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_irc_internet_relay_chat_protocol_activity_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_irc_internet_relay_chat_protocol_activity_to_the_internet.json new file mode 100644 index 00000000000000..dee04ee4fea8a5 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_irc_internet_relay_chat_protocol_activity_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "c6474c34-4953-447a-903e-9fcb7b6661aa", + "risk_score": 50, + "description": "Network - IRC (Internet Relay Chat) Protocol Activity to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - IRC (Internet Relay Chat) Protocol Activity to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(destination.port:6665 or destination.port:6666 or destination.port:6667 or destination.port:6668 or destination.port:6669) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_nat_traversal_port_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_nat_traversal_port_activity.json new file mode 100644 index 00000000000000..6363dd7529cd6e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_nat_traversal_port_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "a9cb3641-ff4b-4cdc-a063-b4b8d02a67c7", + "risk_score": 50, + "description": "Network - NAT Traversal Port Activity\t", + "immutable": true, + "interval": "5m", + "name": "Network - NAT Traversal Port Activity\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:4500", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_26_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_26_activity.json new file mode 100644 index 00000000000000..bda9984167718f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_26_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "d7e62693-aab9-4f66-a21a-3d79ecdd603d", + "risk_score": 50, + "description": "Network - Port 26 Activity\t", + "immutable": true, + "interval": "5m", + "name": "Network - Port 26 Activity\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:26", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity.json new file mode 100644 index 00000000000000..efd92f988fd2bc --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "9c5f8092-e3f7-4eda-b9d3-56eed28fb157", + "risk_score": 50, + "description": "Network - Port 8000 Activity", + "immutable": true, + "interval": "5m", + "name": "Network - Port 8000 Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:8000", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity_to_the_internet.json new file mode 100644 index 00000000000000..790773f5308bb6 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_port_8000_activity_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "08d5d7e2-740f-44d8-aeda-e41f4263efaf", + "risk_score": 50, + "description": "Network - Port 8000 Activity to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - Port 8000 Activity to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:8000 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_pptp_point_to_point_tunneling_protocol_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_pptp_point_to_point_tunneling_protocol_activity.json new file mode 100644 index 00000000000000..f22a23648a7fa4 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_pptp_point_to_point_tunneling_protocol_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "d2053495-8fe7-4168-b3df-dad844046be3", + "risk_score": 50, + "description": "Network - PPTP (Point to Point Tunneling Protocol) Activity\t", + "immutable": true, + "interval": "5m", + "name": "Network - PPTP (Point to Point Tunneling Protocol) Activity\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:1723", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_proxy_port_activity_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_proxy_port_activity_to_the_internet.json new file mode 100644 index 00000000000000..e7cc9b2b07cfdd --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_proxy_port_activity_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "ad0e5e75-dd89-4875-8d0a-dfdc1828b5f3", + "risk_score": 50, + "description": "Network - Proxy Port Activity to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - Proxy Port Activity to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(destination.port:8080 or destination.port:3128) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_from_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_from_the_internet.json new file mode 100644 index 00000000000000..c5a16bfef72486 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_from_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "8c1bdde8-4204-45c0-9e0c-c85ca3902488", + "risk_score": 50, + "description": "Network - RDP (Remote Desktop Protocol) from the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - RDP (Remote Desktop Protocol) from the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:3389 and not source.ip:10.0.0.0/8 and not source.ip:172.16.0.0/12 and not source.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_to_the_internet.json new file mode 100644 index 00000000000000..b069bd5e3ca67f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rdp_remote_desktop_protocol_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "e56993d2-759c-4120-984c-9ec9bb940fd5", + "risk_score": 50, + "description": "Network - RDP (Remote Desktop Protocol) to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - RDP (Remote Desktop Protocol) to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:3389 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_from_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_from_the_internet.json new file mode 100644 index 00000000000000..bef842ec2adc35 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_from_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "143cb236-0956-4f42-a706-814bcaa0cf5a", + "risk_score": 50, + "description": "Network - RPC (Remote Procedure Call) from the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - RPC (Remote Procedure Call) from the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:3389 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_to_the_internet.json new file mode 100644 index 00000000000000..15184aee86edb8 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_rpc_remote_procedure_call_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "32923416-763a-4531-bb35-f33b9232ecdb", + "risk_score": 50, + "description": "Network - RPC (Remote Procedure Call) to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - RPC (Remote Procedure Call) to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:135 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smb_windows_file_sharing_activity_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smb_windows_file_sharing_activity_to_the_internet.json new file mode 100644 index 00000000000000..365490792ed377 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smb_windows_file_sharing_activity_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "c82b2bd8-d701-420c-ba43-f11a155b681a", + "risk_score": 50, + "description": "Network - SMB (Windows File Sharing) Activity to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - SMB (Windows File Sharing) Activity to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(destination.port:139 or destination.port:445) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smtp_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smtp_to_the_internet.json new file mode 100644 index 00000000000000..b16e84e8cea742 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_smtp_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "67a9beba-830d-4035-bfe8-40b7e28f8ac4", + "risk_score": 50, + "description": "Network - SMTP to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - SMTP to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:25 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_sql_server_port_activity_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_sql_server_port_activity_to_the_internet.json new file mode 100644 index 00000000000000..4e884f0de11673 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_sql_server_port_activity_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "139c7458-566a-410c-a5cd-f80238d6a5cd", + "risk_score": 50, + "description": "Network - SQL Server Port Activity to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - SQL Server Port Activity to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:1433 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_from_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_from_the_internet.json new file mode 100644 index 00000000000000..f7340b710be358 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_from_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "ea0784f0-a4d7-4fea-ae86-4baaf27a6f17", + "risk_score": 50, + "description": "Network - SSH (Secure Shell) from the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - SSH (Secure Shell) from the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:22 and not source.ip:10.0.0.0/8 and not source.ip:172.16.0.0/12 and not source.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_to_the_internet.json new file mode 100644 index 00000000000000..21877b9716aaeb --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_ssh_secure_shell_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "6f1500bc-62d7-4eb9-8601-7485e87da2f4", + "risk_score": 50, + "description": "Network - SSH (Secure Shell) to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - SSH (Secure Shell) to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:22 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_telnet_port_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_telnet_port_activity.json new file mode 100644 index 00000000000000..2d917277bcb85e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_telnet_port_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "34fde489-94b0-4500-a76f-b8a157cf9269", + "risk_score": 50, + "description": "Network - Telnet Port Activity\t", + "immutable": true, + "interval": "5m", + "name": "Network - Telnet Port Activity\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:23", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_tor_activity_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_tor_activity_to_the_internet.json new file mode 100644 index 00000000000000..991cc02a2123fa --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_tor_activity_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "7d2c38d7-ede7-4bdf-b140-445906e6c540", + "risk_score": 50, + "description": "Network - Tor Activity to the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - Tor Activity to the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(destination.port:9001 or destination.port:9030) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_from_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_from_the_internet.json new file mode 100644 index 00000000000000..5fbffa0149783a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_from_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "5700cb81-df44-46aa-a5d7-337798f53eb8", + "risk_score": 50, + "description": "Network - VNC (Virtual Network Computing) From the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - VNC (Virtual Network Computing) From the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:5800 and not source.ip:10.0.0.0/8 and not source.ip:172.16.0.0/12 and not source.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_to_the_internet.json new file mode 100644 index 00000000000000..9d3608cb9e05df --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/network_vnc_virtual_network_computing_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "3ad49c61-7adc-42c1-b788-732eda2f5abf", + "risk_score": 50, + "description": "Network - VNC (Virtual Network Computing) To the Internet\t", + "immutable": true, + "interval": "5m", + "name": "Network - VNC (Virtual Network Computing) To the Internet\t", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "destination.port:5800 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/powershell_network_connection.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/powershell_network_connection.json new file mode 100644 index 00000000000000..ba86dd5bdf1dbb --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/powershell_network_connection.json @@ -0,0 +1,68 @@ +{ + "rule_id": "8e792144-39a6-4a63-9779-2f12719dc132", + "risk_score": 50, + "description": "Powershell network connection", + "immutable": true, + "interval": "5m", + "name": "Powershell network connection", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:powershell.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Network connection detected (rule: NetworkConnect)", + "params": { + "query": "Network connection detected (rule: NetworkConnect)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Network connection detected (rule: NetworkConnect)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + }, + { + "meta": { + "negate": true, + "type": "phrase", + "key": "destination.ip", + "value": "169.254.169.254", + "params": { + "query": "169.254.169.254" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "destination.ip": { + "query": "169.254.169.254", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_acrobat_reader_possible_payload.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_acrobat_reader_possible_payload.json new file mode 100644 index 00000000000000..99968dbdcc00db --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_acrobat_reader_possible_payload.json @@ -0,0 +1,43 @@ +{ + "rule_id": "c359628d-d5af-4a20-99df-aeeea109b690", + "risk_score": 50, + "description": "Process started by Acrobat reader - possible payload", + "immutable": true, + "interval": "5m", + "name": "Process started by Acrobat reader - possible payload", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.parent.name:AcroRd32.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_ms_office_program_possible_payload.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_ms_office_program_possible_payload.json new file mode 100644 index 00000000000000..9241a2a44eb069 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_ms_office_program_possible_payload.json @@ -0,0 +1,43 @@ +{ + "rule_id": "3181b814-08e3-43f9-b77a-a2530603b131", + "risk_score": 50, + "description": "Process started by MS Office program - possible payload", + "immutable": true, + "interval": "5m", + "name": "Process started by MS Office program - possible payload", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": " process.parent.name:EXCEL.EXE or process.parent.name:MSPUB.EXE or process.parent.name:OUTLOOK.EXE or process.parent.name:POWERPNT.EXE or process.parent.name:VISIO.EXE or process.parent.name:WINWORD.EXE", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_windows_defender.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_windows_defender.json new file mode 100644 index 00000000000000..3f1dc90c99c97e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/process_started_by_windows_defender.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b3da3321-417d-494b-854c-b40369e063f0", + "risk_score": 50, + "description": "Process started by Windows Defender", + "immutable": true, + "interval": "5m", + "name": "Process started by Windows Defender", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "parent.process.name:MsMpEng.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/psexec_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/psexec_activity.json new file mode 100644 index 00000000000000..3797b44c6d9670 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/psexec_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "9511b7f4-3898-4813-8bd3-d810b03148ab", + "risk_score": 50, + "description": "PSexec activity", + "immutable": true, + "interval": "5m", + "name": "PSexec activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:PsExec.exe or process.name:PsExec64.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/search_windows_10.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/search_windows_10.json new file mode 100644 index 00000000000000..86c1c36f4b832c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/search_windows_10.json @@ -0,0 +1,66 @@ +{ + "rule_id": "5d00c579-794c-4f64-be52-1ed8cae2b11e", + "risk_score": 50, + "description": "(Search) Windows 10", + "immutable": true, + "interval": "5m", + "name": "(Search) Windows 10", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "", + "language": "kuery", + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "key": "agent.hostname", + "negate": false, + "params": { + "query": "LAPTOP-CQNI37L2" + }, + "type": "phrase", + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "agent.hostname": { + "query": "LAPTOP-CQNI37L2", + "type": "phrase" + } + } + } + }, + { + "meta": { + "alias": null, + "negate": false, + "disabled": false, + "type": "phrase", + "key": "event.provider", + "params": { + "query": "Microsoft-Windows-Sysmon" + }, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index" + }, + "query": { + "match": { + "event.provider": { + "query": "Microsoft-Windows-Sysmon", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_invokecommand_powershell_execution.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_invokecommand_powershell_execution.json new file mode 100644 index 00000000000000..332f174cad2cf8 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_invokecommand_powershell_execution.json @@ -0,0 +1,17 @@ +{ + "rule_id": "6ff01a30-95dd-471c-b61d-0fd9ee2d0a20", + "risk_score": 50, + "description": "Suricata Base64 Encoded Invoke-Command Powershell Execution", + "immutable": true, + "interval": "5m", + "name": "Suricata Base64 Encoded Invoke-Command Powershell Execution", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610182 or 2610183 or 2610184 or 2610185 or 2610186 or 2610187)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_newobject_powershell_execution.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_newobject_powershell_execution.json new file mode 100644 index 00000000000000..a86f7fa07e7d99 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_newobject_powershell_execution.json @@ -0,0 +1,17 @@ +{ + "rule_id": "d14d5401-0f7a-4933-b816-1b8f823e3d84", + "risk_score": 50, + "description": "Suricata Base64 Encoded New-Object Powershell Execution", + "immutable": true, + "interval": "5m", + "name": "Suricata Base64 Encoded New-Object Powershell Execution", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610188 or 2610189 or 2610190 or 2610191 or 2610192 or 2610193)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_startprocess_powershell_execution.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_startprocess_powershell_execution.json new file mode 100644 index 00000000000000..722ce65dd83e8b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_base64_encoded_startprocess_powershell_execution.json @@ -0,0 +1,17 @@ +{ + "rule_id": "372dce88-003d-4bcf-8c95-34ea8be180a1", + "risk_score": 50, + "description": "Suricata Base64 Encoded Start-Process Powershell Execution", + "immutable": true, + "interval": "5m", + "name": "Suricata Base64 Encoded Start-Process Powershell Execution", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610194 or 2610195 or 2610196 or 2610197 or 2610198 or 2610199)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_cobaltstrike_artifact_in_an_dns_request.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_cobaltstrike_artifact_in_an_dns_request.json new file mode 100644 index 00000000000000..bffcd182358398 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_cobaltstrike_artifact_in_an_dns_request.json @@ -0,0 +1,17 @@ +{ + "rule_id": "481ef0f5-beda-4fa2-8bfb-039c95500deb", + "risk_score": 50, + "description": "Suricata CobaltStrike Artifact in an DNS Request", + "immutable": true, + "interval": "5m", + "name": "Suricata CobaltStrike Artifact in an DNS Request", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610166 or 2610167 or 2610168)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_commonly_abused_dns_domain_detected.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_commonly_abused_dns_domain_detected.json new file mode 100644 index 00000000000000..334a632697a817 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_commonly_abused_dns_domain_detected.json @@ -0,0 +1,17 @@ +{ + "rule_id": "1844dfe1-b05e-4ca6-b367-6b9e3a1fe227", + "risk_score": 50, + "description": "Suricata Commonly Abused DNS Domain Detected", + "immutable": true, + "interval": "5m", + "name": "Suricata Commonly Abused DNS Domain Detected", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature:(TGI* and *HUNT* and *Abused* and *TLD*) and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_reversal_characters_in_an_http_request.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_reversal_characters_in_an_http_request.json new file mode 100644 index 00000000000000..098b873210d6fa --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_reversal_characters_in_an_http_request.json @@ -0,0 +1,17 @@ +{ + "rule_id": "c0ca8090-60f8-4458-befe-c43687b648a3", + "risk_score": 50, + "description": "Suricata Directory Reversal Characters in an HTTP Request", + "immutable": true, + "interval": "5m", + "name": "Suricata Directory Reversal Characters in an HTTP Request", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610161 or 2610162)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_characters_in_http_response.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_characters_in_http_response.json new file mode 100644 index 00000000000000..3da22fcb912a88 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_characters_in_http_response.json @@ -0,0 +1,17 @@ +{ + "rule_id": "a6406974-ea70-45b5-b5d8-ca17695adbde", + "risk_score": 50, + "description": "Suricata Directory Traversal Characters in HTTP Response", + "immutable": true, + "interval": "5m", + "name": "Suricata Directory Traversal Characters in HTTP Response", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610086 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_in_downloaded_zip_file.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_in_downloaded_zip_file.json new file mode 100644 index 00000000000000..370f9f6ba83fc4 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_directory_traversal_in_downloaded_zip_file.json @@ -0,0 +1,17 @@ +{ + "rule_id": "d5d990bc-303c-4241-8138-6ba3cf2ee93e", + "risk_score": 50, + "description": "Suricata Directory Traversal in Downloaded Zip File", + "immutable": true, + "interval": "5m", + "name": "Suricata Directory Traversal in Downloaded Zip File", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610085 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_tcp_port.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_tcp_port.json new file mode 100644 index 00000000000000..9389897a95b872 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_tcp_port.json @@ -0,0 +1,17 @@ +{ + "rule_id": "deeae336-4ff7-4cf8-ae5b-18bce05da02e", + "risk_score": 50, + "description": "Suricata DNS Traffic on Unusual TCP Port", + "immutable": true, + "interval": "5m", + "name": "Suricata DNS Traffic on Unusual TCP Port", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610013 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_udp_port.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_udp_port.json new file mode 100644 index 00000000000000..a6bcf664bf803f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_dns_traffic_on_unusual_udp_port.json @@ -0,0 +1,17 @@ +{ + "rule_id": "2343d9a4-365b-45b2-acb0-76934d43c75b", + "risk_score": 50, + "description": "Suricata DNS Traffic on Unusual UDP Port", + "immutable": true, + "interval": "5m", + "name": "Suricata DNS Traffic on Unusual UDP Port", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610015 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_a_uri.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_a_uri.json new file mode 100644 index 00000000000000..005156b68ba982 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_a_uri.json @@ -0,0 +1,17 @@ +{ + "rule_id": "1ed4d2d1-330c-4c7d-b32d-2d8805437946", + "risk_score": 50, + "description": "Suricata Double Encoded Characters in a URI", + "immutable": true, + "interval": "5m", + "name": "Suricata Double Encoded Characters in a URI", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610092 or 2610093 or 2610094 or 2610095)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_an_http_post.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_an_http_post.json new file mode 100644 index 00000000000000..2ff186a4026bba --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_double_encoded_characters_in_an_http_post.json @@ -0,0 +1,17 @@ +{ + "rule_id": "a839a360-94ae-4219-b1cc-458d836333a7", + "risk_score": 50, + "description": "Suricata Double Encoded Characters in an HTTP POST", + "immutable": true, + "interval": "5m", + "name": "Suricata Double Encoded Characters in an HTTP POST", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610090 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_eval_php_function_in_an_http_request.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_eval_php_function_in_an_http_request.json new file mode 100644 index 00000000000000..16f47eb0ba663d --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_eval_php_function_in_an_http_request.json @@ -0,0 +1,17 @@ +{ + "rule_id": "8c77b4ed-4e98-438b-adb0-d645d4a4ea26", + "risk_score": 50, + "description": "Suricata eval PHP Function in an HTTP Request", + "immutable": true, + "interval": "5m", + "name": "Suricata eval PHP Function in an HTTP Request", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610088 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ftp_traffic_on_unusual_port_internet_destination.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ftp_traffic_on_unusual_port_internet_destination.json new file mode 100644 index 00000000000000..40ada9bb874259 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ftp_traffic_on_unusual_port_internet_destination.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b1adc850-0fe3-4dac-94d3-6f240071f83a", + "risk_score": 50, + "description": "Suricata FTP Traffic on Unusual Port, Internet Destination", + "immutable": true, + "interval": "5m", + "name": "Suricata FTP Traffic on Unusual Port, Internet Destination", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610005 and (event.module:suricata and event.kind:alert) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_http_traffic_on_unusual_port_internet_destination.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_http_traffic_on_unusual_port_internet_destination.json new file mode 100644 index 00000000000000..8da00c75cedc3b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_http_traffic_on_unusual_port_internet_destination.json @@ -0,0 +1,17 @@ +{ + "rule_id": "43795909-913c-419d-8355-7f2880694bec", + "risk_score": 50, + "description": "Suricata HTTP Traffic On Unusual Port, Internet Destination", + "immutable": true, + "interval": "5m", + "name": "Suricata HTTP Traffic On Unusual Port, Internet Destination", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": " suricata.eve.alert.signature_id:2610001 and (event.module:suricata and event.kind:alert) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_imap_traffic_on_unusual_port_internet_destination.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_imap_traffic_on_unusual_port_internet_destination.json new file mode 100644 index 00000000000000..4f7bfc2baaf37a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_imap_traffic_on_unusual_port_internet_destination.json @@ -0,0 +1,17 @@ +{ + "rule_id": "738ee70b-7d0f-438f-98ac-a393df58c58f", + "risk_score": 50, + "description": "Suricata IMAP Traffic on Unusual Port, internet Destination", + "immutable": true, + "interval": "5m", + "name": "Suricata IMAP Traffic on Unusual Port, internet Destination", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610009 and (event.module:suricata and event.kind:alert) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_lazagne_artifact_in_an_http_post.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_lazagne_artifact_in_an_http_post.json new file mode 100644 index 00000000000000..ed46470838069b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_lazagne_artifact_in_an_http_post.json @@ -0,0 +1,17 @@ +{ + "rule_id": "c6e6f16f-66de-43d5-8ab7-599af536dedf", + "risk_score": 50, + "description": "Suricata LaZagne Artifact in an HTTP POST", + "immutable": true, + "interval": "5m", + "name": "Suricata LaZagne Artifact in an HTTP POST", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610149 or 2610150)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_artifacts_in_an_http_post.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_artifacts_in_an_http_post.json new file mode 100644 index 00000000000000..b3a8079c16f11d --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_artifacts_in_an_http_post.json @@ -0,0 +1,17 @@ +{ + "rule_id": "1b62e8af-c10d-4708-9a74-118cb1c9ed8a", + "risk_score": 50, + "description": "Suricata Mimikatz Artifacts in an HTTP POST", + "immutable": true, + "interval": "5m", + "name": "Suricata Mimikatz Artifacts in an HTTP POST", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610155 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_string_detected_in_http_response.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_string_detected_in_http_response.json new file mode 100644 index 00000000000000..c72f6b348e2593 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_mimikatz_string_detected_in_http_response.json @@ -0,0 +1,17 @@ +{ + "rule_id": "2b365d3a-11a3-4bec-9698-b36c908f46ff", + "risk_score": 50, + "description": "Suricata Mimikatz String Detected in HTTP Response", + "immutable": true, + "interval": "5m", + "name": "Suricata Mimikatz String Detected in HTTP Response", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610144 or 2610145 or 2610146 or 2610147 or 2610148)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_tcp_port_53.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_tcp_port_53.json new file mode 100644 index 00000000000000..66eff77cf43bcd --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_tcp_port_53.json @@ -0,0 +1,17 @@ +{ + "rule_id": "67c7d28e-8be4-49ae-9c89-5c328ea245dc", + "risk_score": 50, + "description": "Suricata non-DNS Traffic on TCP Port 53", + "immutable": true, + "interval": "5m", + "name": "Suricata non-DNS Traffic on TCP Port 53", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610014 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_udp_port_53.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_udp_port_53.json new file mode 100644 index 00000000000000..e09a4357ba5d45 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nondns_traffic_on_udp_port_53.json @@ -0,0 +1,17 @@ +{ + "rule_id": "ba6dea7f-ba98-4a86-b570-d05d85472e79", + "risk_score": 50, + "description": "Suricata non-DNS Traffic on UDP Port 53", + "immutable": true, + "interval": "5m", + "name": "Suricata non-DNS Traffic on UDP Port 53", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610016 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonftp_traffic_on_port_21.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonftp_traffic_on_port_21.json new file mode 100644 index 00000000000000..405be74eb83400 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonftp_traffic_on_port_21.json @@ -0,0 +1,17 @@ +{ + "rule_id": "ee2b07ec-94dd-48b2-b46b-7bef47cc43fc", + "risk_score": 50, + "description": "Suricata non-FTP Traffic on Port 21", + "immutable": true, + "interval": "5m", + "name": "Suricata non-FTP Traffic on Port 21", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610006 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonhttp_traffic_on_tcp_port_80.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonhttp_traffic_on_tcp_port_80.json new file mode 100644 index 00000000000000..cd93ceec2374fb --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonhttp_traffic_on_tcp_port_80.json @@ -0,0 +1,17 @@ +{ + "rule_id": "70f9bd9f-accc-4da8-8674-38992096ddba", + "risk_score": 50, + "description": "Suricata non-HTTP Traffic on TCP Port 80", + "immutable": true, + "interval": "5m", + "name": "Suricata non-HTTP Traffic on TCP Port 80", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610002 and (event.module:suricata and event.kind:alert) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonimap_traffic_on_port_1443_imap.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonimap_traffic_on_port_1443_imap.json new file mode 100644 index 00000000000000..39e5fd188aa4a7 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonimap_traffic_on_port_1443_imap.json @@ -0,0 +1,17 @@ +{ + "rule_id": "241b6a1d-4f73-4b68-bd98-22e909681930", + "risk_score": 50, + "description": "Suricata non-IMAP Traffic on Port 1443 (IMAP)", + "immutable": true, + "interval": "5m", + "name": "Suricata non-IMAP Traffic on Port 1443 (IMAP)", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610010 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonsmb_traffic_on_tcp_port_139_smb.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonsmb_traffic_on_tcp_port_139_smb.json new file mode 100644 index 00000000000000..0fd1c59a3bc629 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonsmb_traffic_on_tcp_port_139_smb.json @@ -0,0 +1,17 @@ +{ + "rule_id": "c259ab53-4b1a-42f6-b204-fe057c521515", + "risk_score": 50, + "description": "Suricata non-SMB Traffic on TCP Port 139 (SMB)", + "immutable": true, + "interval": "5m", + "name": "Suricata non-SMB Traffic on TCP Port 139 (SMB)", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610011 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonssh_traffic_on_port_22.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonssh_traffic_on_port_22.json new file mode 100644 index 00000000000000..3d1cc2e61b1a9c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nonssh_traffic_on_port_22.json @@ -0,0 +1,17 @@ +{ + "rule_id": "256e9e8b-8366-4f23-8cbe-c9eb5ba25633", + "risk_score": 50, + "description": "Suricata non-SSH Traffic on Port 22", + "immutable": true, + "interval": "5m", + "name": "Suricata non-SSH Traffic on Port 22", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610008 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nontls_on_tls_port.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nontls_on_tls_port.json new file mode 100644 index 00000000000000..1fd905e6e4647b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_nontls_on_tls_port.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b060c87f-af49-40eb-acee-561a1f1331aa", + "risk_score": 50, + "description": "Suricata non-TLS on TLS Port", + "immutable": true, + "interval": "5m", + "name": "Suricata non-TLS on TLS Port", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610004 and (event.module:suricata and event.kind:alert) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_cobalt_strike_malleable_c2_null_response.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_cobalt_strike_malleable_c2_null_response.json new file mode 100644 index 00000000000000..a6534d72a9655b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_cobalt_strike_malleable_c2_null_response.json @@ -0,0 +1,17 @@ +{ + "rule_id": "6099a760-7293-4e26-8aa8-b984abb32ac6", + "risk_score": 50, + "description": "Suricata Possible Cobalt Strike Malleable C2 Null Response", + "immutable": true, + "interval": "5m", + "name": "Suricata Possible Cobalt Strike Malleable C2 Null Response", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610202 or 2610203)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_sql_injection_sql_commands_in_http_transactions.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_sql_injection_sql_commands_in_http_transactions.json new file mode 100644 index 00000000000000..0a8b4a9861f9be --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_possible_sql_injection_sql_commands_in_http_transactions.json @@ -0,0 +1,17 @@ +{ + "rule_id": "cdfbcd5e-1d8e-47e6-b3f2-b09bce780640", + "risk_score": 50, + "description": "Suricata Possible SQL Injection - SQL Commands in HTTP Transactions", + "immutable": true, + "interval": "5m", + "name": "Suricata Possible SQL Injection - SQL Commands in HTTP Transactions", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(event.module:suricata and event.kind:alert) and suricata.eve.alert.signature_id: (2610117 or 2610118 or 2610118 or 2610119 or 2610121 or 2610122 or 2610123)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_rpc_traffic_on_http_ports.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_rpc_traffic_on_http_ports.json new file mode 100644 index 00000000000000..4431f46125ef3e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_rpc_traffic_on_http_ports.json @@ -0,0 +1,17 @@ +{ + "rule_id": "87e77fb6-b555-43be-adc5-f57c6aaf7cd0", + "risk_score": 50, + "description": "Suricata RPC Traffic on HTTP Ports", + "immutable": true, + "interval": "5m", + "name": "Suricata RPC Traffic on HTTP Ports", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610012 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_serialized_php_detected.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_serialized_php_detected.json new file mode 100644 index 00000000000000..a176be109f8ffa --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_serialized_php_detected.json @@ -0,0 +1,17 @@ +{ + "rule_id": "3baa5b65-d11e-40fb-a9b4-6b2a6a062d48", + "risk_score": 50, + "description": "Suricata Serialized PHP Detected", + "immutable": true, + "interval": "5m", + "name": "Suricata Serialized PHP Detected", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610091 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_shell_exec_php_function_in_an_http_post.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_shell_exec_php_function_in_an_http_post.json new file mode 100644 index 00000000000000..c1fdb1c083789e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_shell_exec_php_function_in_an_http_post.json @@ -0,0 +1,17 @@ +{ + "rule_id": "082fca48-4707-485a-aedb-340ee77e0687", + "risk_score": 50, + "description": "Suricata shell_exec PHP Function in an HTTP POST", + "immutable": true, + "interval": "5m", + "name": "Suricata shell_exec PHP Function in an HTTP POST", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610087 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ssh_traffic_not_on_port_22_internet_destination.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ssh_traffic_not_on_port_22_internet_destination.json new file mode 100644 index 00000000000000..ee0510d1e37ac1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_ssh_traffic_not_on_port_22_internet_destination.json @@ -0,0 +1,17 @@ +{ + "rule_id": "82265eef-1212-4c4f-af04-f977a3060592", + "risk_score": 50, + "description": "Suricata SSH Traffic Not on Port 22, Internet Destination", + "immutable": true, + "interval": "5m", + "name": "Suricata SSH Traffic Not on Port 22, Internet Destination", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610007 and (event.module:suricata and event.kind:alert) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_tls_traffic_on_unusual_port_internet_destination.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_tls_traffic_on_unusual_port_internet_destination.json new file mode 100644 index 00000000000000..3d0d5175168f1e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_tls_traffic_on_unusual_port_internet_destination.json @@ -0,0 +1,17 @@ +{ + "rule_id": "6c1db8ba-db4b-4513-a0e3-b3c857ba8b05", + "risk_score": 50, + "description": "Suricata TLS Traffic on Unusual Port, Internet Destination", + "immutable": true, + "interval": "5m", + "name": "Suricata TLS Traffic on Unusual Port, Internet Destination", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610003 and (event.module:suricata and event.kind:alert) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_windows_executable_served_by_jpeg_web_content.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_windows_executable_served_by_jpeg_web_content.json new file mode 100644 index 00000000000000..7ab997b11fb263 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suricata_windows_executable_served_by_jpeg_web_content.json @@ -0,0 +1,17 @@ +{ + "rule_id": "f7f038f4-b97a-4d0c-b3b6-d5fa1ad15951", + "risk_score": 50, + "description": "Suricata Windows Executable Served by JPEG Web Content", + "immutable": true, + "interval": "5m", + "name": "Suricata Windows Executable Served by JPEG Web Content", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "suricata.eve.alert.signature_id:2610084 and (event.module:suricata and event.kind:alert)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_process_started_by_a_script.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_process_started_by_a_script.json new file mode 100644 index 00000000000000..43e246cf7c26f2 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/suspicious_process_started_by_a_script.json @@ -0,0 +1,43 @@ +{ + "rule_id": "e49b532b-3e52-4f3d-90f6-05a86982d347", + "risk_score": 50, + "description": "Suspicious process started by a script", + "immutable": true, + "interval": "5m", + "name": "Suspicious process started by a script", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(process.parent.name:cmd.exe or process.parent.name:cscript.exe or process.parent.name:mshta.exe or process.parent.name:powershell.exe or process.parent.name:rundll32.exe or process.parent.name:wscript.exe or process.parent.name:wmiprvse.exe) and (process.name:bitsadmin.exe or process.name:certutil.exe or mshta.exe or process.name:nslookup.exe or process.name:schtasks.exe)", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_background_intelligent_transfer_service_bits_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_background_intelligent_transfer_service_bits_connecting_to_the_internet.json new file mode 100644 index 00000000000000..5842b67076edda --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_background_intelligent_transfer_service_bits_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "7edadee3-98ae-472c-b1c4-8c0a2c4877cc", + "risk_score": 50, + "description": "Windows: Background Intelligent Transfer Service (BITS) Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Background Intelligent Transfer Service (BITS) Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:bitsadmin.exe and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_burp_ce_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_burp_ce_activity.json new file mode 100644 index 00000000000000..4d87d53eb246d1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_burp_ce_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "0f09845b-2ec8-4770-8155-7df3d4e402cc", + "risk_score": 50, + "description": "Windows Burp CE activity", + "immutable": true, + "interval": "5m", + "name": "Windows Burp CE activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:BurpSuiteCommunity.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_certutil_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_certutil_connecting_to_the_internet.json new file mode 100644 index 00000000000000..2e0c9e2b71ae64 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_certutil_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "1a2cf526-6784-4c51-a2b9-f0adcc05d85c", + "risk_score": 50, + "description": "Windows: Certutil Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Certutil Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:certutil.exe and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_command_prompt_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_command_prompt_connecting_to_the_internet.json new file mode 100644 index 00000000000000..3a0e9a2f355669 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_command_prompt_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "89f9a4b0-9f8f-4ee0-8823-c4751a6d6696", + "risk_score": 50, + "description": "Windows: Command Prompt Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Command Prompt Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:cmd.exe and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_commands.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_commands.json new file mode 100644 index 00000000000000..2273249c49b615 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_commands.json @@ -0,0 +1,17 @@ +{ + "rule_id": "66885745-ea38-432c-9edb-599b943948d4", + "risk_score": 50, + "description": "Windows Credential Dumping Commands", + "immutable": true, + "interval": "5m", + "name": "Windows Credential Dumping Commands", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code: 1 and process.args:*Invoke-Mimikatz-DumpCreds* or process.args:*gsecdump* or process.args:*wce* or (process.args:*procdump* and process.args:*lsass*) or (process.args:*ntdsutil* and process.args:*ntds*ifm*create*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_imageload.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_imageload.json new file mode 100644 index 00000000000000..5c9c72efb7aa7c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_imageload.json @@ -0,0 +1,17 @@ +{ + "rule_id": "f872647c-d070-4b1c-afcc-055f081d9205", + "risk_score": 50, + "description": "Windows Credential Dumping via ImageLoad", + "immutable": true, + "interval": "5m", + "name": "Windows Credential Dumping via ImageLoad", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:7 and not process.name:Sysmon.exe and not process.name:Sysmon64.exe and not process.name:svchost.exe and not process.name:logonui.exe and (file.path:*samlib.dll* or file.path:*WinSCard.dll* or file.path:*cryptdll.dll* or file.path:*hid.dll* or file.path:*vaultcli.dll*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_registry_save.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_registry_save.json new file mode 100644 index 00000000000000..38e23c5759162a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_credential_dumping_via_registry_save.json @@ -0,0 +1,17 @@ +{ + "rule_id": "9f6fb56f-4bbd-404e-b955-49dfba7c0e68", + "risk_score": 50, + "description": "Windows Credential Dumping via Registry Save", + "immutable": true, + "interval": "5m", + "name": "Windows Credential Dumping via Registry Save", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code: 1 and process.name:reg.exe and process.args:*save* and (process.args:*sam* or process.args:*system*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_data_compression_using_powershell.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_data_compression_using_powershell.json new file mode 100644 index 00000000000000..604c4148d30568 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_data_compression_using_powershell.json @@ -0,0 +1,17 @@ +{ + "rule_id": "bc913943-e1f9-4bf5-a593-caca7c2eb0c3", + "risk_score": 50, + "description": "Windows Data Compression Using Powershell", + "immutable": true, + "interval": "5m", + "name": "Windows Data Compression Using Powershell", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code: 1 and process.name:powershell.exe and (process.args:*Recurse* and process.args:*Compress-Archive*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_decoding_using_certutil.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_decoding_using_certutil.json new file mode 100644 index 00000000000000..7d6e6c7d539763 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_decoding_using_certutil.json @@ -0,0 +1,17 @@ +{ + "rule_id": "d9642bf2-87d0-45c2-8781-2bd2017cdbb8", + "risk_score": 50, + "description": "Windows Defense Evasion - Decoding Using Certutil", + "immutable": true, + "interval": "5m", + "name": "Windows Defense Evasion - Decoding Using Certutil", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:attrib.exe and (process.args:*+h* or process.args:*+s*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_or_persistence_via_hidden_files.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_or_persistence_via_hidden_files.json new file mode 100644 index 00000000000000..f8f2b6a3fac2a7 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_or_persistence_via_hidden_files.json @@ -0,0 +1,17 @@ +{ + "rule_id": "340a0063-baba-447b-8396-26a5cc1eb684", + "risk_score": 50, + "description": "Windows Defense Evasion or Persistence via Hidden Files", + "immutable": true, + "interval": "5m", + "name": "Windows Defense Evasion or Persistence via Hidden Files", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:attrib.exe and (process.args:*+h* or process.args:*+s*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_filter_manager.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_filter_manager.json new file mode 100644 index 00000000000000..362ed715a8ebfb --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_filter_manager.json @@ -0,0 +1,17 @@ +{ + "rule_id": "06dceabf-adca-48af-ac79-ffdf4c3b1e9a", + "risk_score": 50, + "description": "Windows Defense evasion via Filter Manager", + "immutable": true, + "interval": "5m", + "name": "Windows Defense evasion via Filter Manager", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:fltmc.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_windows_event_log_tools.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_windows_event_log_tools.json new file mode 100644 index 00000000000000..e58399c8c39d24 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_defense_evasion_via_windows_event_log_tools.json @@ -0,0 +1,17 @@ +{ + "rule_id": "07979a67-ab4d-460f-9ff3-bf1352de6762", + "risk_score": 50, + "description": "Windows Defense Evasion via Windows Event Log Tools", + "immutable": true, + "interval": "5m", + "name": "Windows Defense Evasion via Windows Event Log Tools", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:wevtutil.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_compiled_html_file.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_compiled_html_file.json new file mode 100644 index 00000000000000..dac45ae03c237c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_compiled_html_file.json @@ -0,0 +1,17 @@ +{ + "rule_id": "e3343ab9-4245-4715-b344-e11c56b0a47f", + "risk_score": 50, + "description": "Windows Execution via Compiled HTML File", + "immutable": true, + "interval": "5m", + "name": "Windows Execution via Compiled HTML File", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:hh.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_connection_manager.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_connection_manager.json new file mode 100644 index 00000000000000..f97b1da2d5885e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_connection_manager.json @@ -0,0 +1,17 @@ +{ + "rule_id": "f2728299-167a-489c-913c-2e0955ac3c40", + "risk_score": 50, + "description": "Windows Execution via Connection Manager", + "immutable": true, + "interval": "5m", + "name": "Windows Execution via Connection Manager", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.parent.name:pcalua.exe or (process.name:bash.exe or process.name:forfiles.exe or process.name:pcalua.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_microsoft_html_application_hta.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_microsoft_html_application_hta.json new file mode 100644 index 00000000000000..3a98dcc992e3db --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_microsoft_html_application_hta.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b007cc82-c522-48d1-b7a7-53f63c50c494", + "risk_score": 50, + "description": "Windows Execution via Microsoft HTML Application (HTA)", + "immutable": true, + "interval": "5m", + "name": "Windows Execution via Microsoft HTML Application (HTA)", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and (process.parent.args:*mshta* or process.args:*mshta*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_net_com_assemblies.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_net_com_assemblies.json new file mode 100644 index 00000000000000..be40d7616290fb --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_net_com_assemblies.json @@ -0,0 +1,17 @@ +{ + "rule_id": "5c12412f-602c-4120-8c4f-69d723dbba04", + "risk_score": 50, + "description": "Windows Execution via .NET COM Assemblies", + "immutable": true, + "interval": "5m", + "name": "Windows Execution via .NET COM Assemblies", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and (process.name:regasm.exe or process.name:regsvcs.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_regsvr32.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_regsvr32.json new file mode 100644 index 00000000000000..c4351f70e385d0 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_regsvr32.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b7333d08-be4b-4cb4-b81e-924ae37b3143", + "risk_score": 50, + "description": "Windows Execution via Regsvr32", + "immutable": true, + "interval": "5m", + "name": "Windows Execution via Regsvr32", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code: 1 and scrobj.dll and (process.name:certutil.exe or process.name:regsvr32.exe or process.name:rundll32.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_trusted_developer_utilities.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_trusted_developer_utilities.json new file mode 100644 index 00000000000000..cf0701685af277 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_execution_via_trusted_developer_utilities.json @@ -0,0 +1,17 @@ +{ + "rule_id": "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae1", + "risk_score": 50, + "description": "Windows Execution via Trusted Developer Utilities", + "immutable": true, + "interval": "5m", + "name": "Windows Execution via Trusted Developer Utilities", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and (process.name:MSBuild.exe or process.name:msxsl.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_html_help_executable_program_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_html_help_executable_program_connecting_to_the_internet.json new file mode 100644 index 00000000000000..6fa1d4eae74613 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_html_help_executable_program_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b29ee2be-bf99-446c-ab1a-2dc0183394b8", + "risk_score": 50, + "description": "Windows: HTML Help executable Program Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: HTML Help executable Program Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:hh.exe and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_image_load_from_a_temp_directory.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_image_load_from_a_temp_directory.json new file mode 100644 index 00000000000000..6e735cae12985c --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_image_load_from_a_temp_directory.json @@ -0,0 +1,43 @@ +{ + "rule_id": "f23e4cc7-6825-4a28-b27a-e67437a9a806", + "risk_score": 50, + "description": "Windows image load from a temp directory", + "immutable": true, + "interval": "5m", + "name": "Windows image load from a temp directory", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "file.path:Temp", + "language": "kuery", + "filters": [ + { + "meta": { + "alias": null, + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Image loaded (rule: ImageLoad)", + "params": { + "query": "Image loaded (rule: ImageLoad)" + }, + "disabled": false, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Image loaded (rule: ImageLoad)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_indirect_command_execution.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_indirect_command_execution.json new file mode 100644 index 00000000000000..bfcf40d403fbe5 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_indirect_command_execution.json @@ -0,0 +1,17 @@ +{ + "rule_id": "ff969842-c573-4e69-8e12-02fb303290f2", + "risk_score": 50, + "description": "Windows Indirect Command Execution", + "immutable": true, + "interval": "5m", + "name": "Windows Indirect Command Execution", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.parent.name:pcalua.exe or (process.name:bash.exe or process.name:forfiles.exe or process.name:pcalua.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_iodine_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_iodine_activity.json new file mode 100644 index 00000000000000..7fb35a0176b442 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_iodine_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "fcbbf0b2-99c5-4c7f-8411-dc9ee392e43f", + "risk_score": 50, + "description": "Windows Iodine activity", + "immutable": true, + "interval": "5m", + "name": "Windows Iodine activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:iodine.exe or process.name:iodined.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_management_instrumentation_wmi_execution.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_management_instrumentation_wmi_execution.json new file mode 100644 index 00000000000000..b163dcc5c056e3 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_management_instrumentation_wmi_execution.json @@ -0,0 +1,17 @@ +{ + "rule_id": "cec5eb81-6e01-40e5-a1bf-bf175cce4eb4", + "risk_score": 50, + "description": "Windows Management Instrumentation (WMI) Execution", + "immutable": true, + "interval": "5m", + "name": "Windows Management Instrumentation (WMI) Execution", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and (process.parent.args:*wmiprvse.exe* or process.name:wmic.exe or process.args:*wmic* )", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_microsoft_html_application_hta_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_microsoft_html_application_hta_connecting_to_the_internet.json new file mode 100644 index 00000000000000..647dc53a0d05fd --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_microsoft_html_application_hta_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b084514b-e8ba-4bc4-bc2b-50fe145a4215", + "risk_score": 50, + "description": "Windows: Microsoft HTML Application (HTA) Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Microsoft HTML Application (HTA) Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:mshta.exe and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_mimikatz_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_mimikatz_activity.json new file mode 100644 index 00000000000000..a6fa7f8942978a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_mimikatz_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "5346463d-062f-419d-88ff-7a5e97875210", + "risk_score": 50, + "description": "Windows Mimikatz activity", + "immutable": true, + "interval": "5m", + "name": "Windows Mimikatz activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:mimikatz.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_misc_lolbin_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_misc_lolbin_connecting_to_the_internet.json new file mode 100644 index 00000000000000..d2bf2985574015 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_misc_lolbin_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "63e65ec3-43b1-45b0-8f2d-45b34291dc44", + "risk_score": 50, + "description": "Windows: Misc LOLBin Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Misc LOLBin Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(process.name:expand.exe or process.name:extrac.exe or process.name:ieexec.exe or process.name:makecab.exe) and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_command_activity_by_the_system_account.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_command_activity_by_the_system_account.json new file mode 100644 index 00000000000000..cc5e4cec1d7bd8 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_command_activity_by_the_system_account.json @@ -0,0 +1,53 @@ +{ + "rule_id": "c3f5dc81-a8b4-4144-95a7-d0a818d7355d", + "risk_score": 50, + "description": "Windows net command activity by the SYSTEM account", + "immutable": true, + "interval": "5m", + "name": "Windows net command activity by the SYSTEM account", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "user.name:SYSTEM", + "language": "kuery", + "filters": [ + { + "meta": { + "type": "phrases", + "key": "process.name", + "value": "net.exe, net1.exe", + "params": [ + "net.exe", + "net1.exe" + ], + "alias": null, + "negate": false, + "disabled": false, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "bool": { + "should": [ + { + "match_phrase": { + "process.name": "net.exe" + } + }, + { + "match_phrase": { + "process.name": "net1.exe" + } + } + ], + "minimum_should_match": 1 + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_user_command_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_user_command_activity.json new file mode 100644 index 00000000000000..182f6a0c0928c9 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_net_user_command_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "b039a69d-7fba-4c84-8029-57ac12548a15", + "risk_score": 50, + "description": "Windows net user command activity", + "immutable": true, + "interval": "5m", + "name": "Windows net user command activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:net.exe and process.args:user", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_activity.json new file mode 100644 index 00000000000000..fef425b72281f2 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "e2437364-0c89-4e65-a34b-782cfbb7690b", + "risk_score": 50, + "description": "Windows Netcat activity", + "immutable": true, + "interval": "5m", + "name": "Windows Netcat activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:ncat.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_network_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_network_activity.json new file mode 100644 index 00000000000000..91b094785a9bb6 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_netcat_network_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "ebdc4b6f-7fdb-4c21-bbd6-59e1ed11024a", + "risk_score": 50, + "description": "Windows Netcat network activity", + "immutable": true, + "interval": "5m", + "name": "Windows Netcat network activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:ncat.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "connected-to", + "params": { + "query": "connected-to" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "connected-to", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_network_anomalous_windows_process_using_https_ports.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_network_anomalous_windows_process_using_https_ports.json new file mode 100644 index 00000000000000..c59bc4dfa41356 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_network_anomalous_windows_process_using_https_ports.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b486fa9e-e6c7-44a1-b07d-7d5f07f21ce1", + "risk_score": 50, + "description": "Windows Network - Anomalous Windows Process Using HTTP/S Ports", + "immutable": true, + "interval": "5m", + "name": "Windows Network - Anomalous Windows Process Using HTTP/S Ports", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(destination.port:443 or destination.port:80) and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16 and not process.name:chrome.exe and not process.name:explorer.exe and not process.name:filebeat.exe and not process.name:firefox.exe and not process.name:iexplore.exe and not process.name:jusched.exe and not process.name:MpCmdRun.exe and not process.name:MpSigStub.exe and not process.name:msfeedssync.exe and not process.name:packetbeat.exe and not process.name:powershell.exe and not process.name:procexp64.exe and not process.name:svchost.exe and not process.name:taskhostw.exe and not process.name:winlogbeat.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_activity.json new file mode 100644 index 00000000000000..31409e087f8a5a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "5a4b2a98-31a6-4852-b224-d63aeb9e172d", + "risk_score": 50, + "description": "Windows nmap activity", + "immutable": true, + "interval": "5m", + "name": "Windows nmap activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:nmap.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_scan_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_scan_activity.json new file mode 100644 index 00000000000000..580cbe2abcb416 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_nmap_scan_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "54413985-a3da-4f45-b238-75afb65a1bae", + "risk_score": 50, + "description": "Windows nmap scan activity", + "immutable": true, + "interval": "5m", + "name": "Windows nmap scan activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:nmap.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "alias": null, + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Network connection detected (rule: NetworkConnect)", + "params": { + "query": "Network connection detected (rule: NetworkConnect)" + }, + "disabled": false, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Network connection detected (rule: NetworkConnect)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_payload_obfuscation_via_certutil.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_payload_obfuscation_via_certutil.json new file mode 100644 index 00000000000000..9c76c4273cafc1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_payload_obfuscation_via_certutil.json @@ -0,0 +1,17 @@ +{ + "rule_id": "ce7c270c-c69b-47dd-8c21-60a35e92f372", + "risk_score": 50, + "description": "Windows Payload Obfuscation via Certutil", + "immutable": true, + "interval": "5m", + "name": "Windows Payload Obfuscation via Certutil", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:certutil.exe and (process.args:*encode* or process.args:*ToBase64String*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_or_priv_escalation_via_hooking.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_or_priv_escalation_via_hooking.json new file mode 100644 index 00000000000000..98268e9f4ad661 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_or_priv_escalation_via_hooking.json @@ -0,0 +1,17 @@ +{ + "rule_id": "015f070d-cf70-437c-99d1-472e31d36b03", + "risk_score": 50, + "description": "Windows Persistence or Priv Escalation via Hooking", + "immutable": true, + "interval": "5m", + "name": "Windows Persistence or Priv Escalation via Hooking", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:mavinject.exe and processs.args:*INJECTRUNNING*", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_application_shimming.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_application_shimming.json new file mode 100644 index 00000000000000..4db53da43399b6 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_application_shimming.json @@ -0,0 +1,17 @@ +{ + "rule_id": "fd4a992d-6130-4802-9ff8-829b89ae801f", + "risk_score": 50, + "description": "Windows Persistence via Application Shimming", + "immutable": true, + "interval": "5m", + "name": "Windows Persistence via Application Shimming", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:sdbinst.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_bits_jobs.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_bits_jobs.json new file mode 100644 index 00000000000000..e2560badb7be61 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_bits_jobs.json @@ -0,0 +1,17 @@ +{ + "rule_id": "7904fb20-172c-43fb-83e4-bfe27e3c702c", + "risk_score": 50, + "description": "Windows Persistence via BITS Jobs", + "immutable": true, + "interval": "5m", + "name": "Windows Persistence via BITS Jobs", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and (process.name:bitsadmin.exe or process.args:*Start-BitsTransfer*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_modification_of_existing_service.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_modification_of_existing_service.json new file mode 100644 index 00000000000000..27300362fecf66 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_modification_of_existing_service.json @@ -0,0 +1,17 @@ +{ + "rule_id": "3bb04809-84ab-4487-bd99-ccc58675bd40", + "risk_score": 50, + "description": "Windows Persistence via Modification of Existing Service", + "immutable": true, + "interval": "5m", + "name": "Windows Persistence via Modification of Existing Service", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.args:*sc*config*binpath* and (process.name:cmd.exe or process.name:powershell.exe or process.name:sc.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_netshell_helper_dll.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_netshell_helper_dll.json new file mode 100644 index 00000000000000..c0bd446f968c8d --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_persistence_via_netshell_helper_dll.json @@ -0,0 +1,17 @@ +{ + "rule_id": "d7c2561d-2758-46ad-b5a9-247efb9eea21", + "risk_score": 50, + "description": "Windows Persistence via Netshell Helper DLL", + "immutable": true, + "interval": "5m", + "name": "Windows Persistence via Netshell Helper DLL", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:netsh.exe and process.args:*helper*", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_powershell_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_powershell_connecting_to_the_internet.json new file mode 100644 index 00000000000000..dc3fed37a8c53d --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_powershell_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "a8cfa646-e4d8-48b5-884e-6204ba77fc8d", + "risk_score": 50, + "description": "Windows: Powershell Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Powershell Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:powershell.exe and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:169.254.169.254/32 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_priv_escalation_via_accessibility_features.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_priv_escalation_via_accessibility_features.json new file mode 100644 index 00000000000000..afeb03150dfcf1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_priv_escalation_via_accessibility_features.json @@ -0,0 +1,17 @@ +{ + "rule_id": "7405ddf1-6c8e-41ce-818f-48bea6bcaed8", + "risk_score": 50, + "description": "Windows Priv Escalation via Accessibility Features", + "immutable": true, + "interval": "5m", + "name": "Windows Priv Escalation via Accessibility Features", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.parent.name:winlogon.exe and (process.name:atbroker.exe or process.name:displayswitch.exe or process.name:magnify.exe or process.name:narrator.exe or process.name:osk.exe or process.name:sethc.exe or process.name:utilman.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_discovery_via_tasklist_command.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_discovery_via_tasklist_command.json new file mode 100644 index 00000000000000..488943dea29498 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_discovery_via_tasklist_command.json @@ -0,0 +1,17 @@ +{ + "rule_id": "cc16f774-59f9-462d-8b98-d27ccd4519ec", + "risk_score": 50, + "description": "Windows Process Discovery via Tasklist Command", + "immutable": true, + "interval": "5m", + "name": "Windows Process Discovery via Tasklist Command", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and process.name:tasklist.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_started_by_the_java_runtime.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_started_by_the_java_runtime.json new file mode 100644 index 00000000000000..ea246b02643708 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_process_started_by_the_java_runtime.json @@ -0,0 +1,43 @@ +{ + "rule_id": "159168a1-b1d0-4e5c-ad72-c1e9ae2edec2", + "risk_score": 50, + "description": "Windows process started by the Java runtime", + "immutable": true, + "interval": "5m", + "name": "Windows process started by the Java runtime", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.parent.name:javaw.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_register_server_program_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_register_server_program_connecting_to_the_internet.json new file mode 100644 index 00000000000000..cce8effd5d536f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_register_server_program_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "fb02b8d3-71ee-4af1-bacd-215d23f17efa", + "risk_score": 50, + "description": "Windows: Register Server Program Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Register Server Program Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(process.name:regsvr32.exe or process.name:regsvr64.exe) and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:169.254.169.254/32 and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_local.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_local.json new file mode 100644 index 00000000000000..af9935275267bc --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_local.json @@ -0,0 +1,17 @@ +{ + "rule_id": "b9074c74-6d23-4b07-927e-cc18b318a088", + "risk_score": 50, + "description": "Windows Registry Query, Local", + "immutable": true, + "interval": "5m", + "name": "Windows Registry Query, Local", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code: 1 and process.name:reg.exe and process.args:*query* and process.args:*reg*", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_network.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_network.json new file mode 100644 index 00000000000000..4926aabcb8f9d9 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_registry_query_network.json @@ -0,0 +1,17 @@ +{ + "rule_id": "f5412e37-981e-4d37-a1b2-eddaf797445a", + "risk_score": 50, + "description": "Windows Registry Query, Network", + "immutable": true, + "interval": "5m", + "name": "Windows Registry Query, Network", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code: 1 and process.name:reg.exe and process.args:*query* and process.args:*reg*", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_remote_management_execution.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_remote_management_execution.json new file mode 100644 index 00000000000000..d0765ee531bb3b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_remote_management_execution.json @@ -0,0 +1,17 @@ +{ + "rule_id": "ced66221-3e07-40ee-8588-5f107e7d50d8", + "risk_score": 50, + "description": "Windows Remote Management Execution", + "immutable": true, + "interval": "5m", + "name": "Windows Remote Management Execution", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(process.name:wsmprovhost.exe or process.name:winrm.cmd) and (process.args:*Enable-PSRemoting -Force* or process.args:*Invoke-Command -computer_name* or process.args:*wmic*node*process call create*)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_scheduled_task_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_scheduled_task_activity.json new file mode 100644 index 00000000000000..e84d6912793bd1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_scheduled_task_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "a1abd54d-3021-4f21-b2d1-0c6bc5c4051f", + "risk_score": 50, + "description": "Windows Scheduled Task Activity", + "immutable": true, + "interval": "5m", + "name": "Windows Scheduled Task Activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and (process.name:schtasks.exe or process.name:taskeng.exe) or (event.code:1 and process.name:svchost.exe and not process.parent.executable: \"C:\\Windows\\System32\\services.exe\" )", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_script_interpreter_connecting_to_the_internet.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_script_interpreter_connecting_to_the_internet.json new file mode 100644 index 00000000000000..373d5aa86e6a63 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_script_interpreter_connecting_to_the_internet.json @@ -0,0 +1,17 @@ +{ + "rule_id": "2cc4597c-b0c9-4481-b1a6-e6c05cfc9f02", + "risk_score": 50, + "description": "Windows: Script Interpreter Connecting to the Internet", + "immutable": true, + "interval": "5m", + "name": "Windows: Script Interpreter Connecting to the Internet", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "(process.name:cscript.exe or process.name:wscript.exe) and event.action:\"Network connection detected (rule: NetworkConnect)\" and not destination.ip:10.0.0.0/8 and not destination.ip:172.16.0.0/12 and not destination.ip:192.168.0.0/16", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution.json new file mode 100644 index 00000000000000..a05d37126be3e2 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution.json @@ -0,0 +1,17 @@ +{ + "rule_id": "7edb573f-1f9b-4161-8c19-c7c383bb17f2", + "risk_score": 50, + "description": "Windows Signed Binary Proxy Execution", + "immutable": true, + "interval": "5m", + "name": "Windows Signed Binary Proxy Execution", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "event.code:1 and http and (process.name:certutil.exe or process.name:msiexec.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution_download.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution_download.json new file mode 100644 index 00000000000000..931a1f170e5bd1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_signed_binary_proxy_execution_download.json @@ -0,0 +1,17 @@ +{ + "rule_id": "68ecc190-cce2-4021-b976-c7c846ac0a00", + "risk_score": 50, + "description": "Windows Signed Binary Proxy Execution Download", + "immutable": true, + "interval": "5m", + "name": "Windows Signed Binary Proxy Execution Download", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": " event.code:3 and http and (process.name:certutil.exe or process.name:replace.exe)", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_whoami_command_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_whoami_command_activity.json new file mode 100644 index 00000000000000..e4acdcee249bf2 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_whoami_command_activity.json @@ -0,0 +1,43 @@ +{ + "rule_id": "ef862985-3f13-4262-a686-5f357bbb9bc2", + "risk_score": 50, + "description": "Windows whoami command activity", + "immutable": true, + "interval": "5m", + "name": "Windows whoami command activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:whoami.exe", + "language": "kuery", + "filters": [ + { + "meta": { + "negate": false, + "type": "phrase", + "key": "event.action", + "value": "Process Create (rule: ProcessCreate)", + "params": { + "query": "Process Create (rule: ProcessCreate)" + }, + "disabled": false, + "alias": null, + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" + }, + "query": { + "match": { + "event.action": { + "query": "Process Create (rule: ProcessCreate)", + "type": "phrase" + } + } + }, + "$state": { + "store": "appState" + } + } + ], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_wireshark_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_wireshark_activity.json new file mode 100644 index 00000000000000..75dfa58e33318f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_wireshark_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "9af965ed-d501-4541-97f6-5f8d2a39737b", + "risk_score": 50, + "description": "Windows Wireshark activity", + "immutable": true, + "interval": "5m", + "name": "Windows Wireshark activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:wireshark.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windump_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windump_activity.json new file mode 100644 index 00000000000000..db42e194fcf9f7 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windump_activity.json @@ -0,0 +1,17 @@ +{ + "rule_id": "61c56cf4-0c08-4ad5-83ea-d2fe6ac62fa8", + "risk_score": 50, + "description": "WinDump activity", + "immutable": true, + "interval": "5m", + "name": "WinDump activity", + "severity": "low", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "process.name:WinDump.exe", + "language": "kuery", + "filters": [], + "enabled": false, + "version": 1 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts new file mode 100644 index 00000000000000..3d2ca8f91281b8 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_prepacked_rules.ts @@ -0,0 +1,75 @@ +/* + * 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 { ActionsClient } from '../../../../../actions'; +import { AlertsClient } from '../../../../../alerting'; +import { updateRules } from './update_rules'; +import { RuleAlertParamsRest } from '../types'; + +export const updatePrepackagedRules = async ( + alertsClient: AlertsClient, + actionsClient: ActionsClient, + rules: RuleAlertParamsRest[], + outputIndex: string +): Promise => { + await rules.forEach(async rule => { + const { + description, + false_positives: falsePositives, + from, + immutable, + query, + language, + saved_id: savedId, + meta, + filters, + rule_id: ruleId, + index, + interval, + max_signals: maxSignals, + risk_score: riskScore, + name, + severity, + tags, + to, + type, + threats, + references, + version, + } = rule; + + // Note: we do not pass down enabled as we do not want to suddenly disable + // or enable rules on the user when they were not expecting it if a rule updates + return updateRules({ + alertsClient, + actionsClient, + description, + falsePositives, + from, + immutable, + query, + language, + outputIndex, + id: undefined, // We never have an id when updating from pre-packaged rules + savedId, + meta, + filters, + ruleId, + index, + interval, + maxSignals, + riskScore, + name, + severity, + tags, + to, + type, + threats, + references, + version, + }); + }); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts index 1022fea93200fa..c079c637d88b7a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { calculateInterval, calculateName } from './update_rules'; +import { calculateInterval, calculateName, calculateVersion } from './update_rules'; describe('update_rules', () => { describe('#calculateInterval', () => { @@ -24,6 +24,24 @@ describe('update_rules', () => { }); }); + describe('#calculateVersion', () => { + test('given preVersion and nextVersion numbers being null it will return a 1', () => { + expect(calculateVersion(null, null)).toEqual(1); + }); + + test('given preVersion and nextVersion numbers being undefined it will return a 1', () => { + expect(calculateVersion(undefined, undefined)).toEqual(1); + }); + + test('given prevVersion as null and nextVersion being defined, nextVersion will be returned', () => { + expect(calculateVersion(undefined, 5)).toEqual(5); + }); + + test('given prevVersion as being defined but nextVersion is not, prevVersion will be incremented by 1', () => { + expect(calculateVersion(5, undefined)).toEqual(6); + }); + }); + describe('#calculateName', () => { test('should return the updated name when it and originalName is there', () => { const name = calculateName({ updatedName: 'updated', originalName: 'original' }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 12df579ee4c546..689d6bdf175b5f 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -8,7 +8,7 @@ import { defaults } from 'lodash/fp'; import { AlertAction } from '../../../../../alerting/server/types'; import { readRules } from './read_rules'; import { UpdateRuleParams } from './types'; -import { updateTags } from './update_tags'; +import { addTags } from './add_tags'; export const calculateInterval = ( interval: string | undefined, @@ -23,6 +23,27 @@ export const calculateInterval = ( } }; +export const calculateVersion = ( + prevVersion: number | null | undefined, + nextVersion: number | null | undefined +) => { + if (nextVersion == null) { + if (prevVersion != null) { + return prevVersion + 1; + } else { + // really should never hit this code but to just be + // safe let us always check the prev version and if + // its null or undefined return a 1 + return 1; + } + } else { + // The user wants to custom update their version number which + // means this could be in the past. Up to the user if they want + // to do this + return nextVersion; + } +}; + export const calculateName = ({ updatedName, originalName, @@ -69,6 +90,7 @@ export const updateRules = async ({ to, type, references, + version, }: UpdateRuleParams) => { const rule = await readRules({ alertsClient, ruleId, id }); if (rule == null) { @@ -105,18 +127,26 @@ export const updateRules = async ({ type, updatedAt: new Date().toISOString(), references, + version: calculateVersion(rule.params.version, version), } ); - if (rule.enabled && !enabled) { + if (rule.enabled && enabled === false) { await alertsClient.disable({ id: rule.id }); - } else if (!rule.enabled && enabled) { + } else if (!rule.enabled && enabled === true) { await alertsClient.enable({ id: rule.id }); + } else { + // enabled is null or undefined and we do not touch the rule } + return alertsClient.update({ id: rule.id, data: { - tags: updateTags(rule.tags, tags), + tags: addTags( + tags, + rule.params.ruleId, + immutable != null ? immutable : rule.params.immutable // Add new one if it exists, otherwise re-use old one + ), name: calculateName({ updatedName: name, originalName: rule.name }), interval: calculateInterval(interval, rule.interval), actions, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts deleted file mode 100644 index cca937d73bd74f..00000000000000 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 { updateTags } from './update_tags'; -import { INTERNAL_IDENTIFIER } from '../../../../common/constants'; - -describe('update_tags', () => { - test('it should copy internal structures but not any other tags when updating', () => { - const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], ['tag 1']); - expect(tags).toEqual([`${INTERNAL_IDENTIFIER}_some_value`, 'tag 1']); - }); - - test('it should copy internal structures but not any other tags if given an update of empty tags', () => { - const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], []); - expect(tags).toEqual([`${INTERNAL_IDENTIFIER}_some_value`]); - }); - - test('it should work like a normal update if there are no internal structures', () => { - const tags = updateTags(['tag 2', 'tag 3'], ['tag 1']); - expect(tags).toEqual(['tag 1']); - }); - - test('it should not perform an update if the nextTags are undefined', () => { - const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], undefined); - expect(tags).toEqual(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3']); - }); - - test('it should not perform an update if the nextTags are null', () => { - const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], null); - expect(tags).toEqual(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3']); - }); -}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts deleted file mode 100644 index cf1424ea31600c..00000000000000 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 { INTERNAL_IDENTIFIER } from '../../../../common/constants'; - -export const updateTags = (prevTags: string[], nextTags: string[] | undefined | null): string[] => { - if (nextTags == null) { - return prevTags; - } else { - const allInternalStructures = prevTags.filter(tag => tag.startsWith(INTERNAL_IDENTIFIER)); - return [...allInternalStructures, ...nextTags]; - } -}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/add_prepackaged_rules.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/add_prepackaged_rules.sh new file mode 100755 index 00000000000000..be53e0cd682f09 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/add_prepackaged_rules.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# +# 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. +# + +set -e +./check_env_variables.sh + +# Example: ./add_prepackaged_rules.sh +curl -s -k \ + -H 'Content-Type: application/json' \ + -H 'kbn-xsrf: 123' \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X PUT ${KIBANA_URL}${SPACE_URL}/api/detection_engine/rules/prepackaged | jq . diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/convert_saved_search_to_rules.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/convert_saved_search_to_rules.sh index e4d345eec0b656..1995b8c7f6978d 100755 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/convert_saved_search_to_rules.sh +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/convert_saved_search_to_rules.sh @@ -9,4 +9,6 @@ set -e ./check_env_variables.sh -node ../../../../scripts/convert_saved_search_to_rules.js $1 $2 +OUTPUT=${2:-../rules/prepackaged_rules} + +node ../../../../scripts/convert_saved_search_to_rules.js $1 $OUTPUT diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rule_by_filter.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rule_by_filter.sh index 52d49979a072be..6331e72ac7e8e1 100755 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rule_by_filter.sh +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/find_rule_by_filter.sh @@ -11,11 +11,27 @@ set -e FILTER=${1:-'alert.attributes.enabled:%20true'} -# Example: ./find_rule_by_filter.sh "alert.attributes.enabled:%20true" -# Example: ./find_rule_by_filter.sh "alert.attributes.name:%20Detect*" -# Example: ./find_rule_by_filter.sh "alert.attributes.tags:tag_1" # The %20 is just an encoded space that is typical of URL's. +# The %22 is just an encoded quote of " # Table of them for testing if needed: https://www.w3schools.com/tags/ref_urlencode.asp + +# Example get all enabled tags: +# ./find_rule_by_filter.sh "alert.attributes.enabled:%20true" + +# Example get all the names that start with Detect* +# ./find_rule_by_filter.sh "alert.attributes.name:%20Detect*" + +# Exampe get everything that has tag_1 +# ./find_rule_by_filter.sh "alert.attributes.tags:tag_1" + +# Example get all pre-packaged rules +# ./find_rule_by_filter.sh "alert.attributes.tags:%20%22__internal_immutable:true%22" + +# Example get all non pre-packaged rules +# ./find_rule_by_filter.sh "alert.attributes.tags:%20%22__internal_immutable:false%22" + +# Example get all non pre-packaged rules and a tag_1 +# ./find_rule_by_filter.sh "alert.attributes.tags:%20%22__internal_immutable:false%22%20AND%20alert.attributes.tags:tag_1" curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X GET ${KIBANA_URL}${SPACE_URL}/api/detection_engine/rules/_find?filter=$FILTER | jq . diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json index adb96ba398f5e9..919cef392d0cdb 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json @@ -76,5 +76,6 @@ "references": [ "http://www.example.com/some-article-about-attack", "Some plain text string here explaining why this is a valid thing to look out for" - ] + ], + "version": 1 } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_immutable.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_immutable.json new file mode 100644 index 00000000000000..14706b6e54e7bf --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_immutable.json @@ -0,0 +1,4 @@ +{ + "rule_id": "query-rule-id", + "immutable": true +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_interval.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_interval.json new file mode 100644 index 00000000000000..72a535f0ef6417 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_interval.json @@ -0,0 +1,4 @@ +{ + "rule_id": "query-rule-id", + "interval": "6m" +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json index 285e9c94a76d9a..5bbae7e2bb061d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json @@ -76,5 +76,6 @@ "references": [ "http://www.example.com/some-article-about-attack", "Some plain text string here explaining why this is a valid thing to look out for" - ] + ], + "version": 42 } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_version.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_version.json new file mode 100644 index 00000000000000..8df63dd22bf9a9 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_version.json @@ -0,0 +1,4 @@ +{ + "rule_id": "query-rule-id", + "version": 500 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index dde8cc4739e518..619924032e3620 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -32,6 +32,7 @@ export const sampleRuleAlertParams = ( savedId: undefined, meta: undefined, threats: undefined, + version: 1, updatedAt: '2019-12-17T15:04:25.343Z', createdAt: '2019-12-17T15:04:37.105Z', }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts index 7d08d6c1d73f02..90860a817d2703 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -69,6 +69,7 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + version: 1, created_at: fakeSignalSourceHit.signal.rule?.created_at, updated_at: fakeSignalSourceHit.signal.rule?.updated_at, }, @@ -144,6 +145,7 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + version: 1, created_at: fakeSignalSourceHit.signal.rule?.created_at, updated_at: fakeSignalSourceHit.signal.rule?.updated_at, }, @@ -217,6 +219,7 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + version: 1, created_at: fakeSignalSourceHit.signal.rule?.created_at, updated_at: fakeSignalSourceHit.signal.rule?.updated_at, }, @@ -283,6 +286,7 @@ describe('buildBulkBody', () => { enabled: true, created_by: 'elastic', updated_by: 'elastic', + version: 1, updated_at: fakeSignalSourceHit.signal.rule?.updated_at, created_at: fakeSignalSourceHit.signal.rule?.created_at, }, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts index e5214640232840..451e493f3ed8ad 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts @@ -72,6 +72,7 @@ describe('buildRule', () => { query: 'host.name: Braden', }, ], + version: 1, }; expect(rule).toEqual(expected); }); @@ -112,6 +113,7 @@ describe('buildRule', () => { to: 'now', type: 'query', updated_by: 'elastic', + version: 1, updated_at: rule.updated_at, created_at: rule.created_at, }; @@ -154,6 +156,7 @@ describe('buildRule', () => { to: 'now', type: 'query', updated_by: 'elastic', + version: 1, updated_at: rule.updated_at, created_at: rule.created_at, }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts index 05b1da5fc43bed..8a46a8231cc583 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts @@ -55,6 +55,7 @@ export const buildRule = ({ created_by: createdBy, updated_by: updatedBy, threats: ruleParams.threats, + version: ruleParams.version, created_at: ruleParams.createdAt, updated_at: ruleParams.updatedAt, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 03768c41b52dd8..08e4bcc69a9bbc 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -52,6 +52,7 @@ export const signalRulesAlertType = ({ type: schema.string(), updatedAt: schema.string(), references: schema.arrayOf(schema.string(), { defaultValue: [] }), + version: schema.number({ defaultValue: 1 }), }), }, async executor({ alertId, services, params }) { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts index 2d562672a4a638..87739bf785012e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts @@ -28,7 +28,7 @@ describe('read_tags', () => { result2.tags = ['tag 1', 'tag 2', 'tag 3', 'tag 4']; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readRawTags({ @@ -49,7 +49,7 @@ describe('read_tags', () => { result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readRawTags({ @@ -70,7 +70,7 @@ describe('read_tags', () => { result2.tags = []; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readRawTags({ @@ -86,7 +86,7 @@ describe('read_tags', () => { result1.tags = ['tag 1', 'tag 1', 'tag 1', 'tag 2']; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readRawTags({ @@ -102,7 +102,7 @@ describe('read_tags', () => { result1.tags = []; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readRawTags({ @@ -125,7 +125,7 @@ describe('read_tags', () => { result2.tags = ['tag 1', 'tag 2', 'tag 3', 'tag 4']; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readTags({ @@ -146,7 +146,7 @@ describe('read_tags', () => { result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readTags({ @@ -167,7 +167,7 @@ describe('read_tags', () => { result2.tags = []; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1, result2] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readTags({ @@ -183,7 +183,7 @@ describe('read_tags', () => { result1.tags = ['tag 1', 'tag 1', 'tag 1', 'tag 2']; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readTags({ @@ -199,7 +199,7 @@ describe('read_tags', () => { result1.tags = []; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readTags({ @@ -219,7 +219,7 @@ describe('read_tags', () => { ]; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readTags({ @@ -255,7 +255,7 @@ describe('read_tags', () => { ]; const alertsClient = alertsClientMock.create(); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits({ data: [result1] })); const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; const tags = await readTags({ @@ -277,7 +277,7 @@ describe('read_tags', () => { result2.params.ruleId = 'rule-2'; result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; - const findResult = getFindResultWithMultiHits([result1, result2]); + const findResult = getFindResultWithMultiHits({ data: [result1, result2] }); const set = convertTagsToSet(findResult.data); expect(Array.from(set)).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); }); @@ -300,7 +300,7 @@ describe('read_tags', () => { result2.params.ruleId = 'rule-2'; result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; - const findResult = getFindResultWithMultiHits([result1, result2]); + const findResult = getFindResultWithMultiHits({ data: [result1, result2] }); const tags = convertToTags(findResult.data); expect(tags).toEqual([ 'tag 1', @@ -331,7 +331,7 @@ describe('read_tags', () => { result3.params.ruleId = 'rule-2'; result3.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; - const findResult = getFindResultWithMultiHits([result1, result2, result3]); + const findResult = getFindResultWithMultiHits({ data: [result1, result2, result3] }); const tags = convertToTags(findResult.data); expect(tags).toEqual([ 'tag 1', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index f2178390686a10..e1e7a7fb0a2bd0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -45,6 +45,7 @@ export interface RuleAlertParams { to: string; threats: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; + version: number; updatedAt: string; } From 609b5826ff3af1ae96f985a02e71b81079460bad Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 17 Dec 2019 15:57:14 -0700 Subject: [PATCH 33/60] [Metrics UI] Fix AWS SQS toolbar types (#53051) --- x-pack/legacy/plugins/infra/common/graphql/types.ts | 2 +- x-pack/legacy/plugins/infra/server/graphql/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/infra/common/graphql/types.ts b/x-pack/legacy/plugins/infra/common/graphql/types.ts index 0520409800bce4..5bb6beeae8c3b7 100644 --- a/x-pack/legacy/plugins/infra/common/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/common/graphql/types.ts @@ -577,7 +577,7 @@ export enum InfraSnapshotMetricType { rdsQueriesExecuted = 'rdsQueriesExecuted', rdsActiveTransactions = 'rdsActiveTransactions', rdsLatency = 'rdsLatency', - sqsMessagesVisible = 'sqsOldestMessage', + sqsMessagesVisible = 'sqsMessagesVisible', sqsMessagesDelayed = 'sqsMessagesDelayed', sqsMessagesSent = 'sqsMessagesSent', sqsMessagesEmpty = 'sqsMessagesEmpty', diff --git a/x-pack/legacy/plugins/infra/server/graphql/types.ts b/x-pack/legacy/plugins/infra/server/graphql/types.ts index 88ad5b2f58f238..28f1144c75804f 100644 --- a/x-pack/legacy/plugins/infra/server/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/server/graphql/types.ts @@ -605,7 +605,7 @@ export enum InfraSnapshotMetricType { rdsQueriesExecuted = 'rdsQueriesExecuted', rdsActiveTransactions = 'rdsActiveTransactions', rdsLatency = 'rdsLatency', - sqsMessagesVisible = 'sqsOldestMessage', + sqsMessagesVisible = 'sqsMessagesVisible', sqsMessagesDelayed = 'sqsMessagesDelayed', sqsMessagesSent = 'sqsMessagesSent', sqsMessagesEmpty = 'sqsMessagesEmpty', From df3cfcb600ef68ec8316e8969bac98c9cf09a124 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 17 Dec 2019 17:05:04 -0700 Subject: [PATCH 34/60] [yarn] upgrade caniuse-lite database (#53321) --- yarn.lock | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 27e4e12c280a6d..8a6c2e91d25d72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7630,15 +7630,10 @@ can-use-dom@^0.1.0: resolved "https://registry.yarnpkg.com/can-use-dom/-/can-use-dom-0.1.0.tgz#22cc4a34a0abc43950f42c6411024a3f6366b45a" integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo= -caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981: - version "1.0.30000983" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000983.tgz#ab3c70061ca2a3467182a10ac75109b199b647f8" - integrity sha512-/llD1bZ6qwNkt41AsvjsmwNOoA4ZB+8iqmf5LVyeSXuBODT/hAMFNVOh84NdUzoiYiSKqo5vQ3ZzeYHSi/olDQ== - -caniuse-lite@^1.0.30000984: - version "1.0.30000989" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9" - integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw== +caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000984: + version "1.0.30001016" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz#16ea48d7d6e8caf3cad3295c2d746fe38c4e7f66" + integrity sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA== capture-exit@^2.0.0: version "2.0.0" From ef83108c26267d0c229444ba43f8157d72a4f4c8 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Tue, 17 Dec 2019 17:26:45 -0700 Subject: [PATCH 35/60] [Maps] Update license check & requests to use NP services (#52641) * Add back in np licensing changes previously pulled out of a separate pr * Watch license service and update local kibana service const obj. on change. Import new license id in meta * Update flow for initializing indexPatternServices while in this file * Clean up setup method. Add conditional subscribe of licensing * Review feedback. Use license getter instead of obj * Revert "Update flow for initializing indexPatternServices while in this file" This reverts commit 022f7ddb87b565d2962c1ef28a6e0620afbc570b. * Update meta test --- x-pack/legacy/plugins/maps/index.js | 2 -- .../plugins/maps/public/kibana_services.js | 7 ++++- x-pack/legacy/plugins/maps/public/legacy.ts | 4 +-- x-pack/legacy/plugins/maps/public/meta.js | 6 ++--- .../legacy/plugins/maps/public/meta.test.js | 6 ++--- x-pack/legacy/plugins/maps/public/plugin.ts | 20 +++++++++++--- x-pack/legacy/plugins/maps/server/plugin.js | 26 +++++++------------ 7 files changed, 37 insertions(+), 34 deletions(-) diff --git a/x-pack/legacy/plugins/maps/index.js b/x-pack/legacy/plugins/maps/index.js index 77755459ca5cf7..a6e28c9c29a32a 100644 --- a/x-pack/legacy/plugins/maps/index.js +++ b/x-pack/legacy/plugins/maps/index.js @@ -106,7 +106,6 @@ export function maps(kibana) { // legacy dependencies const __LEGACY = { - pluginRef: this, config: server.config, mapConfig() { return server.config().get('map'); @@ -114,7 +113,6 @@ export function maps(kibana) { route: server.route.bind(server), plugins: { elasticsearch: server.plugins.elasticsearch, - xpackMainPlugin: server.plugins.xpack_main, }, savedObjects: { getSavedObjectsRepository: server.savedObjects.getSavedObjectsRepository, diff --git a/x-pack/legacy/plugins/maps/public/kibana_services.js b/x-pack/legacy/plugins/maps/public/kibana_services.js index 7e63866877903c..1ec7565df6f26f 100644 --- a/x-pack/legacy/plugins/maps/public/kibana_services.js +++ b/x-pack/legacy/plugins/maps/public/kibana_services.js @@ -8,7 +8,6 @@ import { getRequestInspectorStats, getResponseInspectorStats, } from '../../../../../src/legacy/ui/public/courier'; -export { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; import { esFilters } from '../../../../../src/plugins/data/public'; import { npStart } from 'ui/new_platform'; @@ -16,6 +15,12 @@ export const SPATIAL_FILTER_TYPE = esFilters.FILTERS.SPATIAL_FILTER; export { SearchSource } from '../../../../../src/legacy/ui/public/courier'; export const indexPatternService = npStart.plugins.data.indexPatterns; +let licenseId; +export const setLicenseId = latestLicenseId => (licenseId = latestLicenseId); +export const getLicenseId = () => { + return licenseId; +}; + export async function fetchSearchSourceAndRecordWithInspector({ searchSource, requestId, diff --git a/x-pack/legacy/plugins/maps/public/legacy.ts b/x-pack/legacy/plugins/maps/public/legacy.ts index 684d7b16fbb3b1..6adab529daf86e 100644 --- a/x-pack/legacy/plugins/maps/public/legacy.ts +++ b/x-pack/legacy/plugins/maps/public/legacy.ts @@ -16,11 +16,11 @@ const setupPlugins = { __LEGACY: { uiModules, }, - plugins: npSetup.plugins, + np: npSetup.plugins, }; const startPlugins = { - plugins: npStart.plugins, + np: npStart.plugins, }; export const setup = pluginInstance.setup(npSetup.core, setupPlugins); diff --git a/x-pack/legacy/plugins/maps/public/meta.js b/x-pack/legacy/plugins/maps/public/meta.js index c47c2847ffd149..d92b8713f0e706 100644 --- a/x-pack/legacy/plugins/maps/public/meta.js +++ b/x-pack/legacy/plugins/maps/public/meta.js @@ -8,7 +8,7 @@ import { GIS_API_PATH, EMS_CATALOGUE_PATH, EMS_GLYPHS_PATH } from '../common/con import chrome from 'ui/chrome'; import { i18n } from '@kbn/i18n'; import { EMSClient } from '@elastic/ems-client'; -import { xpackInfo } from './kibana_services'; +import { getLicenseId } from './kibana_services'; import fetch from 'node-fetch'; const GIS_API_RELATIVE = `../${GIS_API_PATH}`; @@ -68,9 +68,7 @@ export function getEMSClient() { }; } } - const xpackMapsFeature = xpackInfo.get('features.maps'); - const licenseId = - xpackMapsFeature && xpackMapsFeature.maps && xpackMapsFeature.uid ? xpackMapsFeature.uid : ''; + const licenseId = getLicenseId(); if (latestLicenseId !== licenseId) { latestLicenseId = licenseId; emsClient.addQueryParams({ license: licenseId }); diff --git a/x-pack/legacy/plugins/maps/public/meta.test.js b/x-pack/legacy/plugins/maps/public/meta.test.js index 07cf4a37b07cde..06f4071e3444b2 100644 --- a/x-pack/legacy/plugins/maps/public/meta.test.js +++ b/x-pack/legacy/plugins/maps/public/meta.test.js @@ -33,10 +33,8 @@ jest.mock('ui/chrome', () => ({ jest.mock('./kibana_services', () => { return { - xpackInfo: { - get() { - return 'foobarlicenseid'; - }, + getLicenseId() { + return 'foobarlicenseid'; }, }; }); diff --git a/x-pack/legacy/plugins/maps/public/plugin.ts b/x-pack/legacy/plugins/maps/public/plugin.ts index 4e6d52d20db645..0df71098524867 100644 --- a/x-pack/legacy/plugins/maps/public/plugin.ts +++ b/x-pack/legacy/plugins/maps/public/plugin.ts @@ -9,6 +9,8 @@ import { Plugin, CoreStart } from 'src/core/public'; import { wrapInI18nContext } from 'ui/i18n'; // @ts-ignore import { MapListing } from './components/map_listing'; +// @ts-ignore +import { setLicenseId } from './kibana_services'; /** * These are the interfaces with your public contracts. You should export these @@ -21,10 +23,20 @@ export type MapsPluginStart = ReturnType; /** @internal */ export class MapsPlugin implements Plugin { public setup(core: any, plugins: any) { - const app = plugins.__LEGACY.uiModules.get('app/maps', ['ngRoute', 'react']); - app.directive('mapListing', function(reactDirective: any) { - return reactDirective(wrapInI18nContext(MapListing)); - }); + const { + __LEGACY: { uiModules }, + np: { licensing }, + } = plugins; + + uiModules + .get('app/maps', ['ngRoute', 'react']) + .directive('mapListing', function(reactDirective: any) { + return reactDirective(wrapInI18nContext(MapListing)); + }); + + if (licensing) { + licensing.license$.subscribe(({ uid }: { uid: string }) => setLicenseId(uid)); + } } public start(core: CoreStart, plugins: any) {} diff --git a/x-pack/legacy/plugins/maps/server/plugin.js b/x-pack/legacy/plugins/maps/server/plugin.js index 080796fd25d823..e6b474e1c78dde 100644 --- a/x-pack/legacy/plugins/maps/server/plugin.js +++ b/x-pack/legacy/plugins/maps/server/plugin.js @@ -5,16 +5,15 @@ */ import { i18n } from '@kbn/i18n'; import { APP_ID, APP_ICON, createMapPath, MAP_SAVED_OBJECT_TYPE } from '../common/constants'; -import { initRoutes } from './routes'; import { getEcommerceSavedObjects } from './sample_data/ecommerce_saved_objects'; import { getFlightsSavedObjects } from './sample_data/flights_saved_objects.js'; import { getWebLogsSavedObjects } from './sample_data/web_logs_saved_objects.js'; -import { checkLicense } from '../check_license'; -import { watchStatusAndLicenseToInitialize } from '../../../server/lib/watch_status_and_license_to_initialize'; +import { LICENSE_CHECK_STATE } from '../../../../plugins/licensing/server'; +import { initRoutes } from './routes'; export class MapPlugin { setup(core, plugins, __LEGACY) { - const { featuresPlugin } = plugins; + const { featuresPlugin, licensing } = plugins; let routesInitialized = false; featuresPlugin.registerFeature({ @@ -44,20 +43,13 @@ export class MapPlugin { }, }); - watchStatusAndLicenseToInitialize( - __LEGACY.plugins.xpackMainPlugin, - __LEGACY.pluginRef, - async license => { - if (license && license.maps && !routesInitialized) { - routesInitialized = true; - initRoutes(__LEGACY, license.uid); - } + licensing.license$.subscribe(license => { + const { state } = license.check('maps', 'basic'); + if (state === LICENSE_CHECK_STATE.Valid && !routesInitialized) { + routesInitialized = true; + initRoutes(__LEGACY, license.uid); } - ); - - __LEGACY.plugins.xpackMainPlugin.info - .feature(APP_ID) - .registerLicenseCheckResultsGenerator(checkLicense); + }); const sampleDataLinkLabel = i18n.translate('xpack.maps.sampleDataLinkLabel', { defaultMessage: 'Map', From 58f3dfb97c564a0659b2c782b06733526924df59 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Tue, 17 Dec 2019 17:55:37 -0700 Subject: [PATCH 36/60] [SIEM][Detection Engine] Adds timeline_id string to rules (#53343) ## Summary * Adds the timeline_id string to rules * Updates unit tests and fixes a few issues in the unit tests to make types more strict * Updates signal mapping to have it ### Checklist Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. ~~- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~~ ~~- [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)~~ ~~- [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~~ - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios ~~- [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~~ ### For maintainers ~~- [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~ - [x] This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process) --- .../routes/__mocks__/request_responses.ts | 17 +- .../routes/index/signals_mapping.json | 12 + .../routes/rules/create_rules_route.ts | 2 + .../routes/rules/update_rules_route.ts | 2 + .../routes/rules/utils.test.ts | 267 ++++++++++++++---- .../detection_engine/routes/rules/utils.ts | 1 + .../add_prepackaged_rules_schema.test.ts | 22 ++ .../schemas/add_prepackaged_rules_schema.ts | 2 + .../schemas/create_rules_schema.test.ts | 22 ++ .../routes/schemas/create_rules_schema.ts | 2 + .../routes/schemas/schemas.ts | 1 + .../schemas/update_rules_schema.test.ts | 18 ++ .../routes/schemas/update_rules_schema.ts | 2 + .../detection_engine/rules/create_rules.ts | 2 + .../rules/install_prepacked_rules.ts | 2 + .../detection_engine/rules/update_rules.ts | 2 + .../rules/queries/query_timelineid.json | 11 + .../rules/queries/query_with_everything.json | 1 + .../saved_query_with_everything.json | 3 +- .../updates/update_query_everything.json | 1 + .../rules/updates/update_timelineid.json | 4 + .../signals/__mocks__/es_results.ts | 1 + .../detection_engine/signals/build_rule.ts | 1 + .../signals/signal_rule_alert_type.ts | 1 + .../siem/server/lib/detection_engine/types.ts | 3 + 25 files changed, 338 insertions(+), 64 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_timelineid.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_timelineid.json diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 7d114178c6c929..ae205a814daaed 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -51,6 +51,7 @@ export const fullRuleAlertParamsRest = (): RuleAlertParamsRest => ({ max_signals: 100, created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', + timeline_id: 'timeline-id', }); export const typicalPayload = (): Partial => ({ @@ -227,14 +228,22 @@ export const getResult = (): RuleAlertType => ({ index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], falsePositives: [], from: 'now-6m', - filter: null, immutable: false, query: 'user.name: root or user.name: admin', language: 'kuery', outputIndex: '.siem-signals', - savedId: null, - meta: null, - filters: null, + savedId: 'some-id', + timelineId: 'some-timeline-id', + meta: { someMeta: 'someField' }, + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], riskScore: 50, maxSignals: 100, size: 1, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/signals_mapping.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/signals_mapping.json index 501522105bdbc3..afe9bac9d87fec 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/signals_mapping.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/signals_mapping.json @@ -33,6 +33,9 @@ "saved_id": { "type": "keyword" }, + "timeline_id": { + "type": "keyword" + }, "max_signals": { "type": "keyword" }, @@ -96,11 +99,20 @@ "filters": { "type": "object" }, + "created_at": { + "type": "date" + }, + "updated_at": { + "type": "date" + }, "created_by": { "type": "keyword" }, "updated_by": { "type": "keyword" + }, + "version": { + "type": "keyword" } } }, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts index 6fec45b024e845..476d5b8a49ba2d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -43,6 +43,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute = language, output_index: outputIndex, saved_id: savedId, + timeline_id: timelineId, meta, filters, rule_id: ruleId, @@ -99,6 +100,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute = language, outputIndex: finalIndex, savedId, + timelineId, meta, filters, ruleId: ruleId != null ? ruleId : uuid.v4(), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts index 154c8d7341ed32..ec3d9514fa5db8 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -37,6 +37,7 @@ export const createUpdateRulesRoute: Hapi.ServerRoute = { language, output_index: outputIndex, saved_id: savedId, + timeline_id: timelineId, meta, filters, rule_id: ruleId, @@ -75,6 +76,7 @@ export const createUpdateRulesRoute: Hapi.ServerRoute = { language, outputIndex, savedId, + timelineId, meta, filters, id, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index e05bdf764a09c9..e22c8737413927 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -15,13 +15,14 @@ import { } from './utils'; import { getResult } from '../__mocks__/request_responses'; import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; +import { OutputRuleAlertRest } from '../../types'; describe('utils', () => { describe('transformAlertToRule', () => { test('should work with a full data set', () => { const fullRule = getResult(); const rule = transformAlertToRule(fullRule); - expect(rule).toEqual({ + const expected: OutputRuleAlertRest = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -61,16 +62,31 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(rule).toEqual(expected); }); test('should work with a partial data set missing data', () => { const fullRule = getResult(); const { from, language, ...omitData } = transformAlertToRule(fullRule); - expect(omitData).toEqual({ + const expected: Partial = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -108,17 +124,32 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(omitData).toEqual(expected); }); test('should omit query if query is null', () => { const fullRule = getResult(); fullRule.params.query = null; const rule = transformAlertToRule(fullRule); - expect(rule).toEqual({ + const expected: Partial = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -157,17 +188,32 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(rule).toEqual(expected); }); test('should omit query if query is undefined', () => { const fullRule = getResult(); fullRule.params.query = undefined; const rule = transformAlertToRule(fullRule); - expect(rule).toEqual({ + const expected: Partial = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -206,10 +252,25 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(rule).toEqual(expected); }); test('should omit a mix of undefined, null, and missing fields', () => { @@ -217,7 +278,7 @@ describe('utils', () => { fullRule.params.query = undefined; fullRule.params.language = null; const { from, enabled, ...omitData } = transformAlertToRule(fullRule); - expect(omitData).toEqual({ + const expected: Partial = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -253,17 +314,32 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(omitData).toEqual(expected); }); test('should return enabled is equal to false', () => { const fullRule = getResult(); fullRule.enabled = false; const ruleWithEnabledFalse = transformAlertToRule(fullRule); - expect(ruleWithEnabledFalse).toEqual({ + const expected: OutputRuleAlertRest = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -303,17 +379,32 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(ruleWithEnabledFalse).toEqual(expected); }); test('should return immutable is equal to false', () => { const fullRule = getResult(); fullRule.params.immutable = false; const ruleWithEnabledFalse = transformAlertToRule(fullRule); - expect(ruleWithEnabledFalse).toEqual({ + const expected: OutputRuleAlertRest = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -353,17 +444,32 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(ruleWithEnabledFalse).toEqual(expected); }); test('should work with tags but filter out any internal tags', () => { const fullRule = getResult(); fullRule.tags = ['tag 1', 'tag 2', `${INTERNAL_IDENTIFIER}_some_other_value`]; const rule = transformAlertToRule(fullRule); - expect(rule).toEqual({ + const expected: OutputRuleAlertRest = { created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', created_by: 'elastic', @@ -403,10 +509,25 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', to: 'now', type: 'query', version: 1, - }); + }; + expect(rule).toEqual(expected); }); }); @@ -462,53 +583,66 @@ describe('utils', () => { const output = transformFindAlertsOrError({ data: [getResult()], }); - expect(output).toEqual({ - data: [ + const expected: OutputRuleAlertRest = { + created_by: 'elastic', + created_at: '2019-12-13T16:40:33.400Z', + updated_at: '2019-12-13T16:40:33.400Z', + description: 'Detecting root and admin users', + enabled: true, + false_positives: [], + from: 'now-6m', + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + immutable: false, + output_index: '.siem-signals', + index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + interval: '5m', + risk_score: 50, + rule_id: 'rule-1', + language: 'kuery', + max_signals: 100, + name: 'Detect Root/Admin Users', + query: 'user.name: root or user.name: admin', + references: ['http://www.example.com', 'https://ww.example.com'], + severity: 'high', + updated_by: 'elastic', + tags: [], + to: 'now', + type: 'query', + threats: [ { - created_by: 'elastic', - created_at: '2019-12-13T16:40:33.400Z', - updated_at: '2019-12-13T16:40:33.400Z', - description: 'Detecting root and admin users', - enabled: true, - false_positives: [], - from: 'now-6m', - id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - immutable: false, - output_index: '.siem-signals', - index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - interval: '5m', - risk_score: 50, - rule_id: 'rule-1', - language: 'kuery', - max_signals: 100, - name: 'Detect Root/Admin Users', - query: 'user.name: root or user.name: admin', - references: ['http://www.example.com', 'https://ww.example.com'], - severity: 'high', - updated_by: 'elastic', - tags: [], - to: 'now', - type: 'query', - threats: [ + framework: 'MITRE ATT&CK', + tactic: { + id: 'TA0040', + name: 'impact', + reference: 'https://attack.mitre.org/tactics/TA0040/', + }, + techniques: [ { - framework: 'MITRE ATT&CK', - tactic: { - id: 'TA0040', - name: 'impact', - reference: 'https://attack.mitre.org/tactics/TA0040/', - }, - techniques: [ - { - id: 'T1499', - name: 'endpoint denial of service', - reference: 'https://attack.mitre.org/techniques/T1499/', - }, - ], + id: 'T1499', + name: 'endpoint denial of service', + reference: 'https://attack.mitre.org/techniques/T1499/', }, ], - version: 1, }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', + version: 1, + }; + expect(output).toEqual({ + data: [expected], }); }); @@ -521,7 +655,7 @@ describe('utils', () => { describe('transformOrError', () => { test('outputs 200 if the data is of type siem alert', () => { const output = transformOrError(getResult()); - expect(output).toEqual({ + const expected: OutputRuleAlertRest = { created_by: 'elastic', created_at: '2019-12-13T16:40:33.400Z', updated_at: '2019-12-13T16:40:33.400Z', @@ -563,8 +697,23 @@ describe('utils', () => { ], }, ], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + meta: { + someMeta: 'someField', + }, + saved_id: 'some-id', + timeline_id: 'some-timeline-id', version: 1, - }); + }; + expect(output).toEqual(expected); }); test('returns 500 if the data is not of type siem alert', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index a041a5665e79c1..88261d872b0eaf 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -55,6 +55,7 @@ export const transformAlertToRule = (alert: RuleAlertType): Partial { }).error ).toBeFalsy(); }); + + test('validates with timeline_id', () => { + expect( + addPrepackagedRulesSchema.validate>({ + rule_id: 'rule-1', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + version: 1, + timeline_id: 'timeline-id', + }).error + ).toBeFalsy(); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts index 8a58f84f9e8481..c993b05cb5f299 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts @@ -20,6 +20,7 @@ import { query, language, saved_id, + timeline_id, meta, risk_score, max_signals, @@ -61,6 +62,7 @@ export const addPrepackagedRulesSchema = Joi.object({ then: Joi.required(), otherwise: Joi.forbidden(), }), + timeline_id, meta, risk_score: risk_score.required(), max_signals: max_signals.default(DEFAULT_MAX_SIGNALS), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index 4efea69db1f411..8dc00b66e97a3e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -1044,4 +1044,26 @@ describe('create rules schema', () => { }).error ).toBeFalsy(); }); + + test('timeline_id validates', () => { + expect( + createRulesSchema.validate>({ + rule_id: 'rule-1', + output_index: '.siem-signals', + risk_score: 50, + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'query', + references: ['index-1'], + query: 'some query', + language: 'kuery', + timeline_id: 'some_id', + }).error + ).toBeFalsy(); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts index 1814dc09b0c01d..614451312d04da 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts @@ -21,6 +21,7 @@ import { language, output_index, saved_id, + timeline_id, meta, risk_score, max_signals, @@ -55,6 +56,7 @@ export const createRulesSchema = Joi.object({ then: Joi.required(), otherwise: Joi.forbidden(), }), + timeline_id, meta, risk_score: risk_score.required(), max_signals: max_signals.default(DEFAULT_MAX_SIGNALS), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts index 99450fd4c7b1b7..68d3166c74d6da 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/schemas.ts @@ -23,6 +23,7 @@ export const query = Joi.string(); export const language = Joi.string().valid('kuery', 'lucene'); export const output_index = Joi.string(); export const saved_id = Joi.string(); +export const timeline_id = Joi.string(); export const meta = Joi.object(); export const max_signals = Joi.number().greater(0); export const name = Joi.string(); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index 606a30309b2ab7..1f00e0a13866a4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -866,4 +866,22 @@ describe('update rules schema', () => { }).error ).toBeTruthy(); }); + + test('timeline_id validates', () => { + expect( + updateRulesSchema.validate>({ + id: 'rule-1', + description: 'some description', + from: 'now-5m', + to: 'now', + index: ['index-1'], + name: 'some-name', + severity: 'severity', + interval: '5m', + type: 'saved_query', + saved_id: 'some id', + timeline_id: 'some-id', + }).error + ).toBeFalsy(); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts index cdca17c4197f8d..afd8a5fce48331 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts @@ -21,6 +21,7 @@ import { language, output_index, saved_id, + timeline_id, meta, risk_score, max_signals, @@ -51,6 +52,7 @@ export const updateRulesSchema = Joi.object({ language, output_index, saved_id, + timeline_id, meta, risk_score, max_signals, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index d640aa05af5bf1..441a630ae19ae1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -18,6 +18,7 @@ export const createRules = async ({ query, language, savedId, + timelineId, meta, filters, ruleId, @@ -53,6 +54,7 @@ export const createRules = async ({ language, outputIndex, savedId, + timelineId, meta, filters, maxSignals, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts index ec1e5eb6914e2d..9acfbf8c43221c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts @@ -25,6 +25,7 @@ export const installPrepackagedRules = async ( query, language, saved_id: savedId, + timeline_id: timelineId, meta, filters, rule_id: ruleId, @@ -53,6 +54,7 @@ export const installPrepackagedRules = async ( language, outputIndex, savedId, + timelineId, meta, filters, ruleId, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 689d6bdf175b5f..66c4526ae53de4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -73,6 +73,7 @@ export const updateRules = async ({ language, outputIndex, savedId, + timelineId, meta, filters, from, @@ -116,6 +117,7 @@ export const updateRules = async ({ language, outputIndex, savedId, + timelineId, meta, filters, index, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_timelineid.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_timelineid.json new file mode 100644 index 00000000000000..2f995029447ffe --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_timelineid.json @@ -0,0 +1,11 @@ +{ + "name": "Query which is disabled", + "description": "Example query which will is disabled and will not run after being posted", + "risk_score": 1, + "severity": "high", + "type": "query", + "from": "now-6m", + "to": "now", + "query": "user.name: root or user.name: admin", + "timeline_id": "timeline-id" +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json index 919cef392d0cdb..60095a0a6a8334 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_everything.json @@ -77,5 +77,6 @@ "http://www.example.com/some-article-about-attack", "Some plain text string here explaining why this is a valid thing to look out for" ], + "timeline_id": "timeline_id", "version": 1 } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/saved_queries/saved_query_with_everything.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/saved_queries/saved_query_with_everything.json index c4aaf4aae93c26..2628b69eb064d7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/saved_queries/saved_query_with_everything.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/saved_queries/saved_query_with_everything.json @@ -77,5 +77,6 @@ "http://www.example.com/some-article-about-attack", "Some plain text string here explaining why this is a valid thing to look out for" ], - "saved_id": "test-saved-id" + "saved_id": "test-saved-id", + "timeline_id": "test-timeline-id" } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json index 5bbae7e2bb061d..4da285e5b09bf9 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_query_everything.json @@ -77,5 +77,6 @@ "http://www.example.com/some-article-about-attack", "Some plain text string here explaining why this is a valid thing to look out for" ], + "timeline_id": "other-timeline-id", "version": 42 } diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_timelineid.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_timelineid.json new file mode 100644 index 00000000000000..8cfa3303f54a62 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_timelineid.json @@ -0,0 +1,4 @@ +{ + "rule_id": "query-rule-id", + "timeline_id": "other-timeline-id" +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index 619924032e3620..db5b3701a4fc29 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -30,6 +30,7 @@ export const sampleRuleAlertParams = ( maxSignals: maxSignals ? maxSignals : 10000, filters: undefined, savedId: undefined, + timelineId: undefined, meta: undefined, threats: undefined, version: 1, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts index 8a46a8231cc583..0a3526d32e511a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/build_rule.ts @@ -33,6 +33,7 @@ export const buildRule = ({ rule_id: ruleParams.ruleId, false_positives: ruleParams.falsePositives, saved_id: ruleParams.savedId, + timeline_id: ruleParams.timelineId, meta: ruleParams.meta, max_signals: ruleParams.maxSignals, risk_score: ruleParams.riskScore, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 08e4bcc69a9bbc..87d31abbc5371a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -41,6 +41,7 @@ export const signalRulesAlertType = ({ language: schema.nullable(schema.string()), outputIndex: schema.nullable(schema.string()), savedId: schema.nullable(schema.string()), + timelineId: schema.nullable(schema.string()), meta: schema.nullable(schema.object({}, { allowUnknowns: true })), query: schema.nullable(schema.string()), filters: schema.nullable(schema.arrayOf(schema.object({}, { allowUnknowns: true }))), diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index e1e7a7fb0a2bd0..f4a8263da6ba42 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -43,6 +43,7 @@ export interface RuleAlertParams { severity: string; tags: string[]; to: string; + timelineId: string | undefined | null; threats: ThreatParams[] | undefined | null; type: 'query' | 'saved_query'; version: number; @@ -58,6 +59,7 @@ export type RuleAlertParamsRest = Omit< | 'maxSignals' | 'savedId' | 'riskScore' + | 'timelineId' | 'outputIndex' | 'updatedAt' | 'createdAt' @@ -65,6 +67,7 @@ export type RuleAlertParamsRest = Omit< rule_id: RuleAlertParams['ruleId']; false_positives: RuleAlertParams['falsePositives']; saved_id: RuleAlertParams['savedId']; + timeline_id: RuleAlertParams['timelineId']; max_signals: RuleAlertParams['maxSignals']; risk_score: RuleAlertParams['riskScore']; output_index: RuleAlertParams['outputIndex']; From cb8436f248412f24422d26d2ca7bb6f48e5e4ddd Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Tue, 17 Dec 2019 18:11:17 -0800 Subject: [PATCH 37/60] Prevent sending request for rollup indices if we're on an anonymous path, e.g. /logout. (#53233) --- .../rollup_index_pattern_creation_config.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js index 3cf50c358b3e6f..07f2a674decc5d 100644 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js +++ b/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js @@ -5,11 +5,12 @@ */ import React from 'react'; -import { IndexPatternCreationConfig } from '../../../../../../src/legacy/core_plugins/management/public'; +import { i18n } from '@kbn/i18n'; +import { npSetup } from 'ui/new_platform'; import { RollupPrompt } from './components/rollup_prompt'; import { setHttpClient, getRollupIndices } from '../services/api'; -import { i18n } from '@kbn/i18n'; +import { IndexPatternCreationConfig } from '../../../../../../src/legacy/core_plugins/management/public'; const rollupIndexPatternTypeName = i18n.translate( 'xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultTypeName', @@ -63,7 +64,14 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig async setRollupIndices() { try { - this.rollupIndicesCapabilities = await getRollupIndices(); + // This is a hack intended to prevent the getRollupIndices() request from being sent if + // we're on /logout. There is a race condition that can arise on that page, whereby this + // request resolves after the logout request resolves, and un-clears the session ID. + const isAnonymous = npSetup.core.http.anonymousPaths.isAnonymous(window.location.pathname); + if (!isAnonymous) { + this.rollupIndicesCapabilities = await getRollupIndices(); + } + this.rollupIndices = Object.keys(this.rollupIndicesCapabilities); } catch (e) { // Silently swallow failure responses such as expired trials From 621643dfff6598df6e6d86a1ba5d55d726a45b9d Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 18 Dec 2019 02:27:38 +0000 Subject: [PATCH 38/60] [build] Add UBI7 docker target (#52735) * feat(NA): add ubi based docker build images step * chore(NA): remove ubiImageFlavor from appending to oss dir --- .../os_packages/create_os_package_tasks.js | 6 ++++- .../docker_generator/bundle_dockerfiles.js | 6 +++-- .../tasks/os_packages/docker_generator/run.js | 24 +++++++++++++++--- .../templates/build_docker_sh.template.js | 23 +++++++++++------ .../templates/dockerfile.template.js | 25 ++++++++++++++++--- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/dev/build/tasks/os_packages/create_os_package_tasks.js b/src/dev/build/tasks/os_packages/create_os_package_tasks.js index 3a328971538db1..0416dac0aad8ce 100644 --- a/src/dev/build/tasks/os_packages/create_os_package_tasks.js +++ b/src/dev/build/tasks/os_packages/create_os_package_tasks.js @@ -18,7 +18,7 @@ */ import { runFpm } from './run_fpm'; -import { runDockerGenerator } from './docker_generator'; +import { runDockerGenerator, runDockerGeneratorForUBI } from './docker_generator'; export const CreateDebPackageTask = { description: 'Creating deb package', @@ -45,6 +45,10 @@ export const CreateDockerPackageTask = { description: 'Creating docker package', async run(config, log, build) { + // Builds Docker targets for default and oss await runDockerGenerator(config, log, build); + + // Builds Docker target default with ubi7 base image + await runDockerGeneratorForUBI(config, log, build); }, }; diff --git a/src/dev/build/tasks/os_packages/docker_generator/bundle_dockerfiles.js b/src/dev/build/tasks/os_packages/docker_generator/bundle_dockerfiles.js index 65b0ffdfa5e813..bbcb6dfeeb1094 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/bundle_dockerfiles.js +++ b/src/dev/build/tasks/os_packages/docker_generator/bundle_dockerfiles.js @@ -22,9 +22,11 @@ import { compress, copyAll, mkdirp, write } from '../../../lib'; import { dockerfileTemplate } from './templates'; export async function bundleDockerFiles(config, log, build, scope) { - log.info(`Generating kibana${scope.imageFlavor} docker build context bundle`); + log.info( + `Generating kibana${scope.imageFlavor}${scope.ubiImageFlavor} docker build context bundle` + ); - const dockerFilesDirName = `kibana${scope.imageFlavor}-${scope.versionTag}-docker-build-context`; + const dockerFilesDirName = `kibana${scope.imageFlavor}${scope.ubiImageFlavor}-${scope.versionTag}-docker-build-context`; const dockerFilesBuildDir = resolve(scope.dockerBuildDir, dockerFilesDirName); const dockerFilesOutputDir = config.resolveFromTarget(`${dockerFilesDirName}.tar.gz`); diff --git a/src/dev/build/tasks/os_packages/docker_generator/run.js b/src/dev/build/tasks/os_packages/docker_generator/run.js index fcd95357790e51..7424b6f01b82b4 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/run.js +++ b/src/dev/build/tasks/os_packages/docker_generator/run.js @@ -29,20 +29,27 @@ const linkAsync = promisify(link); const unlinkAsync = promisify(unlink); const chmodAsync = promisify(chmod); -export async function runDockerGenerator(config, log, build) { +export async function runDockerGenerator(config, log, build, ubi = false) { + // UBI var config + const baseOSImage = ubi ? 'registry.access.redhat.com/ubi7/ubi-minimal:7.7' : 'centos:7'; + const ubiVersionTag = 'ubi7'; + const ubiImageFlavor = ubi ? `-${ubiVersionTag}` : ''; + + // General docker var config const license = build.isOss() ? 'ASL 2.0' : 'Elastic License'; const imageFlavor = build.isOss() ? '-oss' : ''; const imageTag = 'docker.elastic.co/kibana/kibana'; const versionTag = config.getBuildVersion(); const artifactTarball = `kibana${imageFlavor}-${versionTag}-linux-x86_64.tar.gz`; const artifactsDir = config.resolveFromTarget('.'); + // That would produce oss, default and default-ubi7 const dockerBuildDir = config.resolveFromRepo( 'build', 'kibana-docker', - build.isOss() ? 'oss' : 'default' + build.isOss() ? `oss` : `default${ubiImageFlavor}` ); const dockerOutputDir = config.resolveFromTarget( - `kibana${imageFlavor}-${versionTag}-docker.tar.gz` + `kibana${imageFlavor}${ubiImageFlavor}-${versionTag}-docker.tar.gz` ); const scope = { artifactTarball, @@ -53,6 +60,8 @@ export async function runDockerGenerator(config, log, build) { imageTag, dockerBuildDir, dockerOutputDir, + baseOSImage, + ubiImageFlavor, }; // Verify if we have the needed kibana target in order @@ -103,3 +112,12 @@ export async function runDockerGenerator(config, log, build) { // Pack Dockerfiles and create a target for them await bundleDockerFiles(config, log, build, scope); } + +export async function runDockerGeneratorForUBI(config, log, build) { + // Only run ubi docker image build for default distribution + if (build.isOss()) { + return; + } + + await runDockerGenerator(config, log, build, true); +} diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/build_docker_sh.template.js b/src/dev/build/tasks/os_packages/docker_generator/templates/build_docker_sh.template.js index 66f2fd65832e4a..4e8dfe188b8671 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/build_docker_sh.template.js +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/build_docker_sh.template.js @@ -19,21 +19,28 @@ import dedent from 'dedent'; -function generator({ imageTag, imageFlavor, versionTag, dockerOutputDir }) { +function generator({ + imageTag, + imageFlavor, + versionTag, + dockerOutputDir, + baseOSImage, + ubiImageFlavor, +}) { return dedent(` #!/usr/bin/env bash # # ** THIS IS AN AUTO-GENERATED FILE ** # set -euo pipefail - - docker pull centos:7 - - echo "Building: kibana${imageFlavor}-docker"; \\ - docker build -t ${imageTag}${imageFlavor}:${versionTag} -f Dockerfile . || exit 1; - docker save ${imageTag}${imageFlavor}:${versionTag} | gzip -c > ${dockerOutputDir} - + docker pull ${baseOSImage} + + echo "Building: kibana${imageFlavor}${ubiImageFlavor}-docker"; \\ + docker build -t ${imageTag}${imageFlavor}${ubiImageFlavor}:${versionTag} -f Dockerfile . || exit 1; + + docker save ${imageTag}${imageFlavor}${ubiImageFlavor}:${versionTag} | gzip -c > ${dockerOutputDir} + exit 0 `); } diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/dockerfile.template.js b/src/dev/build/tasks/os_packages/docker_generator/templates/dockerfile.template.js index 5228eed84cd595..25ae71856c12d0 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/dockerfile.template.js +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/dockerfile.template.js @@ -19,7 +19,14 @@ import dedent from 'dedent'; -function generator({ artifactTarball, versionTag, license, usePublicArtifact }) { +function generator({ + artifactTarball, + versionTag, + license, + usePublicArtifact, + baseOSImage, + ubiImageFlavor, +}) { const copyArtifactTarballInsideDockerOptFolder = () => { if (usePublicArtifact) { return `RUN cd /opt && curl --retry 8 -s -L -O https://artifacts.elastic.co/downloads/kibana/${artifactTarball} && cd -`; @@ -28,6 +35,14 @@ function generator({ artifactTarball, versionTag, license, usePublicArtifact }) return `COPY ${artifactTarball} /opt`; }; + const packageManager = () => { + if (ubiImageFlavor) { + return 'microdnf'; + } + + return 'yum'; + }; + return dedent(` # # ** THIS IS AN AUTO-GENERATED FILE ** @@ -37,7 +52,9 @@ function generator({ artifactTarball, versionTag, license, usePublicArtifact }) # Build stage 0 # Extract Kibana and make various file manipulations. ################################################################################ - FROM centos:7 AS prep_files + FROM ${baseOSImage} AS prep_files + # Add tar and gzip + RUN ${packageManager()} update -y && ${packageManager()} install -y tar gzip && ${packageManager()} clean all ${copyArtifactTarballInsideDockerOptFolder()} RUN mkdir /usr/share/kibana WORKDIR /usr/share/kibana @@ -53,11 +70,11 @@ function generator({ artifactTarball, versionTag, license, usePublicArtifact }) # Build stage 1 # Copy prepared files from the previous stage and complete the image. ################################################################################ - FROM centos:7 + FROM ${baseOSImage} EXPOSE 5601 # Add Reporting dependencies. - RUN yum update -y && yum install -y fontconfig freetype && yum clean all + RUN ${packageManager()} update -y && ${packageManager()} install -y fontconfig freetype shadow-utils && ${packageManager()} clean all # Add an init process, check the checksum to make sure it's a match RUN curl -L -o /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_amd64 From 528e49563178d164d3caa9f4b6805515ee238d18 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Tue, 17 Dec 2019 18:31:55 -0800 Subject: [PATCH 39/60] Add support for xpack.license_management.ui.enabled setting. (#53209) --- .../plugins/license_management/index.ts | 19 ++- .../public/management_section.ts | 17 ++- .../public/register_route.ts | 131 +++++++++--------- 3 files changed, 97 insertions(+), 70 deletions(-) diff --git a/x-pack/legacy/plugins/license_management/index.ts b/x-pack/legacy/plugins/license_management/index.ts index c621a96945c41d..e9fbb56e9d6acb 100644 --- a/x-pack/legacy/plugins/license_management/index.ts +++ b/x-pack/legacy/plugins/license_management/index.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Legacy } from 'kibana'; import { resolve } from 'path'; import { PLUGIN } from './common/constants'; -import { Legacy } from '../../../../kibana'; import { plugin } from './server/np_ready'; export function licenseManagement(kibana: any) { @@ -18,6 +18,23 @@ export function licenseManagement(kibana: any) { uiExports: { styleSheetPaths: resolve(__dirname, 'public/np_ready/application/index.scss'), managementSections: ['plugins/license_management/legacy'], + injectDefaultVars(server: Legacy.Server) { + const config = server.config(); + return { + licenseManagementUiEnabled: config.get('xpack.license_management.ui.enabled'), + }; + }, + }, + config(Joi: any) { + return Joi.object({ + // display menu item + ui: Joi.object({ + enabled: Joi.boolean().default(true), + }).default(), + + // enable plugin + enabled: Joi.boolean().default(true), + }).default(); }, init: (server: Legacy.Server) => { plugin({} as any).setup(server.newPlatform.setup.core, { diff --git a/x-pack/legacy/plugins/license_management/public/management_section.ts b/x-pack/legacy/plugins/license_management/public/management_section.ts index 4f69581fff0df6..c7232649857e3d 100644 --- a/x-pack/legacy/plugins/license_management/public/management_section.ts +++ b/x-pack/legacy/plugins/license_management/public/management_section.ts @@ -5,11 +5,16 @@ */ import { management } from 'ui/management'; +import chrome from 'ui/chrome'; import { BASE_PATH, PLUGIN } from '../common/constants'; -management.getSection('elasticsearch').register('license_management', { - visible: true, - display: PLUGIN.TITLE, - order: 99, - url: `#${BASE_PATH}home`, -}); +const licenseManagementUiEnabled = chrome.getInjected('licenseManagementUiEnabled'); + +if (licenseManagementUiEnabled) { + management.getSection('elasticsearch').register('license_management', { + visible: true, + display: PLUGIN.TITLE, + order: 99, + url: `#${BASE_PATH}home`, + }); +} diff --git a/x-pack/legacy/plugins/license_management/public/register_route.ts b/x-pack/legacy/plugins/license_management/public/register_route.ts index ad84f28c6b6d78..994a888ac020a6 100644 --- a/x-pack/legacy/plugins/license_management/public/register_route.ts +++ b/x-pack/legacy/plugins/license_management/public/register_route.ts @@ -9,6 +9,7 @@ import { App } from 'src/core/public'; /* Legacy Imports */ import { npSetup, npStart } from 'ui/new_platform'; import { MANAGEMENT_BREADCRUMB } from 'ui/management'; +import chrome from 'ui/chrome'; import routes from 'ui/routes'; // @ts-ignore import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; @@ -25,74 +26,78 @@ import { import { BASE_PATH } from '../common/constants'; -/* - This method handles the cleanup needed when route is scope is destroyed. It also prevents Angular - from destroying scope when route changes and both old route and new route are this same route. -*/ -const manageAngularLifecycle = ($scope: any, $route: any, unmount: () => void) => { - const lastRoute = $route.current; - const deregister = $scope.$on('$locationChangeSuccess', () => { - const currentRoute = $route.current; - // if templates are the same we are on the same route - if (lastRoute.$$route.template === currentRoute.$$route.template) { - // this prevents angular from destroying scope - $route.current = lastRoute; - } - }); - $scope.$on('$destroy', () => { - if (deregister) { - deregister(); - } - unmount(); - }); -}; +const licenseManagementUiEnabled = chrome.getInjected('licenseManagementUiEnabled'); + +if (licenseManagementUiEnabled) { + /* + This method handles the cleanup needed when route is scope is destroyed. It also prevents Angular + from destroying scope when route changes and both old route and new route are this same route. + */ + const manageAngularLifecycle = ($scope: any, $route: any, unmount: () => void) => { + const lastRoute = $route.current; + const deregister = $scope.$on('$locationChangeSuccess', () => { + const currentRoute = $route.current; + // if templates are the same we are on the same route + if (lastRoute.$$route.template === currentRoute.$$route.template) { + // this prevents angular from destroying scope + $route.current = lastRoute; + } + }); + $scope.$on('$destroy', () => { + if (deregister) { + deregister(); + } + unmount(); + }); + }; -const initializeTelemetry = ($injector: any) => { - const telemetryEnabled = $injector.get('telemetryEnabled'); - const Private = $injector.get('Private'); - const telemetryOptInProvider = Private(TelemetryOptInProvider); - setTelemetryOptInService(telemetryOptInProvider); - setTelemetryEnabled(telemetryEnabled); - setHttpClient($injector.get('$http')); -}; + const initializeTelemetry = ($injector: any) => { + const telemetryEnabled = $injector.get('telemetryEnabled'); + const Private = $injector.get('Private'); + const telemetryOptInProvider = Private(TelemetryOptInProvider); + setTelemetryOptInService(telemetryOptInProvider); + setTelemetryEnabled(telemetryEnabled); + setHttpClient($injector.get('$http')); + }; -const template = ` -
-
`; + const template = ` +
+
`; -routes.when(`${BASE_PATH}:view?`, { - template, - controllerAs: 'licenseManagement', - controller: class LicenseManagementController { - constructor($injector: any, $rootScope: any, $scope: any, $route: any) { - initializeTelemetry($injector); + routes.when(`${BASE_PATH}:view?`, { + template, + controllerAs: 'licenseManagement', + controller: class LicenseManagementController { + constructor($injector: any, $rootScope: any, $scope: any, $route: any) { + initializeTelemetry($injector); - $scope.$$postDigest(() => { - const element = document.getElementById('licenseReactRoot')!; + $scope.$$postDigest(() => { + const element = document.getElementById('licenseReactRoot')!; - const refreshXpack = async () => { - await xpackInfo.refresh($injector); - }; + const refreshXpack = async () => { + await xpackInfo.refresh($injector); + }; - plugin({} as any).setup( - { - ...npSetup.core, - application: { - ...npSetup.core.application, - async register(app: App) { - const unmountApp = await app.mount({ ...npStart } as any, { - element, - appBasePath: '', - }); - manageAngularLifecycle($scope, $route, unmountApp as any); + plugin({} as any).setup( + { + ...npSetup.core, + application: { + ...npSetup.core.application, + async register(app: App) { + const unmountApp = await app.mount({ ...npStart } as any, { + element, + appBasePath: '', + }); + manageAngularLifecycle($scope, $route, unmountApp as any); + }, }, }, - }, - { - __LEGACY: { xpackInfo, refreshXpack, MANAGEMENT_BREADCRUMB }, - } - ); - }); - } - } as any, -} as any); + { + __LEGACY: { xpackInfo, refreshXpack, MANAGEMENT_BREADCRUMB }, + } + ); + }); + } + } as any, + } as any); +} From fd97982b6355bdc7af99573348d122c282a0b521 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 18 Dec 2019 04:00:11 +0000 Subject: [PATCH 40/60] docs(NA): fix broken link for dockerfiles repo (#53448) --- docs/setup/docker.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup/docker.asciidoc b/docs/setup/docker.asciidoc index f3e7273adedeeb..8fd7b0490e194a 100644 --- a/docs/setup/docker.asciidoc +++ b/docs/setup/docker.asciidoc @@ -5,7 +5,7 @@ base image is https://hub.docker.com/_/centos/[centos:7]. A list of all published Docker images and tags is available at https://www.docker.elastic.co[www.docker.elastic.co]. The source code is in -https://github.com/elastic/kibana-docker/tree/{branch}[GitHub]. +https://github.com/elastic/dockerfiles/tree/{branch}/kibana[GitHub]. These images are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. From 73a80d649be3fb911d503c5cd7d2edb19e1d0aae Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 18 Dec 2019 06:27:16 +0100 Subject: [PATCH 41/60] [Timelion] deangularize and typescriptify saved_object usage (#53125) --- .../core_plugins/timelion/public/app.js | 8 +- .../timelion/public/services/_saved_sheet.js | 82 ------------------- .../timelion/public/services/_saved_sheet.ts | 79 ++++++++++++++++++ ...et_register.js => saved_sheet_register.ts} | 6 +- .../{saved_sheets.js => saved_sheets.ts} | 29 ++++--- 5 files changed, 103 insertions(+), 101 deletions(-) delete mode 100644 src/legacy/core_plugins/timelion/public/services/_saved_sheet.js create mode 100644 src/legacy/core_plugins/timelion/public/services/_saved_sheet.ts rename src/legacy/core_plugins/timelion/public/services/{saved_sheet_register.js => saved_sheet_register.ts} (84%) rename src/legacy/core_plugins/timelion/public/services/{saved_sheets.js => saved_sheets.ts} (71%) diff --git a/src/legacy/core_plugins/timelion/public/app.js b/src/legacy/core_plugins/timelion/public/app.js index 82f6d56f8f22aa..bff847becb7a82 100644 --- a/src/legacy/core_plugins/timelion/public/app.js +++ b/src/legacy/core_plugins/timelion/public/app.js @@ -40,6 +40,9 @@ import 'ui/directives/saved_object_finder'; import 'ui/directives/listen'; import 'ui/kbn_top_nav'; import 'ui/saved_objects/ui/saved_object_save_as_checkbox'; +import './services/saved_sheets'; +import './services/_saved_sheet'; +import './services/saved_sheet_register'; import rootTemplate from 'plugins/timelion/index.html'; @@ -57,13 +60,8 @@ document.title = 'Timelion - Kibana'; const app = require('ui/modules').get('apps/timelion', []); -require('plugins/timelion/services/saved_sheets'); -require('plugins/timelion/services/_saved_sheet'); - require('./vis'); -SavedObjectRegistryProvider.register(require('plugins/timelion/services/saved_sheet_register')); - require('ui/routes').enable(); require('ui/routes').when('/:id?', { diff --git a/src/legacy/core_plugins/timelion/public/services/_saved_sheet.js b/src/legacy/core_plugins/timelion/public/services/_saved_sheet.js deleted file mode 100644 index 8875a84d4d3a1d..00000000000000 --- a/src/legacy/core_plugins/timelion/public/services/_saved_sheet.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { uiModules } from 'ui/modules'; -import { createLegacyClass } from 'ui/utils/legacy_class'; -import { SavedObjectProvider } from 'ui/saved_objects/saved_object'; -const module = uiModules.get('app/timelion'); - -// Used only by the savedSheets service, usually no reason to change this -module.factory('SavedSheet', function(Private, config) { - // SavedSheet constructor. Usually you'd interact with an instance of this. - // ID is option, without it one will be generated on save. - const SavedObject = Private(SavedObjectProvider); - createLegacyClass(SavedSheet).inherits(SavedObject); - function SavedSheet(id) { - // Gives our SavedSheet the properties of a SavedObject - SavedObject.call(this, { - type: SavedSheet.type, - mapping: SavedSheet.mapping, - - // if this is null/undefined then the SavedObject will be assigned the defaults - id: id, - - // default values that will get assigned if the doc is new - defaults: { - title: 'New TimeLion Sheet', - hits: 0, - description: '', - timelion_sheet: ['.es(*)'], - timelion_interval: 'auto', - timelion_chart_height: 275, - timelion_columns: config.get('timelion:default_columns') || 2, - timelion_rows: config.get('timelion:default_rows') || 2, - version: 1, - }, - }); - - this.showInRecentlyAccessed = true; - } - - // save these objects with the 'sheet' type - SavedSheet.type = 'timelion-sheet'; - - // if type:sheet has no mapping, we push this mapping into ES - SavedSheet.mapping = { - title: 'text', - hits: 'integer', - description: 'text', - timelion_sheet: 'text', - timelion_interval: 'keyword', - timelion_other_interval: 'keyword', - timelion_chart_height: 'integer', - timelion_columns: 'integer', - timelion_rows: 'integer', - version: 'integer', - }; - - // Order these fields to the top, the rest are alphabetical - SavedSheet.fieldOrder = ['title', 'description']; - - SavedSheet.prototype.getFullPath = function() { - return `/app/timelion#/${this.id}`; - }; - - return SavedSheet; -}); diff --git a/src/legacy/core_plugins/timelion/public/services/_saved_sheet.ts b/src/legacy/core_plugins/timelion/public/services/_saved_sheet.ts new file mode 100644 index 00000000000000..1e956cbd3e5ac9 --- /dev/null +++ b/src/legacy/core_plugins/timelion/public/services/_saved_sheet.ts @@ -0,0 +1,79 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { createSavedObjectClass } from 'ui/saved_objects/saved_object'; +import { SavedObjectKibanaServices } from 'ui/saved_objects/types'; +import { IUiSettingsClient } from 'kibana/public'; + +// Used only by the savedSheets service, usually no reason to change this +export function createSavedSheetClass( + services: SavedObjectKibanaServices, + config: IUiSettingsClient +) { + const SavedObjectClass = createSavedObjectClass(services); + + class SavedSheet extends SavedObjectClass { + static type = 'timelion-sheet'; + + // if type:sheet has no mapping, we push this mapping into ES + static mapping = { + title: 'text', + hits: 'integer', + description: 'text', + timelion_sheet: 'text', + timelion_interval: 'keyword', + timelion_other_interval: 'keyword', + timelion_chart_height: 'integer', + timelion_columns: 'integer', + timelion_rows: 'integer', + version: 'integer', + }; + + // Order these fields to the top, the rest are alphabetical + static fieldOrder = ['title', 'description']; + // SavedSheet constructor. Usually you'd interact with an instance of this. + // ID is option, without it one will be generated on save. + constructor(id: string) { + super({ + type: SavedSheet.type, + mapping: SavedSheet.mapping, + + // if this is null/undefined then the SavedObject will be assigned the defaults + id, + + // default values that will get assigned if the doc is new + defaults: { + title: 'New TimeLion Sheet', + hits: 0, + description: '', + timelion_sheet: ['.es(*)'], + timelion_interval: 'auto', + timelion_chart_height: 275, + timelion_columns: config.get('timelion:default_columns') || 2, + timelion_rows: config.get('timelion:default_rows') || 2, + version: 1, + }, + }); + this.showInRecentlyAccessed = true; + this.getFullPath = () => `/app/timelion#/${this.id}`; + } + } + + return SavedSheet; +} diff --git a/src/legacy/core_plugins/timelion/public/services/saved_sheet_register.js b/src/legacy/core_plugins/timelion/public/services/saved_sheet_register.ts similarity index 84% rename from src/legacy/core_plugins/timelion/public/services/saved_sheet_register.js rename to src/legacy/core_plugins/timelion/public/services/saved_sheet_register.ts index 0353a4d742dd37..6bfbacb95b62e9 100644 --- a/src/legacy/core_plugins/timelion/public/services/saved_sheet_register.js +++ b/src/legacy/core_plugins/timelion/public/services/saved_sheet_register.ts @@ -16,9 +16,9 @@ * specific language governing permissions and limitations * under the License. */ - +import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry'; import './saved_sheets'; -export default function savedSearchObjectFn(savedSheets) { +SavedObjectRegistryProvider.register((savedSheets: any) => { return savedSheets; -} +}); diff --git a/src/legacy/core_plugins/timelion/public/services/saved_sheets.js b/src/legacy/core_plugins/timelion/public/services/saved_sheets.ts similarity index 71% rename from src/legacy/core_plugins/timelion/public/services/saved_sheets.js rename to src/legacy/core_plugins/timelion/public/services/saved_sheets.ts index 064b59a0d45d9c..d851b5a8636581 100644 --- a/src/legacy/core_plugins/timelion/public/services/saved_sheets.js +++ b/src/legacy/core_plugins/timelion/public/services/saved_sheets.ts @@ -16,12 +16,13 @@ * specific language governing permissions and limitations * under the License. */ - -import { SavedObjectLoader, SavedObjectsClientProvider } from 'ui/saved_objects'; +import { npStart } from 'ui/new_platform'; +import { SavedObjectLoader } from 'ui/saved_objects'; +// @ts-ignore import { savedObjectManagementRegistry } from 'plugins/kibana/management/saved_object_registry'; +// @ts-ignore import { uiModules } from 'ui/modules'; -import './_saved_sheet.js'; -import { npStart } from '../../../../ui/public/new_platform'; +import { createSavedSheetClass } from './_saved_sheet'; const module = uiModules.get('app/sheet'); @@ -33,17 +34,23 @@ savedObjectManagementRegistry.register({ }); // This is the only thing that gets injected into controllers -module.service('savedSheets', function(Private, SavedSheet, kbnUrl) { - const savedObjectClient = Private(SavedObjectsClientProvider); +module.service('savedSheets', function() { + const savedObjectsClient = npStart.core.savedObjects.client; + const services = { + savedObjectsClient, + indexPatterns: npStart.plugins.data.indexPatterns, + chrome: npStart.core.chrome, + overlays: npStart.core.overlays, + }; + + const SavedSheet = createSavedSheetClass(services, npStart.core.uiSettings); + const savedSheetLoader = new SavedObjectLoader( SavedSheet, - savedObjectClient, + savedObjectsClient, npStart.core.chrome ); - savedSheetLoader.urlFor = function(id) { - return kbnUrl.eval('#/{{id}}', { id: id }); - }; - + savedSheetLoader.urlFor = id => `#/${encodeURIComponent(id)}`; // Customize loader properties since adding an 's' on type doesn't work for type 'timelion-sheet'. savedSheetLoader.loaderProperties = { name: 'timelion-sheet', From b1273e25b7b299a6f856eb145eeb87abaa137da8 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 18 Dec 2019 10:46:07 +0300 Subject: [PATCH 42/60] value suggestions server route -> data plugin (#53191) * value suggestions server route -> data plugin Closes #52842 * fix PR comments * fix PR comments --- src/legacy/core_plugins/kibana/index.js | 2 - .../suggestions/register_value_suggestions.js | 117 --------------- .../data/common/index_patterns/types.ts | 1 + .../autocomplete/autocomplete_service.ts | 29 ++++ .../data/server/autocomplete/index.ts} | 6 +- .../data/server/autocomplete/routes.ts | 27 ++++ .../autocomplete/value_suggestions_route.ts | 135 ++++++++++++++++++ src/plugins/data/server/index.ts | 1 + .../data/server/index_patterns/index.ts | 2 + .../data/server/index_patterns/utils.ts | 47 ++++++ src/plugins/data/server/plugin.ts | 7 + 11 files changed, 250 insertions(+), 124 deletions(-) delete mode 100644 src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js create mode 100644 src/plugins/data/server/autocomplete/autocomplete_service.ts rename src/{legacy/core_plugins/kibana/server/routes/api/suggestions/index.js => plugins/data/server/autocomplete/index.ts} (83%) create mode 100644 src/plugins/data/server/autocomplete/routes.ts create mode 100644 src/plugins/data/server/autocomplete/value_suggestions_route.ts create mode 100644 src/plugins/data/server/index_patterns/utils.ts diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js index 8dc470e20c6198..dd741197376575 100644 --- a/src/legacy/core_plugins/kibana/index.js +++ b/src/legacy/core_plugins/kibana/index.js @@ -27,7 +27,6 @@ import { exportApi } from './server/routes/api/export'; import { homeApi } from './server/routes/api/home'; import { managementApi } from './server/routes/api/management'; import { scriptsApi } from './server/routes/api/scripts'; -import { registerSuggestionsApi } from './server/routes/api/suggestions'; import { registerKqlTelemetryApi } from './server/routes/api/kql_telemetry'; import { registerFieldFormats } from './server/field_formats/register'; import { registerTutorials } from './server/tutorials/register'; @@ -331,7 +330,6 @@ export default function(kibana) { exportApi(server); homeApi(server); managementApi(server); - registerSuggestionsApi(server); registerKqlTelemetryApi(server); registerFieldFormats(server); registerTutorials(server); diff --git a/src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js b/src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js deleted file mode 100644 index 6a6276234e5503..00000000000000 --- a/src/legacy/core_plugins/kibana/server/routes/api/suggestions/register_value_suggestions.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { get, map } from 'lodash'; -import { abortableRequestHandler } from '../../../../../elasticsearch/lib/abortable_request_handler'; - -export function registerValueSuggestions(server) { - const serverConfig = server.config(); - const autocompleteTerminateAfter = serverConfig.get('kibana.autocompleteTerminateAfter'); - const autocompleteTimeout = serverConfig.get('kibana.autocompleteTimeout'); - server.route({ - path: '/api/kibana/suggestions/values/{index}', - method: ['POST'], - handler: abortableRequestHandler(async function(signal, req) { - const { index } = req.params; - const { field: fieldName, query, boolFilter } = req.payload; - const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); - - const savedObjectsClient = req.getSavedObjectsClient(); - const savedObjectsResponse = await savedObjectsClient.find({ - type: 'index-pattern', - fields: ['fields'], - search: `"${index}"`, - searchFields: ['title'], - }); - const indexPattern = - savedObjectsResponse.total > 0 ? savedObjectsResponse.saved_objects[0] : null; - const fields = indexPattern ? JSON.parse(indexPattern.attributes.fields) : null; - const field = fields ? fields.find(field => field.name === fieldName) : fieldName; - - const body = getBody( - { field, query, boolFilter }, - autocompleteTerminateAfter, - autocompleteTimeout - ); - - try { - const response = await callWithRequest(req, 'search', { index, body }, { signal }); - const buckets = - get(response, 'aggregations.suggestions.buckets') || - get(response, 'aggregations.nestedSuggestions.suggestions.buckets') || - []; - const suggestions = map(buckets, 'key'); - return suggestions; - } catch (error) { - throw server.plugins.elasticsearch.handleESError(error); - } - }), - }); -} - -function getBody({ field, query, boolFilter = [] }, terminateAfter, timeout) { - // Helps ensure that the regex is not evaluated eagerly against the terms dictionary - const executionHint = 'map'; - - // We don't care about the accuracy of the counts, just the content of the terms, so this reduces - // the amount of information that needs to be transmitted to the coordinating node - const shardSize = 10; - - const body = { - size: 0, - timeout: `${timeout}ms`, - terminate_after: terminateAfter, - query: { - bool: { - filter: boolFilter, - }, - }, - aggs: { - suggestions: { - terms: { - field: field.name || field, - include: `${getEscapedQuery(query)}.*`, - execution_hint: executionHint, - shard_size: shardSize, - }, - }, - }, - }; - - if (field.subType && field.subType.nested) { - return { - ...body, - aggs: { - nestedSuggestions: { - nested: { - path: field.subType.nested.path, - }, - aggs: body.aggs, - }, - }, - }; - } - - return body; -} - -function getEscapedQuery(query = '') { - // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#_standard_operators - return query.replace(/[.?+*|{}[\]()"\\#@&<>~]/g, match => `\\${match}`); -} diff --git a/src/plugins/data/common/index_patterns/types.ts b/src/plugins/data/common/index_patterns/types.ts index 0a1ba483422442..98cdd20ea4b846 100644 --- a/src/plugins/data/common/index_patterns/types.ts +++ b/src/plugins/data/common/index_patterns/types.ts @@ -20,6 +20,7 @@ import { IFieldType } from './fields'; export interface IIndexPattern { + [key: string]: any; fields: IFieldType[]; title: string; id?: string; diff --git a/src/plugins/data/server/autocomplete/autocomplete_service.ts b/src/plugins/data/server/autocomplete/autocomplete_service.ts new file mode 100644 index 00000000000000..1b85321aa2185e --- /dev/null +++ b/src/plugins/data/server/autocomplete/autocomplete_service.ts @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CoreSetup, Plugin } from 'kibana/server'; +import { registerRoutes } from './routes'; + +export class AutocompleteService implements Plugin { + public setup(core: CoreSetup) { + registerRoutes(core); + } + + public start() {} +} diff --git a/src/legacy/core_plugins/kibana/server/routes/api/suggestions/index.js b/src/plugins/data/server/autocomplete/index.ts similarity index 83% rename from src/legacy/core_plugins/kibana/server/routes/api/suggestions/index.js rename to src/plugins/data/server/autocomplete/index.ts index 15110b192ee33c..6c10a8c98bdbf7 100644 --- a/src/legacy/core_plugins/kibana/server/routes/api/suggestions/index.js +++ b/src/plugins/data/server/autocomplete/index.ts @@ -17,8 +17,4 @@ * under the License. */ -import { registerValueSuggestions } from './register_value_suggestions'; - -export function registerSuggestionsApi(server) { - registerValueSuggestions(server); -} +export { AutocompleteService } from './autocomplete_service'; diff --git a/src/plugins/data/server/autocomplete/routes.ts b/src/plugins/data/server/autocomplete/routes.ts new file mode 100644 index 00000000000000..9134287d2b8ff4 --- /dev/null +++ b/src/plugins/data/server/autocomplete/routes.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CoreSetup } from 'kibana/server'; +import { registerValueSuggestionsRoute } from './value_suggestions_route'; + +export function registerRoutes({ http }: CoreSetup): void { + const router = http.createRouter(); + + registerValueSuggestionsRoute(router); +} diff --git a/src/plugins/data/server/autocomplete/value_suggestions_route.ts b/src/plugins/data/server/autocomplete/value_suggestions_route.ts new file mode 100644 index 00000000000000..b415e83becf930 --- /dev/null +++ b/src/plugins/data/server/autocomplete/value_suggestions_route.ts @@ -0,0 +1,135 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { get, map } from 'lodash'; +import { schema } from '@kbn/config-schema'; +import { IRouter } from 'kibana/server'; + +import { IFieldType, indexPatterns, esFilters } from '../index'; + +export function registerValueSuggestionsRoute(router: IRouter) { + router.post( + { + path: '/api/kibana/suggestions/values/{index}', + validate: { + params: schema.object( + { + index: schema.string(), + }, + { allowUnknowns: false } + ), + body: schema.object( + { + field: schema.string(), + query: schema.string(), + boolFilter: schema.maybe(schema.any()), + }, + { allowUnknowns: false } + ), + }, + }, + async (context, request, response) => { + const { client: uiSettings } = context.core.uiSettings; + const { field: fieldName, query, boolFilter } = request.body; + const { index } = request.params; + const { dataClient } = context.core.elasticsearch; + + const autocompleteSearchOptions = { + timeout: await uiSettings.get('kibana.autocompleteTimeout'), + terminate_after: await uiSettings.get('kibana.autocompleteTerminateAfter'), + }; + + const indexPattern = await indexPatterns.findIndexPatternById( + context.core.savedObjects.client, + index + ); + + const field = indexPattern && indexPatterns.getFieldByName(fieldName, indexPattern); + const body = await getBody(autocompleteSearchOptions, field || fieldName, query, boolFilter); + + try { + const result = await dataClient.callAsCurrentUser('search', { index, body }); + + const buckets: any[] = + get(result, 'aggregations.suggestions.buckets') || + get(result, 'aggregations.nestedSuggestions.suggestions.buckets'); + + return response.ok({ body: map(buckets || [], 'key') }); + } catch (error) { + return response.internalError({ body: error }); + } + } + ); +} + +async function getBody( + { timeout, terminate_after }: Record, + field: IFieldType | string, + query: string, + boolFilter: esFilters.Filter[] = [] +) { + const isFieldObject = (f: any): f is IFieldType => Boolean(f && f.name); + + // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#_standard_operators + const getEscapedQuery = (q: string = '') => + q.replace(/[.?+*|{}[\]()"\\#@&<>~]/g, match => `\\${match}`); + + // Helps ensure that the regex is not evaluated eagerly against the terms dictionary + const executionHint = 'map'; + + // We don't care about the accuracy of the counts, just the content of the terms, so this reduces + // the amount of information that needs to be transmitted to the coordinating node + const shardSize = 10; + const body = { + size: 0, + timeout, + terminate_after, + query: { + bool: { + filter: boolFilter, + }, + }, + aggs: { + suggestions: { + terms: { + field: isFieldObject(field) ? field.name : field, + include: `${getEscapedQuery(query)}.*`, + execution_hint: executionHint, + shard_size: shardSize, + }, + }, + }, + }; + + if (isFieldObject(field) && field.subType && field.subType.nested) { + return { + ...body, + aggs: { + nestedSuggestions: { + nested: { + path: field.subType.nested.path, + }, + aggs: body.aggs, + }, + }, + }; + } + + return body; +} diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 022eb0ae502958..fe96c494bd9ff4 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -57,6 +57,7 @@ export { IndexPatternsFetcher, FieldDescriptor, shouldReadFieldFromDocValues, + indexPatterns, } from './index_patterns'; export * from './search'; export { diff --git a/src/plugins/data/server/index_patterns/index.ts b/src/plugins/data/server/index_patterns/index.ts index 6937fa22c4e5d1..b303ae30ea810b 100644 --- a/src/plugins/data/server/index_patterns/index.ts +++ b/src/plugins/data/server/index_patterns/index.ts @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import * as indexPatterns from './utils'; export { IndexPatternsFetcher, FieldDescriptor, shouldReadFieldFromDocValues } from './fetcher'; export { IndexPatternsService } from './index_patterns_service'; +export { indexPatterns }; diff --git a/src/plugins/data/server/index_patterns/utils.ts b/src/plugins/data/server/index_patterns/utils.ts new file mode 100644 index 00000000000000..b7adafaeb3e94b --- /dev/null +++ b/src/plugins/data/server/index_patterns/utils.ts @@ -0,0 +1,47 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SavedObjectsClientContract } from 'kibana/server'; +import { IIndexPattern, IFieldType } from '../../common'; + +export const getFieldByName = ( + fieldName: string, + indexPattern: IIndexPattern +): IFieldType | undefined => { + const fields: IFieldType[] = indexPattern && JSON.parse(indexPattern.attributes.fields); + const field = fields && fields.find(f => f.name === fieldName); + + return field; +}; + +export const findIndexPatternById = async ( + savedObjectsClient: SavedObjectsClientContract, + index: string +): Promise => { + const savedObjectsResponse = await savedObjectsClient.find({ + type: 'index-pattern', + fields: ['fields'], + search: `"${index}"`, + searchFields: ['title'], + }); + + if (savedObjectsResponse.total > 0) { + return (savedObjectsResponse.saved_objects[0] as unknown) as IIndexPattern; + } +}; diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index e81250e653ebd3..6df0a11e7538dd 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -21,18 +21,25 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../.. import { IndexPatternsService } from './index_patterns'; import { ISearchSetup } from './search'; import { SearchService } from './search/search_service'; +import { AutocompleteService } from './autocomplete'; export interface DataPluginSetup { search: ISearchSetup; } + export class DataServerPlugin implements Plugin { private readonly searchService: SearchService; + private readonly autocompleteService = new AutocompleteService(); private readonly indexPatterns = new IndexPatternsService(); + constructor(initializerContext: PluginInitializerContext) { this.searchService = new SearchService(initializerContext); } + public setup(core: CoreSetup) { this.indexPatterns.setup(core); + this.autocompleteService.setup(core); + return { search: this.searchService.setup(core), }; From 63379ac0745143948922bf9f1434e1fb8a00d46c Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 18 Dec 2019 08:47:49 +0100 Subject: [PATCH 43/60] [Uptime] Uptime date picker will use commonly used ranges from advance settings (#52944) * Uptime date picker will use common ranges from advance settings * removed duplicate constant --- .../uptime/common/constants/capabilities.ts | 3 + .../plugins/uptime/common/constants/index.ts | 2 +- .../uptime_date_picker.test.tsx.snap | 287 ++++++++++++++++++ .../__tests__/uptime_date_picker.test.tsx | 47 +++ .../functional/uptime_date_picker.tsx | 25 +- .../framework/new_platform_adapter.tsx | 10 +- .../plugins/uptime/public/uptime_app.tsx | 10 +- 7 files changed, 376 insertions(+), 8 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap create mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/__tests__/uptime_date_picker.test.tsx diff --git a/x-pack/legacy/plugins/uptime/common/constants/capabilities.ts b/x-pack/legacy/plugins/uptime/common/constants/capabilities.ts index 1c9ae581749580..68cc114182afcc 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/capabilities.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/capabilities.ts @@ -5,3 +5,6 @@ */ export const INTEGRATED_SOLUTIONS = ['apm', 'infrastructure', 'logs']; + +export const DEFAULT_TIMEPICKER_QUICK_RANGES = 'timepicker:quickRanges'; +export const DEFAULT_DARK_MODE = 'theme:darkMode'; diff --git a/x-pack/legacy/plugins/uptime/common/constants/index.ts b/x-pack/legacy/plugins/uptime/common/constants/index.ts index 40ad1ff1d40b30..e3c4352f0a484c 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/index.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/index.ts @@ -8,6 +8,6 @@ export { CHART_FORMAT_LIMITS } from './chart_format_limits'; export { CLIENT_DEFAULTS } from './client_defaults'; export { CONTEXT_DEFAULTS } from './context_defaults'; export { INDEX_NAMES } from './index_names'; -export { INTEGRATED_SOLUTIONS } from './capabilities'; +export * from './capabilities'; export { PLUGIN } from './plugin'; export { QUERY, STATES } from './query'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap new file mode 100644 index 00000000000000..8a49cac07692e4 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap @@ -0,0 +1,287 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UptimeDatePicker component renders properly with mock data 1`] = ` +
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + + +
+
+`; + +exports[`UptimeDatePicker component renders properly without commonlyUsedRanges prop 1`] = ` +
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + + +
+
+`; + +exports[`UptimeDatePicker component validates props with shallow render 1`] = ` + +`; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/uptime_date_picker.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/uptime_date_picker.test.tsx new file mode 100644 index 00000000000000..93fa0b505a891f --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/uptime_date_picker.test.tsx @@ -0,0 +1,47 @@ +/* + * 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 { shallowWithIntl, renderWithIntl } from 'test_utils/enzyme_helpers'; +import React from 'react'; +import { UptimeDatePicker, CommonlyUsedRange } from '../uptime_date_picker'; + +describe('UptimeDatePicker component', () => { + let commonlyUsedRange: CommonlyUsedRange[]; + + beforeEach(() => { + commonlyUsedRange = [ + { from: 'now/d', to: 'now/d', display: 'Today' }, + { from: 'now/w', to: 'now/w', display: 'This week' }, + { from: 'now-15m', to: 'now', display: 'Last 15 minutes' }, + { from: 'now-30m', to: 'now', display: 'Last 30 minutes' }, + { from: 'now-1h', to: 'now', display: 'Last 1 hour' }, + { from: 'now-24h', to: 'now', display: 'Last 24 hours' }, + { from: 'now-7d', to: 'now', display: 'Last 7 days' }, + { from: 'now-30d', to: 'now', display: 'Last 30 days' }, + { from: 'now-90d', to: 'now', display: 'Last 90 days' }, + { from: 'now-1y', to: 'now', display: 'Last 2 year' }, + ]; + }); + + it('validates props with shallow render', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchSnapshot(); + }); + + it('renders properly with mock data', () => { + const component = renderWithIntl( + + ); + expect(component).toMatchSnapshot(); + }); + + it('renders properly without commonlyUsedRanges prop', () => { + const component = renderWithIntl(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/uptime_date_picker.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/uptime_date_picker.tsx index 78e69a68afbd88..ebd0cd1e4ae850 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/uptime_date_picker.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/uptime_date_picker.tsx @@ -20,21 +20,40 @@ interface SuperDateRangePickerRefreshChangedEvent { refreshInterval?: number; } +export interface CommonlyUsedRange { + from: string; + to: string; + display: string; +} + interface Props { refreshApp: () => void; + commonlyUsedRanges?: CommonlyUsedRange[]; } type UptimeDatePickerProps = Props; -export const UptimeDatePicker = (props: UptimeDatePickerProps) => { - const { refreshApp } = props; +export const UptimeDatePicker = ({ refreshApp, commonlyUsedRanges }: UptimeDatePickerProps) => { const [getUrlParams, updateUrl] = useUrlParams(); const { autorefreshInterval, autorefreshIsPaused, dateRangeStart, dateRangeEnd } = getUrlParams(); + + const euiCommonlyUsedRanges = commonlyUsedRanges + ? commonlyUsedRanges.map( + ({ from, to, display }: { from: string; to: string; display: string }) => { + return { + start: from, + end: to, + label: display, + }; + } + ) + : CLIENT_DEFAULTS.COMMONLY_USED_DATE_RANGES; + return ( { diff --git a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx index 94bfe79a6ca6e4..b7ff3b2aa6264e 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx +++ b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx @@ -13,7 +13,12 @@ import { i18n as i18nFormatter } from '@kbn/i18n'; import { CreateGraphQLClient } from './framework_adapter_types'; import { UptimeApp, UptimeAppProps } from '../../../uptime_app'; import { getIntegratedAppAvailability } from './capabilities_adapter'; -import { INTEGRATED_SOLUTIONS, PLUGIN } from '../../../../common/constants'; +import { + INTEGRATED_SOLUTIONS, + PLUGIN, + DEFAULT_DARK_MODE, + DEFAULT_TIMEPICKER_QUICK_RANGES, +} from '../../../../common/constants'; import { getTelemetryMonitorPageLogger, getTelemetryOverviewPageLogger } from '../telemetry'; import { UMFrameworkAdapter, BootstrapUptimeApp } from '../../lib'; import { createApolloClient } from './apollo_client_adapter'; @@ -43,7 +48,8 @@ export const getKibanaFrameworkAdapter = ( basePath: basePath.get(), canSave, client: createApolloClient(`${basePath.get()}/api/uptime/graphql`, 'true'), - darkMode: core.uiSettings.get('theme:darkMode'), + darkMode: core.uiSettings.get(DEFAULT_DARK_MODE), + commonlyUsedRanges: core.uiSettings.get(DEFAULT_TIMEPICKER_QUICK_RANGES), i18n, isApmAvailable: apm, isInfraAvailable: infrastructure, diff --git a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx index 47743729c1e762..456aff1f9a24d7 100644 --- a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/legacy/plugins/uptime/public/uptime_app.tsx @@ -18,7 +18,7 @@ import { AutocompleteProviderRegister } from 'src/plugins/data/public'; import { UMGraphQLClient, UMUpdateBreadcrumbs, UMUpdateBadge } from './lib/lib'; import { MonitorPage, OverviewPage, NotFoundPage } from './pages'; import { UptimeRefreshContext, UptimeSettingsContext, UMSettingsContextValues } from './contexts'; -import { UptimeDatePicker } from './components/functional/uptime_date_picker'; +import { UptimeDatePicker, CommonlyUsedRange } from './components/functional/uptime_date_picker'; import { useUrlParams } from './hooks'; import { getTitle } from './lib/helper/get_title'; import { store } from './state'; @@ -50,6 +50,7 @@ export interface UptimeAppProps { setBreadcrumbs: UMUpdateBreadcrumbs; setBadge: UMUpdateBadge; renderGlobalHelpControls(): void; + commonlyUsedRanges: CommonlyUsedRange[]; } const Application = (props: UptimeAppProps) => { @@ -59,6 +60,7 @@ const Application = (props: UptimeAppProps) => { canSave, client, darkMode, + commonlyUsedRanges, i18n: i18nCore, isApmAvailable, isInfraAvailable, @@ -175,7 +177,11 @@ const Application = (props: UptimeAppProps) => {
- +
From d4c6e654489b20892dbd63433fe9e9e199ed3d0b Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 18 Dec 2019 09:08:27 +0100 Subject: [PATCH 44/60] [Maps] Migrate SavedGisMap to use createSavedObjectClass (#53121) --- .../services/gis_map_saved_object_loader.js | 13 +- .../public/angular/services/saved_gis_map.js | 174 +++++++++--------- 2 files changed, 94 insertions(+), 93 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js b/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js index 0eba30e0c4e9be..bd496f44aa8acb 100644 --- a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js +++ b/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import './saved_gis_map'; +import { createSavedGisMapClass } from './saved_gis_map'; import { uiModules } from 'ui/modules'; import { SavedObjectLoader } from 'ui/saved_objects'; import { npStart } from '../../../../../../../src/legacy/ui/public/new_platform'; @@ -12,6 +12,15 @@ import { npStart } from '../../../../../../../src/legacy/ui/public/new_platform' const module = uiModules.get('app/maps'); // This is the only thing that gets injected into controllers -module.service('gisMapSavedObjectLoader', function(SavedGisMap) { +module.service('gisMapSavedObjectLoader', function() { + const savedObjectsClient = npStart.core.savedObjects.client; + const services = { + savedObjectsClient, + indexPatterns: npStart.plugins.data.indexPatterns, + chrome: npStart.core.chrome, + overlays: npStart.core.overlays, + }; + const SavedGisMap = createSavedGisMapClass(services); + return new SavedObjectLoader(SavedGisMap, npStart.core.savedObjects.client, npStart.core.chrome); }); diff --git a/x-pack/legacy/plugins/maps/public/angular/services/saved_gis_map.js b/x-pack/legacy/plugins/maps/public/angular/services/saved_gis_map.js index b846bb5b775439..035ae4886920c2 100644 --- a/x-pack/legacy/plugins/maps/public/angular/services/saved_gis_map.js +++ b/x-pack/legacy/plugins/maps/public/angular/services/saved_gis_map.js @@ -5,9 +5,7 @@ */ import _ from 'lodash'; -import { uiModules } from 'ui/modules'; -import { createLegacyClass } from 'ui/utils/legacy_class'; -import { SavedObjectProvider } from 'ui/saved_objects/saved_object'; +import { createSavedObjectClass } from 'ui/saved_objects/saved_object'; import { getTimeFilters, getMapZoom, @@ -24,95 +22,89 @@ import { copyPersistentState } from '../../reducers/util'; import { extractReferences, injectReferences } from '../../../common/migrations/references'; import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; -const module = uiModules.get('app/maps'); - -module.factory('SavedGisMap', function(Private) { - const SavedObject = Private(SavedObjectProvider); - createLegacyClass(SavedGisMap).inherits(SavedObject); - function SavedGisMap(id) { - SavedGisMap.Super.call(this, { - type: SavedGisMap.type, - mapping: SavedGisMap.mapping, - searchSource: SavedGisMap.searchsource, - extractReferences, - injectReferences: (savedObject, references) => { - const { attributes } = injectReferences({ - attributes: { layerListJSON: savedObject.layerListJSON }, - references, - }); - - savedObject.layerListJSON = attributes.layerListJSON; - - const indexPatternIds = references - .filter(reference => { - return reference.type === 'index-pattern'; - }) - .map(reference => { - return reference.id; - }); - savedObject.indexPatternIds = _.uniq(indexPatternIds); - }, - - // if this is null/undefined then the SavedObject will be assigned the defaults - id: id, - - // default values that will get assigned if the doc is new - defaults: { - title: 'New Map', - description: '', +export function createSavedGisMapClass(services) { + const SavedObjectClass = createSavedObjectClass(services); + + class SavedGisMap extends SavedObjectClass { + static type = MAP_SAVED_OBJECT_TYPE; + + // Mappings are used to place object properties into saved object _source + static mapping = { + title: 'text', + description: 'text', + mapStateJSON: 'text', + layerListJSON: 'text', + uiStateJSON: 'text', + bounds: { + type: 'object', }, - }); + }; + static fieldOrder = ['title', 'description']; + static searchSource = false; + + constructor(id) { + super({ + type: SavedGisMap.type, + mapping: SavedGisMap.mapping, + searchSource: SavedGisMap.searchSource, + extractReferences, + injectReferences: (savedObject, references) => { + const { attributes } = injectReferences({ + attributes: { layerListJSON: savedObject.layerListJSON }, + references, + }); - this.showInRecentlyAccessed = true; + savedObject.layerListJSON = attributes.layerListJSON; + + const indexPatternIds = references + .filter(reference => { + return reference.type === 'index-pattern'; + }) + .map(reference => { + return reference.id; + }); + savedObject.indexPatternIds = _.uniq(indexPatternIds); + }, + + // if this is null/undefined then the SavedObject will be assigned the defaults + id: id, + + // default values that will get assigned if the doc is new + defaults: { + title: 'New Map', + description: '', + }, + }); + this.showInRecentlyAccessed = true; + } + getFullPath() { + return `/app/maps#map/${this.id}`; + } + getLayerList() { + return this.layerListJSON ? JSON.parse(this.layerListJSON) : null; + } + + syncWithStore(state) { + const layerList = getLayerListRaw(state); + const layerListConfigOnly = copyPersistentState(layerList); + this.layerListJSON = JSON.stringify(layerListConfigOnly); + + this.mapStateJSON = JSON.stringify({ + zoom: getMapZoom(state), + center: getMapCenter(state), + timeFilters: getTimeFilters(state), + refreshConfig: getRefreshConfig(state), + query: _.omit(getQuery(state), 'queryLastTriggeredAt'), + filters: getFilters(state), + }); + + this.uiStateJSON = JSON.stringify({ + isLayerTOCOpen: getIsLayerTOCOpen(state), + openTOCDetails: getOpenTOCDetails(state), + }); + + this.bounds = convertMapExtentToPolygon(getMapExtent(state)); + } } - - SavedGisMap.type = MAP_SAVED_OBJECT_TYPE; - - // Mappings are used to place object properties into saved object _source - SavedGisMap.mapping = { - title: 'text', - description: 'text', - mapStateJSON: 'text', - layerListJSON: 'text', - uiStateJSON: 'text', - bounds: { - type: 'object', - }, - }; - - SavedGisMap.fieldOrder = ['title', 'description']; - - SavedGisMap.searchsource = false; - - SavedGisMap.prototype.getFullPath = function() { - return `/app/maps#map/${this.id}`; - }; - - SavedGisMap.prototype.getLayerList = function() { - return this.layerListJSON ? JSON.parse(this.layerListJSON) : null; - }; - - SavedGisMap.prototype.syncWithStore = function(state) { - const layerList = getLayerListRaw(state); - const layerListConfigOnly = copyPersistentState(layerList); - this.layerListJSON = JSON.stringify(layerListConfigOnly); - - this.mapStateJSON = JSON.stringify({ - zoom: getMapZoom(state), - center: getMapCenter(state), - timeFilters: getTimeFilters(state), - refreshConfig: getRefreshConfig(state), - query: _.omit(getQuery(state), 'queryLastTriggeredAt'), - filters: getFilters(state), - }); - - this.uiStateJSON = JSON.stringify({ - isLayerTOCOpen: getIsLayerTOCOpen(state), - openTOCDetails: getOpenTOCDetails(state), - }); - - this.bounds = convertMapExtentToPolygon(getMapExtent(state)); - }; - return SavedGisMap; -}); +} From 862265a48e666c3b578c3181002b5148693f9133 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Wed, 18 Dec 2019 10:20:30 +0100 Subject: [PATCH 45/60] Feature/monitor list externel linking (#53098) * update monitor list columns * update columns * update snaps * fix type * removed unused ii8n --- .../monitor_bar_series.test.tsx.snap | 1 + .../functional/charts/monitor_bar_series.tsx | 19 +- .../__snapshots__/monitor_list.test.tsx.snap | 44 +--- .../monitor_list_pagination.test.tsx.snap | 44 +--- .../functional/monitor_list/monitor_list.tsx | 196 ++++++------------ .../monitor_list_actions_popover.tsx | 12 +- .../monitor_list_drawer.test.tsx.snap | 128 +++++++++--- .../monitor_status_list.test.tsx.snap | 38 +--- .../monitor_status_row.test.tsx.snap | 4 +- .../most_recent_error.test.tsx.snap | 6 + .../monitor_list_drawer.tsx | 18 +- .../monitor_status_list.tsx | 8 +- .../monitor_status_row.tsx | 2 +- .../monitor_list_drawer/most_recent_error.tsx | 4 +- .../functional/monitor_list/translations.ts | 54 +++++ .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 17 files changed, 291 insertions(+), 291 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/translations.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap index 376f20ffcf18a6..1f197294ebc151 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap @@ -5,6 +5,7 @@ exports[`MonitorBarSeries component renders a series when there are down items 1 style={ Object { "height": 50, + "maxWidth": "1200px", "width": "100%", } } diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx index 1011ddd8e4101f..52b41416bd17bf 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/charts/monitor_bar_series.tsx @@ -17,6 +17,8 @@ import { } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiText, EuiToolTip } from '@elastic/eui'; import { SummaryHistogramPoint } from '../../../../common/graphql/types'; import { getColorsMap } from './get_colors_map'; import { getChartDateLabel, seriesHasDownValues } from '../../../lib/helper'; @@ -54,7 +56,7 @@ export const MonitorBarSeries = ({ const id = getSpecId('downSeries'); return seriesHasDownValues(histogramSeries) ? ( -
+
- ) : null; + ) : ( + down }} + /> + } + > + -- + + ); }; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap index 0c6acb8d9f46e1..dc98878f6fe085 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap @@ -26,6 +26,7 @@ exports[`MonitorList component renders a no items message when no data is provid "field": "state.monitor.status", "name": "Status", "render": [Function], + "width": "20%", }, Object { "align": "left", @@ -33,15 +34,10 @@ exports[`MonitorList component renders a no items message when no data is provid "name": "Name", "render": [Function], "sortable": true, + "width": "30%", }, Object { - "align": "left", - "field": "state.url.full", - "name": "URL", - "render": [Function], - "sortable": true, - }, - Object { + "align": "center", "field": "histogram.points", "mobileOptions": Object { "show": false, @@ -51,23 +47,11 @@ exports[`MonitorList component renders a no items message when no data is provid }, Object { "align": "right", - "field": "state", - "hasActions": true, - "id": "actions", - "mobileOptions": Object { - "header": false, - }, - "name": "Integrations", - "render": [Function], - }, - Object { - "align": "left", "field": "monitor_id", "isExpander": true, "name": "", "render": [Function], "sortable": true, - "width": "24px", }, ] } @@ -133,6 +117,7 @@ exports[`MonitorList component renders the monitor list 1`] = ` "field": "state.monitor.status", "name": "Status", "render": [Function], + "width": "20%", }, Object { "align": "left", @@ -140,15 +125,10 @@ exports[`MonitorList component renders the monitor list 1`] = ` "name": "Name", "render": [Function], "sortable": true, + "width": "30%", }, Object { - "align": "left", - "field": "state.url.full", - "name": "URL", - "render": [Function], - "sortable": true, - }, - Object { + "align": "center", "field": "histogram.points", "mobileOptions": Object { "show": false, @@ -158,23 +138,11 @@ exports[`MonitorList component renders the monitor list 1`] = ` }, Object { "align": "right", - "field": "state", - "hasActions": true, - "id": "actions", - "mobileOptions": Object { - "header": false, - }, - "name": "Integrations", - "render": [Function], - }, - Object { - "align": "left", "field": "monitor_id", "isExpander": true, "name": "", "render": [Function], "sortable": true, - "width": "24px", }, ] } diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list_pagination.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list_pagination.test.tsx.snap index b7c8ddbc51b276..c251e3d8de0ead 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list_pagination.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_list_pagination.test.tsx.snap @@ -26,6 +26,7 @@ exports[`MonitorList component renders a no items message when no data is provid "field": "state.monitor.status", "name": "Status", "render": [Function], + "width": "20%", }, Object { "align": "left", @@ -33,15 +34,10 @@ exports[`MonitorList component renders a no items message when no data is provid "name": "Name", "render": [Function], "sortable": true, + "width": "30%", }, Object { - "align": "left", - "field": "state.url.full", - "name": "URL", - "render": [Function], - "sortable": true, - }, - Object { + "align": "center", "field": "histogram.points", "mobileOptions": Object { "show": false, @@ -51,23 +47,11 @@ exports[`MonitorList component renders a no items message when no data is provid }, Object { "align": "right", - "field": "state", - "hasActions": true, - "id": "actions", - "mobileOptions": Object { - "header": false, - }, - "name": "Integrations", - "render": [Function], - }, - Object { - "align": "left", "field": "monitor_id", "isExpander": true, "name": "", "render": [Function], "sortable": true, - "width": "24px", }, ] } @@ -133,6 +117,7 @@ exports[`MonitorList component renders the monitor list 1`] = ` "field": "state.monitor.status", "name": "Status", "render": [Function], + "width": "20%", }, Object { "align": "left", @@ -140,15 +125,10 @@ exports[`MonitorList component renders the monitor list 1`] = ` "name": "Name", "render": [Function], "sortable": true, + "width": "30%", }, Object { - "align": "left", - "field": "state.url.full", - "name": "URL", - "render": [Function], - "sortable": true, - }, - Object { + "align": "center", "field": "histogram.points", "mobileOptions": Object { "show": false, @@ -158,23 +138,11 @@ exports[`MonitorList component renders the monitor list 1`] = ` }, Object { "align": "right", - "field": "state", - "hasActions": true, - "id": "actions", - "mobileOptions": Object { - "header": false, - }, - "name": "Integrations", - "render": [Function], - }, - Object { - "align": "left", "field": "monitor_id", "isExpander": true, "name": "", "render": [Function], "sortable": true, - "width": "24px", }, ] } diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list.tsx index 40a51f7c978e69..f059418324f712 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list.tsx @@ -10,13 +10,10 @@ import { EuiPanel, EuiTitle, EuiButtonIcon, - EuiIcon, - EuiLink, EuiFlexItem, EuiSpacer, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import React, { useState, Fragment } from 'react'; import { withUptimeGraphQL, UptimeGraphQLQueryProps } from '../../higher_order'; @@ -32,8 +29,8 @@ import { ExpandedRowMap } from './types'; import { MonitorListDrawer } from './monitor_list_drawer'; import { MonitorBarSeries } from '../charts'; import { MonitorPageLink } from './monitor_page_link'; -import { MonitorListActionsPopover } from './monitor_list_actions_popover'; import { OverviewPageLink } from './overview_page_link'; +import * as labels from './translations'; interface MonitorListQueryResult { monitorStates?: MonitorSummaryResult; @@ -80,6 +77,68 @@ export const MonitorListComponent = (props: Props) => { }, {}); }; + const columns = [ + { + align: 'left', + width: '20%', + field: 'state.monitor.status', + name: labels.STATUS_COLUMN_LABEL, + render: (status: string, { state: { timestamp } }: MonitorSummary) => { + return ; + }, + }, + { + align: 'left', + width: '30%', + field: 'state.monitor.name', + name: labels.NAME_COLUMN_LABEL, + render: (name: string, summary: MonitorSummary) => ( + + {name ? name : `Unnamed - ${summary.monitor_id}`} + + ), + sortable: true, + }, + { + align: 'center', + field: 'histogram.points', + name: labels.HISTORY_COLUMN_LABEL, + mobileOptions: { + show: false, + }, + render: (histogramSeries: SummaryHistogramPoint[] | null) => ( + + ), + }, + { + align: 'right', + field: 'monitor_id', + name: '', + sortable: true, + isExpander: true, + render: (id: string) => { + return ( + { + if (drawerIds.includes(id)) { + updateDrawerIds(drawerIds.filter(p => p !== id)); + } else { + updateDrawerIds([...drawerIds, id]); + } + }} + /> + ); + }, + }, + ]; + return ( @@ -93,11 +152,7 @@ export const MonitorListComponent = (props: Props) => { { // TODO: not needed without sorting and pagination // onChange={onChange} noItemsMessage={ - hasActiveFilters - ? i18n.translate('xpack.uptime.monitorList.noItemForSelectedFiltersMessage', { - defaultMessage: 'No monitors found for selected filter criteria', - description: - 'This message is show if there are no monitors in the table and some filter or search criteria exists', - }) - : i18n.translate('xpack.uptime.monitorList.noItemMessage', { - defaultMessage: 'No uptime monitors found', - description: - 'This message is shown if the monitors table is rendered but has no items.', - }) + hasActiveFilters ? labels.NO_MONITOR_ITEM_SELECTED : labels.NO_DATA_MESSAGE } // TODO: reintegrate pagination in future release // pagination={pagination} // TODO: reintegrate sorting in future release // sorting={sorting} - columns={[ - { - align: 'left', - field: 'state.monitor.status', - name: i18n.translate('xpack.uptime.monitorList.statusColumnLabel', { - defaultMessage: 'Status', - }), - render: (status: string, { state: { timestamp } }: MonitorSummary) => { - return ; - }, - }, - { - align: 'left', - field: 'state.monitor.name', - name: i18n.translate('xpack.uptime.monitorList.nameColumnLabel', { - defaultMessage: 'Name', - }), - render: (name: string, summary: MonitorSummary) => ( - - {name ? name : `Unnamed - ${summary.monitor_id}`} - - ), - sortable: true, - }, - { - align: 'left', - field: 'state.url.full', - name: i18n.translate('xpack.uptime.monitorList.urlColumnLabel', { - defaultMessage: 'URL', - }), - render: (url: string, summary: MonitorSummary) => ( - - - {url} - - - ), - sortable: true, - }, - { - field: 'histogram.points', - name: i18n.translate('xpack.uptime.monitorList.monitorHistoryColumnLabel', { - defaultMessage: 'Downtime history', - }), - mobileOptions: { - show: false, - }, - render: (histogramSeries: SummaryHistogramPoint[] | null) => ( - - ), - }, - { - id: 'actions', - align: 'right', - field: 'state', - hasActions: true, - mobileOptions: { - header: false, - }, - name: i18n.translate( - 'xpack.uptime.monitorList.observabilityIntegrationsColumnLabel', - { - defaultMessage: 'Integrations', - description: - 'The heading column of some action buttons that will take users to other Observability apps', - } - ), - render: (state: any, summary: MonitorSummary) => ( - - ), - }, - { - align: 'left', - field: 'monitor_id', - name: '', - sortable: true, - width: '24px', - isExpander: true, - render: (id: string) => { - return ( - { - if (drawerIds.includes(id)) { - updateDrawerIds(drawerIds.filter(p => p !== id)); - } else { - updateDrawerIds([...drawerIds, id]); - } - }} - /> - ); - }, - }, - ]} + columns={columns} /> diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_actions_popover.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_actions_popover.tsx index 04f195d42531bc..af06761f50c835 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_actions_popover.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_actions_popover.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiButtonIcon, EuiPopover } from '@elastic/eui'; +import { EuiPopover, EuiButton } from '@elastic/eui'; import React, { useContext } from 'react'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; @@ -43,7 +43,7 @@ const MonitorListActionsPopoverComponent = ({ return ( togglePopoverIsVisible({ id: popoverId, open: true })} - /> + iconType="arrowDown" + iconSide="right" + > + Integrations + } closePopover={() => togglePopoverIsVisible({ id: popoverId, open: false })} id={popoverId} diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap index 80e064e25e1a5e..b6402ae852215f 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap @@ -6,21 +6,68 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there are - - https://expired.badssl.com - - + + + https://expired.badssl.com + + + + + + - - https://expired.badssl.com - - + + + https://expired.badssl.com + + + + + + - - - , - } - } - /> - - `; @@ -39,7 +22,7 @@ exports[`MonitorStatusList component renders null in place of child status with - - - , - } - } - /> - - `; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap index e2caf6f718728e..8e4aa984c1e897 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap @@ -16,7 +16,7 @@ exports[`MonitorStatusRow component renders status row when status is down 1`] = /> `; @@ -37,7 +37,7 @@ exports[`MonitorStatusRow component renders status row when status is up 1`] = ` /> `; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap index 5c1fe27d234a3f..389afa27fd21fe 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap @@ -2,6 +2,9 @@ exports[`MostRecentError component renders properly with mock data 1`] = ` Array [ +
,
@@ -9,6 +12,9 @@ Array [ Most recent error (5 days ago)
, +
, +
+
+
+ `); + + cleanup(); + + expect(target).toMatchInlineSnapshot(`
`); + }); + + it('should register the nav control once the license supports it', () => { + const license$ = new BehaviorSubject({} as ILicense); + + const navControlService = new SecurityNavControlService(); + navControlService.setup({ + securityLicense: new SecurityLicenseService().setup({ license$ }).license, + }); + + const coreStart = coreMock.createStart(); + navControlService.start({ core: coreStart }); + + expect(coreStart.chrome.navControls.registerRight).not.toHaveBeenCalled(); + + license$.next(validLicense); + + expect(coreStart.chrome.navControls.registerRight).toHaveBeenCalled(); + }); + + it('should not register the nav control for anonymous paths', () => { + const license$ = new BehaviorSubject(validLicense); + + const navControlService = new SecurityNavControlService(); + navControlService.setup({ + securityLicense: new SecurityLicenseService().setup({ license$ }).license, + }); + + const coreStart = coreMock.createStart(); + coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); + navControlService.start({ core: coreStart }); + + expect(coreStart.chrome.navControls.registerRight).not.toHaveBeenCalled(); + }); + + it('should only register the nav control once', () => { + const license$ = new BehaviorSubject(validLicense); + + const navControlService = new SecurityNavControlService(); + navControlService.setup({ + securityLicense: new SecurityLicenseService().setup({ license$ }).license, + }); + + const coreStart = coreMock.createStart(); + navControlService.start({ core: coreStart }); + + expect(coreStart.chrome.navControls.registerRight).toHaveBeenCalledTimes(1); + + // trigger license change + license$.next({} as ILicense); + license$.next(validLicense); + + expect(coreStart.chrome.navControls.registerRight).toHaveBeenCalledTimes(1); + }); + + it('should allow for re-registration if the service is restarted', () => { + const license$ = new BehaviorSubject(validLicense); + + const navControlService = new SecurityNavControlService(); + navControlService.setup({ + securityLicense: new SecurityLicenseService().setup({ license$ }).license, + }); + + const coreStart = coreMock.createStart(); + navControlService.start({ core: coreStart }); + + expect(coreStart.chrome.navControls.registerRight).toHaveBeenCalledTimes(1); + + navControlService.stop(); + + navControlService.start({ core: coreStart }); + expect(coreStart.chrome.navControls.registerRight).toHaveBeenCalledTimes(2); + }); +}); diff --git a/x-pack/plugins/security/public/nav_control/nav_control_service.tsx b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx new file mode 100644 index 00000000000000..aeeb84219c937d --- /dev/null +++ b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx @@ -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 { Subscription } from 'rxjs'; +import { CoreStart } from 'src/core/public'; +import ReactDOM from 'react-dom'; +import React from 'react'; +import { SecurityLicense } from '../../common/licensing'; +import { AuthenticatedUser } from '../../common/model'; +import { SecurityNavControl } from './nav_control_component'; + +interface SetupDeps { + securityLicense: SecurityLicense; +} + +interface StartDeps { + core: CoreStart; +} + +export class SecurityNavControlService { + private securityLicense!: SecurityLicense; + + private navControlRegistered!: boolean; + + private securityFeaturesSubscription?: Subscription; + + public setup({ securityLicense }: SetupDeps) { + this.securityLicense = securityLicense; + } + + public start({ core }: StartDeps) { + this.securityFeaturesSubscription = this.securityLicense.features$.subscribe( + ({ showLinks }) => { + const isAnonymousPath = core.http.anonymousPaths.isAnonymous(window.location.pathname); + + const shouldRegisterNavControl = + !isAnonymousPath && showLinks && !this.navControlRegistered; + + if (shouldRegisterNavControl) { + const user = core.http.get('/internal/security/me', { + headers: { + 'kbn-system-api': true, + }, + }) as Promise; + this.registerSecurityNavControl(core, user); + } + } + ); + } + + public stop() { + if (this.securityFeaturesSubscription) { + this.securityFeaturesSubscription.unsubscribe(); + this.securityFeaturesSubscription = undefined; + } + this.navControlRegistered = false; + } + + private registerSecurityNavControl( + core: Pick, + user: Promise + ) { + core.chrome.navControls.registerRight({ + order: 2000, + mount: (el: HTMLElement) => { + const I18nContext = core.i18n.Context; + + const props = { + user, + editProfileUrl: core.http.basePath.prepend('/app/kibana#/account'), + logoutUrl: core.http.basePath.prepend(`/logout`), + }; + ReactDOM.render( + + + , + el + ); + + return () => ReactDOM.unmountComponentAtNode(el); + }, + }); + + this.navControlRegistered = true; + } +} diff --git a/x-pack/plugins/security/public/plugin.ts b/x-pack/plugins/security/public/plugin.ts index 7b1a554e1d3f12..0f10f9d89f25a2 100644 --- a/x-pack/plugins/security/public/plugin.ts +++ b/x-pack/plugins/security/public/plugin.ts @@ -4,18 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Plugin, CoreSetup } from 'src/core/public'; +import { Plugin, CoreSetup, CoreStart } from 'src/core/public'; +import { LicensingPluginSetup } from '../../licensing/public'; import { SessionExpired, SessionTimeout, SessionTimeoutHttpInterceptor, UnauthorizedResponseHttpInterceptor, } from './session'; +import { SecurityLicenseService } from '../common/licensing'; +import { SecurityNavControlService } from './nav_control'; + +export interface PluginSetupDependencies { + licensing: LicensingPluginSetup; +} export class SecurityPlugin implements Plugin { private sessionTimeout!: SessionTimeout; - public setup(core: CoreSetup) { + private navControlService!: SecurityNavControlService; + + private securityLicenseService!: SecurityLicenseService; + + public setup(core: CoreSetup, { licensing }: PluginSetupDependencies) { const { http, notifications, injectedMetadata } = core; const { basePath, anonymousPaths } = http; anonymousPaths.register('/login'); @@ -28,18 +39,29 @@ export class SecurityPlugin implements Plugin { let apiKeys: APIKeys; diff --git a/x-pack/plugins/security/server/authentication/api_keys.ts b/x-pack/plugins/security/server/authentication/api_keys.ts index b207e227c56af0..2b1a93d9074710 100644 --- a/x-pack/plugins/security/server/authentication/api_keys.ts +++ b/x-pack/plugins/security/server/authentication/api_keys.ts @@ -5,7 +5,7 @@ */ import { IClusterClient, KibanaRequest, Logger } from '../../../../../src/core/server'; -import { SecurityLicense } from '../licensing'; +import { SecurityLicense } from '../../common/licensing'; /** * Represents the options to create an APIKey class instance that will be diff --git a/x-pack/plugins/security/server/authentication/index.test.ts b/x-pack/plugins/security/server/authentication/index.test.ts index 6a0057e97dcf06..0c1095b56e6e24 100644 --- a/x-pack/plugins/security/server/authentication/index.test.ts +++ b/x-pack/plugins/security/server/authentication/index.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { licenseMock } from '../licensing/index.mock'; +import { licenseMock } from '../../common/licensing/index.mock'; jest.mock('./api_keys'); jest.mock('./authenticator'); @@ -43,7 +43,7 @@ import { InvalidateAPIKeyResult, InvalidateAPIKeyParams, } from './api_keys'; -import { SecurityLicense } from '../licensing'; +import { SecurityLicense } from '../../common/licensing'; describe('setupAuthentication()', () => { let mockSetupAuthenticationParams: { diff --git a/x-pack/plugins/security/server/authentication/index.ts b/x-pack/plugins/security/server/authentication/index.ts index de2fb54ab8c2a1..1002ad7709b804 100644 --- a/x-pack/plugins/security/server/authentication/index.ts +++ b/x-pack/plugins/security/server/authentication/index.ts @@ -16,7 +16,7 @@ import { getErrorStatusCode } from '../errors'; import { Authenticator, ProviderSession } from './authenticator'; import { LegacyAPI } from '../plugin'; import { APIKeys, CreateAPIKeyParams, InvalidateAPIKeyParams } from './api_keys'; -import { SecurityLicense } from '../licensing'; +import { SecurityLicense } from '../../common/licensing'; export { canRedirectRequest } from './can_redirect_request'; export { Authenticator, ProviderLoginAttempt } from './authenticator'; diff --git a/x-pack/plugins/security/server/authorization/index.test.ts b/x-pack/plugins/security/server/authorization/index.test.ts index 34b9efea771659..9e99cae6206334 100644 --- a/x-pack/plugins/security/server/authorization/index.test.ts +++ b/x-pack/plugins/security/server/authorization/index.test.ts @@ -24,7 +24,7 @@ import { elasticsearchServiceMock, loggingServiceMock, } from '../../../../../src/core/server/mocks'; -import { licenseMock } from '../licensing/index.mock'; +import { licenseMock } from '../../common/licensing/index.mock'; test(`returns exposed services`, () => { const kibanaIndexName = '.a-kibana-index'; diff --git a/x-pack/plugins/security/server/authorization/index.ts b/x-pack/plugins/security/server/authorization/index.ts index 41e6d12eb8f365..00a50dd5b8821b 100644 --- a/x-pack/plugins/security/server/authorization/index.ts +++ b/x-pack/plugins/security/server/authorization/index.ts @@ -31,7 +31,7 @@ import { disableUICapabilitiesFactory } from './disable_ui_capabilities'; import { validateFeaturePrivileges } from './validate_feature_privileges'; import { registerPrivilegesWithCluster } from './register_privileges_with_cluster'; import { APPLICATION_PREFIX } from '../../common/constants'; -import { SecurityLicense } from '../licensing'; +import { SecurityLicense } from '../../common/licensing'; export { Actions } from './actions'; export { CheckSavedObjectsPrivileges } from './check_saved_objects_privileges'; diff --git a/x-pack/plugins/security/server/authorization/mode.test.ts b/x-pack/plugins/security/server/authorization/mode.test.ts index 3f6aa1f68ff0dc..7d7d2108c049b7 100644 --- a/x-pack/plugins/security/server/authorization/mode.test.ts +++ b/x-pack/plugins/security/server/authorization/mode.test.ts @@ -7,9 +7,9 @@ import { authorizationModeFactory } from './mode'; import { httpServerMock } from '../../../../../src/core/server/mocks'; -import { licenseMock } from '../licensing/index.mock'; -import { SecurityLicenseFeatures } from '../licensing/license_features'; -import { SecurityLicense } from '../licensing'; +import { licenseMock } from '../../common/licensing/index.mock'; +import { SecurityLicenseFeatures } from '../../common/licensing/license_features'; +import { SecurityLicense } from '../../common/licensing'; describe(`#useRbacForRequest`, () => { let mockLicense: jest.Mocked; diff --git a/x-pack/plugins/security/server/authorization/mode.ts b/x-pack/plugins/security/server/authorization/mode.ts index 43ac8f43436fd5..6a56c6cfc260ad 100644 --- a/x-pack/plugins/security/server/authorization/mode.ts +++ b/x-pack/plugins/security/server/authorization/mode.ts @@ -5,7 +5,7 @@ */ import { KibanaRequest } from '../../../../../src/core/server'; -import { SecurityLicense } from '../licensing'; +import { SecurityLicense } from '../../common/licensing'; export interface AuthorizationMode { useRbacForRequest(request: KibanaRequest): boolean; diff --git a/x-pack/plugins/security/server/licensing/license_service.ts b/x-pack/plugins/security/server/licensing/license_service.ts deleted file mode 100644 index e9e2791efbd171..00000000000000 --- a/x-pack/plugins/security/server/licensing/license_service.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 { deepFreeze } from '../../../../../src/core/utils'; -import { ILicense } from '../../../licensing/server'; -import { SecurityLicenseFeatures } from './license_features'; - -export interface SecurityLicense { - isEnabled(): boolean; - getFeatures(): SecurityLicenseFeatures; -} - -export class SecurityLicenseService { - public setup() { - let rawLicense: Readonly | undefined; - - return { - update(newRawLicense: Readonly) { - rawLicense = newRawLicense; - }, - - license: deepFreeze({ - isEnabled() { - if (!rawLicense) { - return false; - } - - const securityFeature = rawLicense.getFeature('security'); - return ( - securityFeature !== undefined && - securityFeature.isAvailable && - securityFeature.isEnabled - ); - }, - - /** - * Returns up-do-date Security related features based on the last known license. - */ - getFeatures(): SecurityLicenseFeatures { - // If, for some reason, we cannot get license information from Elasticsearch, - // assume worst-case and lock user at login screen. - if (rawLicense === undefined || !rawLicense.isAvailable) { - return { - showLogin: true, - allowLogin: false, - showLinks: false, - allowRoleDocumentLevelSecurity: false, - allowRoleFieldLevelSecurity: false, - allowRbac: false, - layout: - rawLicense !== undefined && !rawLicense.isAvailable - ? 'error-xpack-unavailable' - : 'error-es-unavailable', - }; - } - - if (!this.isEnabled()) { - return { - showLogin: false, - allowLogin: false, - showLinks: false, - allowRoleDocumentLevelSecurity: false, - allowRoleFieldLevelSecurity: false, - allowRbac: false, - linksMessage: 'Access is denied because Security is disabled in Elasticsearch.', - }; - } - - const isLicensePlatinumOrBetter = rawLicense.isOneOf(['platinum', 'enterprise', 'trial']); - return { - showLogin: true, - allowLogin: true, - showLinks: true, - // Only platinum and trial licenses are compliant with field- and document-level security. - allowRoleDocumentLevelSecurity: isLicensePlatinumOrBetter, - allowRoleFieldLevelSecurity: isLicensePlatinumOrBetter, - allowRbac: true, - }; - }, - }), - }; - } -} diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts index cce928976accc7..05d67b112bad89 100644 --- a/x-pack/plugins/security/server/plugin.test.ts +++ b/x-pack/plugins/security/server/plugin.test.ts @@ -54,6 +54,17 @@ describe('Security Plugin', () => { "secureCookies": true, }, "license": Object { + "features$": Observable { + "_isScalar": false, + "operator": MapOperator { + "project": [Function], + "thisArg": undefined, + }, + "source": Observable { + "_isScalar": false, + "_subscribe": [Function], + }, + }, "getFeatures": [Function], "isEnabled": [Function], }, diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index df5be97e7c393b..14dd1e6ac00d34 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Subscription, combineLatest } from 'rxjs'; +import { combineLatest } from 'rxjs'; import { first } from 'rxjs/operators'; import { IClusterClient, @@ -25,7 +25,7 @@ import { Authentication, setupAuthentication } from './authentication'; import { Authorization, setupAuthorization } from './authorization'; import { createConfig$ } from './config'; import { defineRoutes } from './routes'; -import { SecurityLicenseService, SecurityLicense } from './licensing'; +import { SecurityLicenseService, SecurityLicense } from '../common/licensing'; import { setupSavedObjects } from './saved_objects'; import { SecurityAuditLogger } from './audit'; import { elasticsearchClientPlugin } from './elasticsearch_client_plugin'; @@ -90,7 +90,7 @@ export class Plugin { private readonly logger: Logger; private clusterClient?: IClusterClient; private spacesService?: SpacesService | symbol = Symbol('not accessed'); - private licenseSubscription?: Subscription; + private securityLicenseService?: SecurityLicenseService; private legacyAPI?: LegacyAPI; private readonly getLegacyAPI = () => { @@ -128,10 +128,10 @@ export class Plugin { plugins: [elasticsearchClientPlugin], }); - const { license, update: updateLicense } = new SecurityLicenseService().setup(); - this.licenseSubscription = licensing.license$.subscribe(rawLicense => - updateLicense(rawLicense) - ); + this.securityLicenseService = new SecurityLicenseService(); + const { license } = this.securityLicenseService.setup({ + license$: licensing.license$, + }); const authc = await setupAuthentication({ http: core.http, @@ -223,9 +223,9 @@ export class Plugin { this.clusterClient = undefined; } - if (this.licenseSubscription) { - this.licenseSubscription.unsubscribe(); - this.licenseSubscription = undefined; + if (this.securityLicenseService) { + this.securityLicenseService.stop(); + this.securityLicenseService = undefined; } } From 55ba993fb3d5ac0ea995754b1defa49c505c65a8 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 18 Dec 2019 13:19:00 +0100 Subject: [PATCH 51/60] [APM] Add `service.version` filter to transaction views (#52748) * [APM] Add `service.version` filter to transaction views Closes #51427. * Add service.version filter to error/metric views --- .../__snapshots__/elasticsearch_fieldnames.test.ts.snap | 6 ++++++ .../plugins/apm/common/elasticsearch_fieldnames.ts | 1 + .../public/components/app/ErrorGroupOverview/index.tsx | 2 +- .../apm/public/components/app/ServiceMetrics/index.tsx | 2 +- .../public/components/app/TransactionDetails/index.tsx | 2 +- .../public/components/app/TransactionOverview/index.tsx | 8 +++++++- .../components/shared/Links/apm/ErrorOverviewLink.tsx | 3 ++- .../components/shared/Links/apm/MetricOverviewLink.tsx | 3 ++- .../shared/Links/apm/ServiceNodeMetricOverviewLink.tsx | 3 ++- .../shared/Links/apm/ServiceNodeOverviewLink.tsx | 3 ++- .../shared/Links/apm/TransactionDetailLink.tsx | 6 +++++- .../shared/Links/apm/TransactionOverviewLink.tsx | 3 ++- .../apm/server/lib/ui_filters/local_ui_filters/config.ts | 9 ++++++++- 13 files changed, 40 insertions(+), 11 deletions(-) diff --git a/x-pack/legacy/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/legacy/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index 9d82cd6b5455c4..e345ca3552e5ae 100644 --- a/x-pack/legacy/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/legacy/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -68,6 +68,8 @@ exports[`Error SERVICE_NAME 1`] = `"service name"`; exports[`Error SERVICE_NODE_NAME 1`] = `undefined`; +exports[`Error SERVICE_VERSION 1`] = `undefined`; + exports[`Error SPAN_ACTION 1`] = `undefined`; exports[`Error SPAN_DURATION 1`] = `undefined`; @@ -174,6 +176,8 @@ exports[`Span SERVICE_NAME 1`] = `"service name"`; exports[`Span SERVICE_NODE_NAME 1`] = `undefined`; +exports[`Span SERVICE_VERSION 1`] = `undefined`; + exports[`Span SPAN_ACTION 1`] = `"my action"`; exports[`Span SPAN_DURATION 1`] = `1337`; @@ -280,6 +284,8 @@ exports[`Transaction SERVICE_NAME 1`] = `"service name"`; exports[`Transaction SERVICE_NODE_NAME 1`] = `undefined`; +exports[`Transaction SERVICE_VERSION 1`] = `undefined`; + exports[`Transaction SPAN_ACTION 1`] = `undefined`; exports[`Transaction SPAN_DURATION 1`] = `undefined`; diff --git a/x-pack/legacy/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/legacy/plugins/apm/common/elasticsearch_fieldnames.ts index b8b35e79a9908b..0d7ff3114e73fb 100644 --- a/x-pack/legacy/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/legacy/plugins/apm/common/elasticsearch_fieldnames.ts @@ -8,6 +8,7 @@ export const SERVICE_NAME = 'service.name'; export const SERVICE_ENVIRONMENT = 'service.environment'; export const SERVICE_AGENT_NAME = 'agent.name'; export const SERVICE_NODE_NAME = 'service.node.name'; +export const SERVICE_VERSION = 'service.version'; export const URL_FULL = 'url.full'; export const HTTP_REQUEST_METHOD = 'http.request.method'; export const USER_ID = 'user.id'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx index f2d2f28fc975af..2e1efabf47b2c8 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx @@ -80,7 +80,7 @@ const ErrorGroupOverview: React.FC = () => { const localUIFiltersConfig = useMemo(() => { const config: React.ComponentProps = { - filterNames: ['host', 'containerId', 'podName'], + filterNames: ['host', 'containerId', 'podName', 'serviceVersion'], params: { serviceName }, diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx index 8005fc17f2a20c..d01093be801a24 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx @@ -31,7 +31,7 @@ export function ServiceMetrics({ agentName }: ServiceMetricsProps) { const localFiltersConfig: React.ComponentProps = useMemo( () => ({ - filterNames: ['host', 'containerId', 'podName'], + filterNames: ['host', 'containerId', 'podName', 'serviceVersion'], params: { serviceName, serviceNodeName diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/index.tsx index dbd0e9d3b9d221..9d6639b0007626 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/index.tsx @@ -50,7 +50,7 @@ export function TransactionDetails() { const localUIFiltersConfig = useMemo(() => { const config: React.ComponentProps = { - filterNames: ['transactionResult'], + filterNames: ['transactionResult', 'serviceVersion'], projection: PROJECTION.TRANSACTIONS, params: { transactionName, diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx index de356b5812e9a4..439e3d80eef4f1 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx @@ -96,7 +96,13 @@ export function TransactionOverview() { const localFiltersConfig: React.ComponentProps = useMemo( () => ({ - filterNames: ['transactionResult', 'host', 'containerId', 'podName'], + filterNames: [ + 'transactionResult', + 'host', + 'containerId', + 'podName', + 'serviceVersion' + ], params: { serviceName, transactionType diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx index c99c7f12062e21..fcc0dc7d266957 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx @@ -21,7 +21,8 @@ const ErrorOverviewLink = ({ serviceName, query, ...rest }: Props) => { urlParams, 'host', 'containerId', - 'podName' + 'podName', + 'serviceVersion' ); return ( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx index dd988f3e3720d4..7d21e1efa44f23 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx @@ -19,7 +19,8 @@ const MetricOverviewLink = ({ serviceName, ...rest }: Props) => { urlParams, 'host', 'containerId', - 'podName' + 'podName', + 'serviceVersion' ); return ( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx index 925d85fa0663ed..527c3da9e7e1ce 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx @@ -24,7 +24,8 @@ const ServiceNodeMetricOverviewLink = ({ urlParams, 'host', 'containerId', - 'podName' + 'podName', + 'serviceVersion' ); return ( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx index 10e55d3382448e..db1b6ec117bf43 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx @@ -19,7 +19,8 @@ const ServiceNodeOverviewLink = ({ serviceName, ...rest }: Props) => { urlParams, 'host', 'containerId', - 'podName' + 'podName', + 'serviceVersion' ); return ( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx index a4ac05379615a7..784f9b36ff621d 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx @@ -27,7 +27,11 @@ export const TransactionDetailLink = ({ }: Props) => { const { urlParams } = useUrlParams(); - const persistedFilters = pickKeys(urlParams, 'transactionResult'); + const persistedFilters = pickKeys( + urlParams, + 'transactionResult', + 'serviceVersion' + ); return ( { 'transactionResult', 'host', 'containerId', - 'podName' + 'podName', + 'serviceVersion' ); return ( diff --git a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index a0149bec728c5c..6363b996ce5bbf 100644 --- a/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts +++ b/x-pack/legacy/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts @@ -9,7 +9,8 @@ import { POD_NAME, SERVICE_AGENT_NAME, HOST_NAME, - TRANSACTION_RESULT + TRANSACTION_RESULT, + SERVICE_VERSION } from '../../../../common/elasticsearch_fieldnames'; const filtersByName = { @@ -42,6 +43,12 @@ const filtersByName = { defaultMessage: 'Transaction result' }), fieldName: TRANSACTION_RESULT + }, + serviceVersion: { + title: i18n.translate('xpack.apm.localFilters.titles.serviceVersion', { + defaultMessage: 'Service version' + }), + fieldName: SERVICE_VERSION } }; From 0c0fc608727d86cd740356d86786ff9861526ac3 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 18 Dec 2019 08:12:29 -0500 Subject: [PATCH 52/60] Docs: Add --direct_html (#53294) Adds the new `--direct_html` argument while building the docs to line up with the change in the global docs build made by elastic/docs#1645. This cuts the time to build the docs in half. --- src/docs/docs_repo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/docs_repo.js b/src/docs/docs_repo.js index 63fcd2a6de5ecb..51ae0d495b9ff1 100644 --- a/src/docs/docs_repo.js +++ b/src/docs/docs_repo.js @@ -27,7 +27,7 @@ export function buildDocsScript(cmd) { export function buildDocsArgs(cmd) { const docsIndexFile = resolve(kibanaDir, 'docs', 'index.asciidoc'); - let args = ['--doc', docsIndexFile, '--chunk=1']; + let args = ['--doc', docsIndexFile, '--direct_html', '--chunk=1']; if (cmd.open) { args = [...args, '--open']; } From a806bac32dd46f3d9fcf4be4ac6e62932968fd50 Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Wed, 18 Dec 2019 14:32:20 +0100 Subject: [PATCH 53/60] Fix ClusterManager call parameters (#53263) * Fix ClusterManager call parameters * remove static ClusterManager.create * migrate ClusterManager to ts * remove default import for ClusterManager and Worker --- .../{__mocks__/cluster.js => cluster.mock.ts} | 17 +++-- src/cli/cluster/cluster_manager.test.mocks.ts | 22 ++++++ ...anager.test.js => cluster_manager.test.ts} | 38 +++++----- ...{cluster_manager.js => cluster_manager.ts} | 65 ++++++++++------- .../{worker.test.js => worker.test.ts} | 51 +++++++------ src/cli/cluster/{worker.js => worker.ts} | 72 +++++++++++++------ src/core/server/legacy/legacy_service.test.ts | 28 +++++--- src/core/server/legacy/legacy_service.ts | 6 +- 8 files changed, 185 insertions(+), 114 deletions(-) rename src/cli/cluster/{__mocks__/cluster.js => cluster.mock.ts} (85%) create mode 100644 src/cli/cluster/cluster_manager.test.mocks.ts rename src/cli/cluster/{cluster_manager.test.js => cluster_manager.test.ts} (84%) rename src/cli/cluster/{cluster_manager.js => cluster_manager.ts} (83%) rename src/cli/cluster/{worker.test.js => worker.test.ts} (80%) rename src/cli/cluster/{worker.js => worker.ts} (75%) diff --git a/src/cli/cluster/__mocks__/cluster.js b/src/cli/cluster/cluster.mock.ts similarity index 85% rename from src/cli/cluster/__mocks__/cluster.js rename to src/cli/cluster/cluster.mock.ts index d653771136ae6a..332f8aad53ba14 100644 --- a/src/cli/cluster/__mocks__/cluster.js +++ b/src/cli/cluster/cluster.mock.ts @@ -18,12 +18,15 @@ */ /* eslint-env jest */ +// eslint-disable-next-line max-classes-per-file import EventEmitter from 'events'; import { assign, random } from 'lodash'; import { delay } from 'bluebird'; class MockClusterFork extends EventEmitter { - constructor(cluster) { + public exitCode = 0; + + constructor(cluster: MockCluster) { super(); let dead = true; @@ -49,9 +52,9 @@ class MockClusterFork extends EventEmitter { send: jest.fn(), }); - jest.spyOn(this, 'on'); - jest.spyOn(this, 'off'); - jest.spyOn(this, 'emit'); + jest.spyOn(this as EventEmitter, 'on'); + jest.spyOn(this as EventEmitter, 'off'); + jest.spyOn(this as EventEmitter, 'emit'); (async () => { await wait(); @@ -61,11 +64,7 @@ class MockClusterFork extends EventEmitter { } } -class MockCluster extends EventEmitter { +export class MockCluster extends EventEmitter { fork = jest.fn(() => new MockClusterFork(this)); setupMaster = jest.fn(); } - -export function mockCluster() { - return new MockCluster(); -} diff --git a/src/cli/cluster/cluster_manager.test.mocks.ts b/src/cli/cluster/cluster_manager.test.mocks.ts new file mode 100644 index 00000000000000..53984fd12cbf17 --- /dev/null +++ b/src/cli/cluster/cluster_manager.test.mocks.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { MockCluster } from './cluster.mock'; +export const mockCluster = new MockCluster(); +jest.mock('cluster', () => mockCluster); diff --git a/src/cli/cluster/cluster_manager.test.js b/src/cli/cluster/cluster_manager.test.ts similarity index 84% rename from src/cli/cluster/cluster_manager.test.js rename to src/cli/cluster/cluster_manager.test.ts index be8a096db9a66a..bd37e854e1691c 100644 --- a/src/cli/cluster/cluster_manager.test.js +++ b/src/cli/cluster/cluster_manager.test.ts @@ -17,8 +17,7 @@ * under the License. */ -import { mockCluster } from './__mocks__/cluster'; -jest.mock('cluster', () => mockCluster()); +import { mockCluster } from './cluster_manager.test.mocks'; jest.mock('readline', () => ({ createInterface: jest.fn(() => ({ on: jest.fn(), @@ -27,15 +26,14 @@ jest.mock('readline', () => ({ })), })); -import cluster from 'cluster'; import { sample } from 'lodash'; -import ClusterManager from './cluster_manager'; -import Worker from './worker'; +import { ClusterManager } from './cluster_manager'; +import { Worker } from './worker'; describe('CLI cluster manager', () => { beforeEach(() => { - cluster.fork.mockImplementation(() => { + mockCluster.fork.mockImplementation(() => { return { process: { kill: jest.fn(), @@ -44,16 +42,16 @@ describe('CLI cluster manager', () => { off: jest.fn(), on: jest.fn(), send: jest.fn(), - }; + } as any; }); }); afterEach(() => { - cluster.fork.mockReset(); + mockCluster.fork.mockReset(); }); test('has two workers', () => { - const manager = ClusterManager.create({}); + const manager = new ClusterManager({}, {} as any); expect(manager.workers).toHaveLength(2); for (const worker of manager.workers) expect(worker).toBeInstanceOf(Worker); @@ -63,7 +61,7 @@ describe('CLI cluster manager', () => { }); test('delivers broadcast messages to other workers', () => { - const manager = ClusterManager.create({}); + const manager = new ClusterManager({}, {} as any); for (const worker of manager.workers) { Worker.prototype.start.call(worker); // bypass the debounced start method @@ -76,10 +74,10 @@ describe('CLI cluster manager', () => { messenger.emit('broadcast', football); for (const worker of manager.workers) { if (worker === messenger) { - expect(worker.fork.send).not.toHaveBeenCalled(); + expect(worker.fork!.send).not.toHaveBeenCalled(); } else { - expect(worker.fork.send).toHaveBeenCalledTimes(1); - expect(worker.fork.send).toHaveBeenCalledWith(football); + expect(worker.fork!.send).toHaveBeenCalledTimes(1); + expect(worker.fork!.send).toHaveBeenCalledWith(football); } } }); @@ -88,7 +86,7 @@ describe('CLI cluster manager', () => { test('correctly configures `BasePathProxy`.', async () => { const basePathProxyMock = { start: jest.fn() }; - ClusterManager.create({}, {}, basePathProxyMock); + new ClusterManager({}, {} as any, basePathProxyMock as any); expect(basePathProxyMock.start).toHaveBeenCalledWith({ shouldRedirectFromOldBasePath: expect.any(Function), @@ -97,13 +95,13 @@ describe('CLI cluster manager', () => { }); describe('proxy is configured with the correct `shouldRedirectFromOldBasePath` and `blockUntil` functions.', () => { - let clusterManager; - let shouldRedirectFromOldBasePath; - let blockUntil; + let clusterManager: ClusterManager; + let shouldRedirectFromOldBasePath: (path: string) => boolean; + let blockUntil: () => Promise; beforeEach(async () => { const basePathProxyMock = { start: jest.fn() }; - clusterManager = ClusterManager.create({}, {}, basePathProxyMock); + clusterManager = new ClusterManager({}, {} as any, basePathProxyMock as any); jest.spyOn(clusterManager.server, 'on'); jest.spyOn(clusterManager.server, 'off'); @@ -146,7 +144,7 @@ describe('CLI cluster manager', () => { expect(clusterManager.server.on).toHaveBeenCalledTimes(2); expect(clusterManager.server.on).toHaveBeenCalledWith('crashed', expect.any(Function)); - const [, [eventName, onCrashed]] = clusterManager.server.on.mock.calls; + const [, [eventName, onCrashed]] = (clusterManager.server.on as jest.Mock).mock.calls; // Check event name to make sure we call the right callback, // in Jest 23 we could use `toHaveBeenNthCalledWith` instead. expect(eventName).toBe('crashed'); @@ -164,7 +162,7 @@ describe('CLI cluster manager', () => { expect(clusterManager.server.on).toHaveBeenCalledTimes(2); expect(clusterManager.server.on).toHaveBeenCalledWith('listening', expect.any(Function)); - const [[eventName, onListening]] = clusterManager.server.on.mock.calls; + const [[eventName, onListening]] = (clusterManager.server.on as jest.Mock).mock.calls; // Check event name to make sure we call the right callback, // in Jest 23 we could use `toHaveBeenNthCalledWith` instead. expect(eventName).toBe('listening'); diff --git a/src/cli/cluster/cluster_manager.js b/src/cli/cluster/cluster_manager.ts similarity index 83% rename from src/cli/cluster/cluster_manager.js rename to src/cli/cluster/cluster_manager.ts index cd1b3a0dadfc69..d97f7485fb4d22 100644 --- a/src/cli/cluster/cluster_manager.js +++ b/src/cli/cluster/cluster_manager.ts @@ -20,26 +20,38 @@ import { resolve } from 'path'; import { format as formatUrl } from 'url'; import opn from 'opn'; - import { debounce, invoke, bindAll, once, uniq } from 'lodash'; import * as Rx from 'rxjs'; import { first, mapTo, filter, map, take } from 'rxjs/operators'; import { REPO_ROOT } from '@kbn/dev-utils'; +import { FSWatcher } from 'chokidar'; + +import { LegacyConfig } from '../../core/server/legacy/config'; +import { BasePathProxyServer } from '../../core/server/http'; +// @ts-ignore import Log from '../log'; -import Worker from './worker'; -import { Config } from '../../legacy/server/config/config'; +import { Worker } from './worker'; process.env.kbnWorkerType = 'managr'; -export default class ClusterManager { - static create(opts, settings = {}, basePathProxy) { - return new ClusterManager(opts, Config.withDefaultSchema(settings), basePathProxy); - } - - constructor(opts, config, basePathProxy) { +export class ClusterManager { + public optimizer: Worker; + public server: Worker; + public workers: Worker[]; + + private watcher: FSWatcher | null = null; + private basePathProxy: BasePathProxyServer | undefined; + private log: any; + private addedCount = 0; + private inReplMode: boolean; + + constructor( + opts: Record, + config: LegacyConfig, + basePathProxy?: BasePathProxyServer + ) { this.log = new Log(opts.quiet, opts.silent); - this.addedCount = 0; this.inReplMode = !!opts.repl; this.basePathProxy = basePathProxy; @@ -79,7 +91,7 @@ export default class ClusterManager { worker.on('broadcast', msg => { this.workers.forEach(to => { if (to !== worker && to.online) { - to.fork.send(msg); + to.fork!.send(msg); } }); }); @@ -90,10 +102,10 @@ export default class ClusterManager { // and all workers. This is only used by LogRotator service // when the cluster mode is enabled this.server.on('reloadLoggingConfigFromServerWorker', () => { - process.emit('message', { reloadLoggingConfig: true }); + process.emit('message' as any, { reloadLoggingConfig: true } as any); this.workers.forEach(worker => { - worker.fork.send({ reloadLoggingConfig: true }); + worker.fork!.send({ reloadLoggingConfig: true }); }); }); @@ -111,9 +123,9 @@ export default class ClusterManager { } if (opts.watch) { - const pluginPaths = config.get('plugins.paths'); + const pluginPaths = config.get('plugins.paths'); const scanDirs = [ - ...config.get('plugins.scanDirs'), + ...config.get('plugins.scanDirs'), resolve(REPO_ROOT, 'src/plugins'), resolve(REPO_ROOT, 'x-pack/plugins'), ]; @@ -131,7 +143,7 @@ export default class ClusterManager { resolve(path, 'scripts'), resolve(path, 'docs') ), - [] + [] as string[] ); this.setupWatching(extraPaths, pluginInternalDirsIgnore); @@ -149,7 +161,7 @@ export default class ClusterManager { } } - setupOpen(openUrl) { + setupOpen(openUrl: string) { const serverListening$ = Rx.merge( Rx.fromEvent(this.server, 'listening').pipe(mapTo(true)), Rx.fromEvent(this.server, 'fork:exit').pipe(mapTo(false)), @@ -157,7 +169,7 @@ export default class ClusterManager { ); const optimizeSuccess$ = Rx.fromEvent(this.optimizer, 'optimizeStatus').pipe( - map(msg => !!msg.success) + map((msg: any) => !!msg.success) ); Rx.combineLatest(serverListening$, optimizeSuccess$) @@ -169,8 +181,10 @@ export default class ClusterManager { .then(() => opn(openUrl)); } - setupWatching(extraPaths, pluginInternalDirsIgnore) { + setupWatching(extraPaths: string[], pluginInternalDirsIgnore: string[]) { + // eslint-disable-next-line @typescript-eslint/no-var-requires const chokidar = require('chokidar'); + // eslint-disable-next-line @typescript-eslint/no-var-requires const { fromRoot } = require('../../core/server/utils'); const watchPaths = [ @@ -204,7 +218,7 @@ export default class ClusterManager { ...ignorePaths, 'plugins/java_languageserver', ], - }); + }) as FSWatcher; this.watcher.on('add', this.onWatcherAdd); this.watcher.on('error', this.onWatcherError); @@ -213,8 +227,8 @@ export default class ClusterManager { 'ready', once(() => { // start sending changes to workers - this.watcher.removeListener('add', this.onWatcherAdd); - this.watcher.on('all', this.onWatcherChange); + this.watcher!.removeListener('add', this.onWatcherAdd); + this.watcher!.on('all', this.onWatcherChange); this.log.good('watching for changes', `(${this.addedCount} files)`); this.startCluster(); @@ -229,6 +243,7 @@ export default class ClusterManager { if (this.inReplMode) { return; } + // eslint-disable-next-line @typescript-eslint/no-var-requires const readline = require('readline'); const rl = readline.createInterface(process.stdin, process.stdout); @@ -263,16 +278,16 @@ export default class ClusterManager { this.addedCount += 1; } - onWatcherChange(e, path) { + onWatcherChange(e: any, path: string) { invoke(this.workers, 'onChange', path); } - onWatcherError(err) { + onWatcherError(err: any) { this.log.bad('failed to watch files!\n', err.stack); process.exit(1); // eslint-disable-line no-process-exit } - shouldRedirectFromOldBasePath(path) { + shouldRedirectFromOldBasePath(path: string) { // strip `s/{id}` prefix when checking for need to redirect if (path.startsWith('s/')) { path = path diff --git a/src/cli/cluster/worker.test.js b/src/cli/cluster/worker.test.ts similarity index 80% rename from src/cli/cluster/worker.test.js rename to src/cli/cluster/worker.test.ts index b43cc123abcbb6..4f9337681e0835 100644 --- a/src/cli/cluster/worker.test.js +++ b/src/cli/cluster/worker.test.ts @@ -17,22 +17,20 @@ * under the License. */ -import { mockCluster } from './__mocks__/cluster'; -jest.mock('cluster', () => mockCluster()); +import { mockCluster } from './cluster_manager.test.mocks'; -import cluster from 'cluster'; - -import Worker from './worker'; +import { Worker, ClusterWorker } from './worker'; +// @ts-ignore import Log from '../log'; -const workersToShutdown = []; +const workersToShutdown: Worker[] = []; -function assertListenerAdded(emitter, event) { +function assertListenerAdded(emitter: NodeJS.EventEmitter, event: any) { expect(emitter.on).toHaveBeenCalledWith(event, expect.any(Function)); } -function assertListenerRemoved(emitter, event) { - const [, onEventListener] = emitter.on.mock.calls.find(([eventName]) => { +function assertListenerRemoved(emitter: NodeJS.EventEmitter, event: any) { + const [, onEventListener] = (emitter.on as jest.Mock).mock.calls.find(([eventName]) => { return eventName === event; }); @@ -44,6 +42,7 @@ function setup(opts = {}) { log: new Log(false, true), ...opts, baseArgv: [], + type: 'test', }); workersToShutdown.push(worker); @@ -53,7 +52,7 @@ function setup(opts = {}) { describe('CLI cluster manager', () => { afterEach(async () => { while (workersToShutdown.length > 0) { - const worker = workersToShutdown.pop(); + const worker = workersToShutdown.pop() as Worker; // If `fork` exists we should set `exitCode` to the non-zero value to // prevent worker from auto restart. if (worker.fork) { @@ -63,14 +62,14 @@ describe('CLI cluster manager', () => { await worker.shutdown(); } - cluster.fork.mockClear(); + mockCluster.fork.mockClear(); }); describe('#onChange', () => { describe('opts.watch = true', () => { test('restarts the fork', () => { const worker = setup({ watch: true }); - jest.spyOn(worker, 'start').mockImplementation(() => {}); + jest.spyOn(worker, 'start').mockResolvedValue(); worker.onChange('/some/path'); expect(worker.changes).toEqual(['/some/path']); expect(worker.start).toHaveBeenCalledTimes(1); @@ -80,7 +79,7 @@ describe('CLI cluster manager', () => { describe('opts.watch = false', () => { test('does not restart the fork', () => { const worker = setup({ watch: false }); - jest.spyOn(worker, 'start').mockImplementation(() => {}); + jest.spyOn(worker, 'start').mockResolvedValue(); worker.onChange('/some/path'); expect(worker.changes).toEqual([]); expect(worker.start).not.toHaveBeenCalled(); @@ -94,13 +93,13 @@ describe('CLI cluster manager', () => { const worker = setup(); await worker.start(); expect(worker).toHaveProperty('online', true); - const fork = worker.fork; - expect(fork.process.kill).not.toHaveBeenCalled(); + const fork = worker.fork as ClusterWorker; + expect(fork!.process.kill).not.toHaveBeenCalled(); assertListenerAdded(fork, 'message'); assertListenerAdded(fork, 'online'); assertListenerAdded(fork, 'disconnect'); await worker.shutdown(); - expect(fork.process.kill).toHaveBeenCalledTimes(1); + expect(fork!.process.kill).toHaveBeenCalledTimes(1); assertListenerRemoved(fork, 'message'); assertListenerRemoved(fork, 'online'); assertListenerRemoved(fork, 'disconnect'); @@ -120,7 +119,7 @@ describe('CLI cluster manager', () => { test(`is bound to fork's message event`, async () => { const worker = setup(); await worker.start(); - expect(worker.fork.on).toHaveBeenCalledWith('message', expect.any(Function)); + expect(worker.fork!.on).toHaveBeenCalledWith('message', expect.any(Function)); }); }); @@ -138,8 +137,8 @@ describe('CLI cluster manager', () => { test('calls #onMessage with message parts', () => { const worker = setup(); jest.spyOn(worker, 'onMessage').mockImplementation(() => {}); - worker.parseIncomingMessage([10, 100, 1000, 10000]); - expect(worker.onMessage).toHaveBeenCalledWith(10, 100, 1000, 10000); + worker.parseIncomingMessage(['event', 'some-data']); + expect(worker.onMessage).toHaveBeenCalledWith('event', 'some-data'); }); }); }); @@ -149,7 +148,7 @@ describe('CLI cluster manager', () => { test('emits the data to be broadcasted', () => { const worker = setup(); const data = {}; - jest.spyOn(worker, 'emit').mockImplementation(() => {}); + jest.spyOn(worker, 'emit').mockImplementation(() => true); worker.onMessage('WORKER_BROADCAST', data); expect(worker.emit).toHaveBeenCalledWith('broadcast', data); }); @@ -158,7 +157,7 @@ describe('CLI cluster manager', () => { describe('when sent WORKER_LISTENING message', () => { test('sets the listening flag and emits the listening event', () => { const worker = setup(); - jest.spyOn(worker, 'emit').mockImplementation(() => {}); + jest.spyOn(worker, 'emit').mockImplementation(() => true); expect(worker).toHaveProperty('listening', false); worker.onMessage('WORKER_LISTENING'); expect(worker).toHaveProperty('listening', true); @@ -170,8 +169,6 @@ describe('CLI cluster manager', () => { test('does nothing', () => { const worker = setup(); worker.onMessage('asdlfkajsdfahsdfiohuasdofihsdoif'); - worker.onMessage({}); - worker.onMessage(23049283094); }); }); }); @@ -185,7 +182,7 @@ describe('CLI cluster manager', () => { await worker.start(); - expect(cluster.fork).toHaveBeenCalledTimes(1); + expect(mockCluster.fork).toHaveBeenCalledTimes(1); expect(worker.on).toHaveBeenCalledWith('fork:online', expect.any(Function)); }); @@ -193,12 +190,12 @@ describe('CLI cluster manager', () => { const worker = setup(); jest.spyOn(process, 'on'); - jest.spyOn(cluster, 'on'); + jest.spyOn(mockCluster, 'on'); await worker.start(); - expect(cluster.on).toHaveBeenCalledTimes(1); - expect(cluster.on).toHaveBeenCalledWith('exit', expect.any(Function)); + expect(mockCluster.on).toHaveBeenCalledTimes(1); + expect(mockCluster.on).toHaveBeenCalledWith('exit', expect.any(Function)); expect(process.on).toHaveBeenCalledTimes(1); expect(process.on).toHaveBeenCalledWith('exit', expect.any(Function)); }); diff --git a/src/cli/cluster/worker.js b/src/cli/cluster/worker.ts similarity index 75% rename from src/cli/cluster/worker.js rename to src/cli/cluster/worker.ts index 2250075f20a609..fb87f1a87654c3 100644 --- a/src/cli/cluster/worker.js +++ b/src/cli/cluster/worker.ts @@ -21,25 +21,57 @@ import _ from 'lodash'; import cluster from 'cluster'; import { EventEmitter } from 'events'; -import { BinderFor } from '../../legacy/utils'; +import { BinderFor } from '../../legacy/utils/binder_for'; import { fromRoot } from '../../core/server/utils'; const cliPath = fromRoot('src/cli'); const baseArgs = _.difference(process.argv.slice(2), ['--no-watch']); const baseArgv = [process.execPath, cliPath].concat(baseArgs); +export type ClusterWorker = cluster.Worker & { + killed: boolean; + exitCode?: number; +}; + cluster.setupMaster({ exec: cliPath, silent: false, }); -const dead = fork => { +const dead = (fork: ClusterWorker) => { return fork.isDead() || fork.killed; }; -export default class Worker extends EventEmitter { - constructor(opts) { - opts = opts || {}; +interface WorkerOptions { + type: string; + log: any; // src/cli/log.js + argv?: string[]; + title?: string; + watch?: boolean; + baseArgv?: string[]; +} + +export class Worker extends EventEmitter { + private readonly clusterBinder: BinderFor; + private readonly processBinder: BinderFor; + + private type: string; + private title: string; + private log: any; + private forkBinder: BinderFor | null = null; + private startCount: number; + private watch: boolean; + private env: Record; + + public fork: ClusterWorker | null = null; + public changes: string[]; + + // status flags + public online = false; // the fork can accept messages + public listening = false; // the fork is listening for connections + public crashed = false; // the fork crashed + + constructor(opts: WorkerOptions) { super(); this.log = opts.log; @@ -48,15 +80,9 @@ export default class Worker extends EventEmitter { this.watch = opts.watch !== false; this.startCount = 0; - // status flags - this.online = false; // the fork can accept messages - this.listening = false; // the fork is listening for connections - this.crashed = false; // the fork crashed - this.changes = []; - this.forkBinder = null; // defined when the fork is - this.clusterBinder = new BinderFor(cluster); + this.clusterBinder = new BinderFor(cluster as any); // lack the 'off' method this.processBinder = new BinderFor(process); this.env = { @@ -66,7 +92,7 @@ export default class Worker extends EventEmitter { }; } - onExit(fork, code) { + onExit(fork: ClusterWorker, code: number) { if (this.fork !== fork) return; // we have our fork's exit, so stop listening for others @@ -91,7 +117,7 @@ export default class Worker extends EventEmitter { } } - onChange(path) { + onChange(path: string) { if (!this.watch) return; this.changes.push(path); this.start(); @@ -104,7 +130,7 @@ export default class Worker extends EventEmitter { this.fork.killed = true; // stop listening to the fork, it's just going to die - this.forkBinder.destroy(); + this.forkBinder!.destroy(); // we don't need to react to process.exit anymore this.processBinder.destroy(); @@ -114,12 +140,14 @@ export default class Worker extends EventEmitter { } } - parseIncomingMessage(msg) { - if (!Array.isArray(msg)) return; - this.onMessage(...msg); + parseIncomingMessage(msg: any) { + if (!Array.isArray(msg)) { + return; + } + this.onMessage(msg[0], msg[1]); } - onMessage(type, data) { + onMessage(type: string, data?: any) { switch (type) { case 'WORKER_BROADCAST': this.emit('broadcast', data); @@ -170,16 +198,16 @@ export default class Worker extends EventEmitter { this.log.warn(`restarting ${this.title}...`); } - this.fork = cluster.fork(this.env); + this.fork = cluster.fork(this.env) as ClusterWorker; this.forkBinder = new BinderFor(this.fork); // when the fork sends a message, comes online, or loses its connection, then react - this.forkBinder.on('message', msg => this.parseIncomingMessage(msg)); + this.forkBinder.on('message', (msg: any) => this.parseIncomingMessage(msg)); this.forkBinder.on('online', () => this.onOnline()); this.forkBinder.on('disconnect', () => this.onDisconnect()); // when the cluster says a fork has exited, check if it is ours - this.clusterBinder.on('exit', (fork, code) => this.onExit(fork, code)); + this.clusterBinder.on('exit', (fork: ClusterWorker, code: number) => this.onExit(fork, code)); // when the process exits, make sure we kill our workers this.processBinder.on('exit', () => this.shutdown()); diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index 17ec1e97564323..7025e96d9ecb4c 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -27,7 +27,7 @@ import { findLegacyPluginSpecsMock } from './legacy_service.test.mocks'; import { BehaviorSubject, throwError } from 'rxjs'; import { LegacyService, LegacyServiceSetupDeps, LegacyServiceStartDeps } from '.'; // @ts-ignore: implicit any for JS file -import MockClusterManager from '../../../cli/cluster/cluster_manager'; +import { ClusterManager as MockClusterManager } from '../../../cli/cluster/cluster_manager'; import KbnServer from '../../../legacy/server/kbn_server'; import { Config, Env, ObjectToConfigAdapter } from '../config'; import { getEnvOptions } from '../config/__mocks__/env'; @@ -354,9 +354,15 @@ describe('once LegacyService is set up in `devClusterMaster` mode', () => { await devClusterLegacyService.setup(setupDeps); await devClusterLegacyService.start(startDeps); - const [[cliArgs, , basePathProxy]] = MockClusterManager.create.mock.calls; - expect(cliArgs.basePath).toBe(false); - expect(basePathProxy).not.toBeDefined(); + expect(MockClusterManager).toHaveBeenCalledTimes(1); + expect(MockClusterManager).toHaveBeenCalledWith( + expect.objectContaining({ silent: true, basePath: false }), + expect.objectContaining({ + get: expect.any(Function), + set: expect.any(Function), + }), + undefined + ); }); test('creates ClusterManager with base path proxy.', async () => { @@ -376,11 +382,15 @@ describe('once LegacyService is set up in `devClusterMaster` mode', () => { await devClusterLegacyService.setup(setupDeps); await devClusterLegacyService.start(startDeps); - expect(MockClusterManager.create).toBeCalledTimes(1); - - const [[cliArgs, , basePathProxy]] = MockClusterManager.create.mock.calls; - expect(cliArgs.basePath).toEqual(true); - expect(basePathProxy).toBeInstanceOf(BasePathProxyServer); + expect(MockClusterManager).toHaveBeenCalledTimes(1); + expect(MockClusterManager).toHaveBeenCalledWith( + expect.objectContaining({ quiet: true, basePath: true }), + expect.objectContaining({ + get: expect.any(Function), + set: expect.any(Function), + }), + expect.any(BasePathProxyServer) + ); }); }); diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index 1bba38433d7f45..412f4570887a4f 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -244,7 +244,7 @@ export class LegacyService implements CoreService { private async createClusterManager(config: LegacyConfig) { const basePathProxy$ = this.coreContext.env.cliArgs.basePath - ? combineLatest(this.devConfig$, this.httpConfig$).pipe( + ? combineLatest([this.devConfig$, this.httpConfig$]).pipe( first(), map( ([dev, http]) => @@ -253,7 +253,9 @@ export class LegacyService implements CoreService { ) : EMPTY; - require('../../../cli/cluster/cluster_manager').create( + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { ClusterManager } = require('../../../cli/cluster/cluster_manager'); + return new ClusterManager( this.coreContext.env.cliArgs, config, await basePathProxy$.toPromise() From 42d868db7f7116b3fcd073eb6a426b0573ad9ce5 Mon Sep 17 00:00:00 2001 From: Rudolf Meijering Date: Wed, 18 Dec 2019 14:52:18 +0100 Subject: [PATCH 54/60] [RFC][skip-ci] Prevent plugins from blocking Kibana startup (#45796) * Draft RFC for unblocking plugin lifecycle methods * Draft RFC for unblocking kibana startup * Rename rfc from 0006 to 0007 * Add references to TC39 top-level await * Update with review suggestion Co-Authored-By: Court Ewing * Update RFC#0007 * Apply suggestions from code review Co-Authored-By: Aleh Zasypkin * Address review comments from @joshdover and @azasypkin 1. Fleshed out motivation, this RFC doesn't prevent errors, but isolates the impact on the rest of Kibana. 2. Added a footnote explaining that sync lifecycles can still block on sync for loops, so it's not a perfect guarantee (from @azasypkin). 3. Updated IContextProvider type signature in (2) to match latest master 4. Dynamically reloading configuration changes should be limited to a whitelist, risky changes like the Elasticsearch host should still require a complete restart. Added to (3) based on https://github.com/elastic/kibana/pull/45796#discussion_r331277153 5. Added Section 5, "Core should expose a status signal for Core services & plugins" (from @joshdover) 6. Added the drawback that incorrect, but valid config would not block Kibana, and might only be surfaced when the associted API/UI gets used (from @azasypkin) * Formatting: number ordered list instead of letter for github rendering * Apply suggestions from code review Co-Authored-By: Josh Dover * Update rfcs/text/0007_lifecycle_unblocked.md Co-Authored-By: Josh Dover * Example of plugin exposing API dependent on internal async operation * Clarify that context providers won't block kibana, just their handlers * Update adoption strategy as per latest discussion * Fix formatting --- rfcs/text/0007_lifecycle_unblocked.md | 374 ++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 rfcs/text/0007_lifecycle_unblocked.md diff --git a/rfcs/text/0007_lifecycle_unblocked.md b/rfcs/text/0007_lifecycle_unblocked.md new file mode 100644 index 00000000000000..cb978d3dcd7baa --- /dev/null +++ b/rfcs/text/0007_lifecycle_unblocked.md @@ -0,0 +1,374 @@ +- Start Date: 2019-09-11 +- RFC PR: (leave this empty) +- Kibana Issue: (leave this empty) + +## Table of contents +- [Summary](#summary) +- [Motivation](#motivation) +- [Detailed design](#detailed-design) + - [
  1. Synchronous lifecycle methods
](#ollisynchronous-lifecycle-methodsliol) + - [
  1. Synchronous Context Provider functions
](#ol-start2lisynchronous-context-provider-functionsliol) + - [
  1. Core should not expose API's as observables
](#ol-start3licore-should-not-expose-apis-as-observablesliol) + - [
  1. Complete example code
](#ol-start4licomplete-example-codeliol) + - [
  1. Core should expose a status signal for Core services & plugins
](#ol-start5licore-should-expose-a-status-signal-for-core-services-amp-pluginsliol) +- [Drawbacks](#drawbacks) +- [Alternatives](#alternatives) + - [
  1. Introduce a lifecycle/context provider timeout
](#olliintroduce-a-lifecyclecontext-provider-timeoutliol) + - [
  1. Treat anything that blocks Kibana from starting up as a bug
](#ol-start2litreat-anything-that-blocks-kibana-from-starting-up-as-a-bugliol) +- [Adoption strategy](#adoption-strategy) +- [How we teach this](#how-we-teach-this) +- [Unresolved questions](#unresolved-questions) +- [Footnotes](#footnotes) + +# Summary + +Prevent plugin lifecycle methods from blocking Kibana startup by making the +following changes: +1. Synchronous lifecycle methods +2. Synchronous context provider functions +3. Core should not expose API's as observables + +# Motivation +Plugin lifecycle methods and context provider functions are async +(promise-returning) functions. Core runs these functions in series and waits +for each plugin's lifecycle/context provider function to resolve before +calling the next. This allows plugins to depend on the API's returned from +other plugins. + +With the current design, a single lifecycle method that blocks will block all +of Kibana from starting up. Similarly, a blocking context provider will block +all the handlers that depend on that context. Plugins (including legacy +plugins) rely heavily on this blocking behaviour to ensure that all conditions +required for their plugin's operation are met before their plugin is started +and exposes it's API's. This means a single plugin with a network error that +isn't retried or a dependency on an external host that is down, could block +all of Kibana from starting up. + +We should make it impossible for a single plugin lifecycle function to stall +all of kibana. + +# Detailed design + +### 1. Synchronous lifecycle methods +Lifecycle methods are synchronous functions, they can perform async operations +but Core doesn't wait for these to complete. This guarantees that no plugin +lifecycle function can block other plugins or core from starting up [1]. + +Core will still expose special API's that are able block the setup lifecycle +such as registering Saved Object migrations, but this will be limited to +operations where the risk of blocking all of kibana starting up is limited. + +### 2. Synchronous Context Provider functions +Making context provider functions synchronous guarantees that a context +handler will never be blocked by registered context providers. They can expose +async API's which could potentially have blocking behaviour. + +```ts +export type IContextProvider< + THandler extends HandlerFunction, + TContextName extends keyof HandlerContextType +> = ( + context: Partial>, + ...rest: HandlerParameters +) => + | HandlerContextType[TContextName]; +``` + +### 3. Core should not expose API's as observables +All Core API's should be reactive: when internal state changes, their behaviour +should change accordingly. But, exposing these internal state changes as part +of the API contract leaks internal implementation details consumers can't do +anything useful with and don't care about. + +For example: Core currently exposes `core.elasticsearch.adminClient$`, an +Observable which emits a pre-configured elasticsearch client every time there's +a configuration change. This includes changes to the logging configuration and +might in the future include updating the authentication headers sent to +elasticsearch https://github.com/elastic/kibana/issues/19829. As a plugin +author who wants to make search requests against elasticsearch I shouldn't +have to care about, react to, or keep track of, how many times the underlying +configuration has changed. I want to use the `callAsInternalUser` method and I +expect Core to use the most up to date configuration to send this request. + +> Note: It would not be desirable for Core to dynamically load all +> configuration changes. Changing the Elasticsearch `hosts` could mean Kibana +> is pointing to a completely new Elasticsearch cluster. Since this is a risky +> change to make and would likely require core and almost all plugins to +> completely re-initialize, it's safer to require a complete Kibana restart. + +This does not mean we should remove all observables from Core's API's. When an +API consumer is interested in the *state changes itself* it absolutely makes +sense to expose this as an Observable. Good examples of this is exposing +plugin config as this is state that changes over time to which a plugin should +directly react to. + +This is important in the context of synchronous lifecycle methods and context +handlers since exposing convenient API's become very ugly: + +*(3.1): exposing Observable-based API's through the route handler context:* +```ts +// Before: Using an async context provider +coreSetup.http.registerRouteHandlerContext(coreId, 'core', async (context, req) => { + const adminClient = await coreSetup.elasticsearch.adminClient$.pipe(take(1)).toPromise(); + const dataClient = await coreSetup.elasticsearch.dataClient$.pipe(take(1)).toPromise(); + return { + elasticsearch: { + adminClient: adminClient.asScoped(req), + dataClient: dataClient.asScoped(req), + }, + }; +}); + +// After: Using a synchronous context provider +coreSetup.http.registerRouteHandlerContext(coreId, 'core', async (context, req) => { + return { + elasticsearch: { + // (3.1.1) We can expose a convenient API by doing a lot of work + adminClient: () => { + callAsInternalUser: async (...args) => { + const adminClient = await coreSetup.elasticsearch.adminClient$.pipe(take(1)).toPromise(); + return adminClient.asScoped(req).callAsinternalUser(args); + }, + callAsCurrentUser: async (...args) => { + adminClient = await coreSetup.elasticsearch.adminClient$.pipe(take(1)).toPromise(); + return adminClient.asScoped(req).callAsCurrentUser(args); + } + }, + // (3.1.2) Or a lazy approach which perpetuates the problem to consumers: + dataClient: async () => { + const dataClient = await coreSetup.elasticsearch.dataClient$.pipe(take(1)).toPromise(); + return dataClient.asScoped(req); + }, + }, + }; +}); +``` + +### 4. Complete example code +*(4.1) Doing async operations in a plugin's setup lifecycle* +```ts +export class Plugin { + public setup(core: CoreSetup) { + // Async setup is possible and any operations involving async API's + // will still block until these API's are ready, (savedObjects find only + // resolves once the elasticsearch client has established a connection to + // the cluster). The difference is that these details are now internal to + // the API. + (async () => { + const docs = await core.savedObjects.client.find({...}); + ... + await core.savedObjects.client.update(...); + })(); + } +} +``` + +*(4.2) Exposing an API from a plugin's setup lifecycle* +```ts +export class Plugin { + constructor(private readonly initializerContext: PluginInitializerContext) {} + private async initSavedConfig(core: CoreSetup) { + // Note: pulling a config value here means our code isn't reactive to + // changes, but this is equivalent to doing it in an async setup lifecycle. + const config = await this.initializerContext.config + .create>() + .pipe(first()) + .toPromise(); + try { + const savedConfig = await core.savedObjects.internalRepository.get({...}); + return Object.assign({}, config, savedConfig); + } catch (e) { + if (SavedObjectErrorHelpers.isNotFoundError(e)) { + return await core.savedObjects.internalRepository.create(config, {...}); + } + } + } + public setup(core: CoreSetup) { + // savedConfigPromise resolves with the same kind of "setup state" that a + // plugin would have constructed in an async setup lifecycle. + const savedConfigPromise = initSavedConfig(core); + return { + ping: async () => { + const savedConfig = await savedConfigPromise; + if (config.allowPing === false || savedConfig.allowPing === false) { + throw new Error('ping() has been disabled'); + } + // Note: the elasticsearch client no longer exposes an adminClient$ + // observable, improving the ergonomics of consuming the API. + return await core.elasticsearch.adminClient.callAsInternalUser('ping', ...); + } + }; + } +} +``` + +*(4.3) Exposing an observable free Elasticsearch API from the route context* +```ts +coreSetup.http.registerRouteHandlerContext(coreId, 'core', async (context, req) => { + return { + elasticsearch: { + adminClient: coreSetup.elasticsearch.adminClient.asScoped(req), + dataClient: coreSetup.elasticsearch.adminClient.asScoped(req), + }, + }; +}); +``` + +### 5. Core should expose a status signal for Core services & plugins +Core should expose a global mechanism for core services and plugins to signal +their status. This is equivalent to the legacy status API +`kibana.Plugin.status` which allowed plugins to set their status to e.g. 'red' +or 'green'. The exact design of this API is outside of the scope of this RFC. + +What is important, is that there is a global mechanism to signal status +changes which Core then makes visible to system administrators in the Kibana +logs and the `/status` HTTP API. Plugins should be able to inspect and +subscribe to status changes from any of their dependencies. + +This will provide an obvious mechanism for plugins to signal that the +conditions which are required for this plugin to operate are not currently +present and manual intervention might be required. Status changes can happen +in both setup and start lifecycles e.g.: + - [setup] a required remote host is down + - [start] a remote host which was up during setup, started returning + connection timeout errors. + +# Drawbacks +Not being able to block on a lifecycle method means plugins can no longer be +certain that all setup is "complete" before they expose their API's or reach +the start lifecycle. + +A plugin might want to poll an external host to ensure that the host is up in +its setup lifecycle before making network requests to this host in it's start +lifecycle. + +Even if Kibana was using a valid, but incorrect configuration for the remote +host, with synchronous lifecycles Kibana would still start up. Although the +status API and logs would indicate a problem, these might not be monitored +leading to the error only being discovered once someone tries to use it's +functionality. This is an acceptable drawback because it buys us isolation. +Some problems might go unnoticed, but no single plugin should affect the +availability of all other plugins. + +In effect, the plugin is polling the world to construct a snapshot +of state which drives future behaviour. Modeling this with lifecycle functions +is insufficient since it assumes that any state constructed in the setup +lifecycle is static and won't and can't be changed in the future. + +For example: a plugin's setup lifecycle might poll for the existence of a +custom Elasticsearch index and if it doesn't exist, create it. Should there be +an Elasticsearch restore which deletes the index, the plugin wouldn't be able +to gracefully recover by simply running it's setup lifecycle a second time. + +The once-off nature of lifecycle methods are incompatible with the real-world +dynamic conditions under which plugins run. Not being able to block a +lifecycle method is, therefore, only a drawback when plugins are authored under +the false illusion of stability. + +# Alternatives +## 1. Introduce a lifecycle/context provider timeout +Lifecycle methods and context providers would timeout after X seconds and any +API's they expose would not be available if the timeout had been reached. + +Drawbacks: +1. A blocking setup lifecycle makes it easy for plugin authors to fall into + the trap of assuming that their plugin's behaviour can continue to operate + based on the snapshot of conditions present during setup. + +2. For lifecycle methods: there would be no way to recover from a timeout, + once a timeout had been reached the API will remain unavailable. + + Context providers have the benefit of being re-created for each handler + call, so a single timeout would not permanently disable the API. + +3. Plugins have less control over their behaviour. When an upstream server + becomes unavailable, a plugin might prefer to keep retrying the request + indefinitely or only timeout after more than X seconds. It also isn't able + to expose detailed error information to downstream consumers such as + specifying which host or service is unavailable. + +4. (minor) Introduces an additional failure condition that needs to be handled. + Consumers should handle the API not being available in setup, as well as, + error responses from the API itself. Since remote hosts like Elasticsearch + could go down even after a successful setup, this effectively means API + consumers have to handle the same error condition in two places. + +## 2. Treat anything that blocks Kibana from starting up as a bug +Keep the existing New Platform blocking behaviour, but through strong +conventions and developer awareness minimize the risk of plugins blocking +Kibana's startup indefinetely. By logging detailed diagnostic info on any +plugins that appear to be blocking startup, we can aid system administrators +to recover a blocked Kibana. + +A parallel can be drawn between Kibana's async plugin initialization and the TC39 +proposal for [top-level await](https://github.com/tc39/proposal-top-level-await). +> enables modules to act as big async functions: With top-level await, +> ECMAScript Modules (ESM) can await resources, causing other modules who +> import them to wait before they start evaluating their body + +They believe the benefits outweigh the risk of modules blocking loading since: + - [developer education should result in correct usage](https://github.com/tc39/proposal-top-level-await#will-top-level-await-cause-developers-to-make-their-code-block-longer-than-it-should) + - [there are existing unavoidable ways in which modules could block loading such as infinite loops or recursion](https://github.com/tc39/proposal-top-level-await#does-top-level-await-increase-the-risk-of-deadlocks) + + +Drawbacks: +1. A blocking setup lifecycle makes it easy for plugin authors to fall into + the trap of assuming that their plugin's behaviour can continue to operate + based on the snapshot of conditions present during setup. +2. This opens up the potential for a bug in Elastic or third-party plugins to + effectively "break" kibana. Instead of a single plugin being disabled all + of kibana would be down requiring manual intervention by a system + administrator. + +# Adoption strategy +Although the eventual goal is to have sync-only lifecycles / providers, we +will start by deprecating async behaviour and implementing a 30s timeout as +per alternative (1). This will immediately lower the impact of plugin bugs +while at the same time enabling a more incremental rollout and the flexibility +to discover use cases that would require adopting Core API's to support sync +lifecycles / providers. + +Adoption and implementation should be handled as follows: + - Adopt Core API’s to make sync lifecycles easier (3) + - Update migration guide and other documentation examples. + - Deprecate async lifecycles / context providers with a warning. Add a + timeout of 30s after which a plugin and it's dependencies will be disabled. + - Refactor existing plugin lifecycles which are easily converted to sync + - Future: remove async timeout lifecycles / context providers + +The following New Platform plugins or shims currently rely on async lifecycle +functions and will be impacted: +1. [region_map](https://github.com/elastic/kibana/blob/6039709929caf0090a4130b8235f3a53bd04ed84/src/legacy/core_plugins/region_map/public/plugin.ts#L68) +2. [tile_map](https://github.com/elastic/kibana/blob/6039709929caf0090a4130b8235f3a53bd04ed84/src/legacy/core_plugins/tile_map/public/plugin.ts#L62) +3. [vis_type_table](https://github.com/elastic/kibana/blob/6039709929caf0090a4130b8235f3a53bd04ed84/src/legacy/core_plugins/vis_type_table/public/plugin.ts#L61) +4. [vis_type_vega](https://github.com/elastic/kibana/blob/6039709929caf0090a4130b8235f3a53bd04ed84/src/legacy/core_plugins/vis_type_vega/public/plugin.ts#L59) +5. [timelion](https://github.com/elastic/kibana/blob/9d69b72a5f200e58220231035b19da852fc6b0a5/src/plugins/timelion/server/plugin.ts#L40) +6. [code](https://github.com/elastic/kibana/blob/5049b460b47d4ae3432e1d9219263bb4be441392/x-pack/legacy/plugins/code/server/plugin.ts#L129-L149) +7. [spaces](https://github.com/elastic/kibana/blob/096c7ee51136327f778845c636d7c4f1188e5db2/x-pack/legacy/plugins/spaces/server/new_platform/plugin.ts#L95) +8. [licensing](https://github.com/elastic/kibana/blob/4667c46caef26f8f47714504879197708debae32/x-pack/plugins/licensing/server/plugin.ts) +9. [security](https://github.com/elastic/kibana/blob/0f2324e44566ce2cf083d89082841e57d2db6ef6/x-pack/plugins/security/server/plugin.ts#L96) + +# How we teach this + +Async Plugin lifecycle methods and async context provider functions have been +deprecated. In the future all lifecycle methods will by sync only. Plugins +should treat the setup lifecycle as a place in time to register functionality +with core or other plugins' API's and not as a mechanism to kick off and wait +for any initialization that's required for the plugin to be able to run. + +# Unresolved questions +1. ~~Are the drawbacks worth the benefits or can we live with Kibana potentially +being blocked for the sake of convenient async lifecycle stages?~~ + +2. Should core provide conventions or patterns for plugins to construct a + snapshot of state and reactively updating this state and the behaviour it + drives as the state of the world changes? + +3. Do plugins ever need to read config values and pass these as parameters to + Core API’s? If so we would have to expose synchronous config values to + support sync lifecycles. + +# Footnotes +[1] Synchronous lifecycles can still be blocked by e.g. an infine for loop, +but this would always be unintentional behaviour in contrast to intentional +async behaviour like blocking until an external service becomes available. From 815f72155555c66d9d86e8446f705827ca791e58 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 18 Dec 2019 15:12:02 +0100 Subject: [PATCH 55/60] [APM] Add version annotations to timeseries charts (#52640) * [APM] Add version annotations to timeseries charts Closes #51426. * Don't subdue 'Version' text in tooltip * Optimize version queries * Don't pass radius/color to indicator --- .../legacy/plugins/apm/common/annotations.ts | 16 +++ .../charts/CustomPlot/AnnotationsPlot.tsx | 74 ++++++++++++ .../shared/charts/CustomPlot/Legends.js | 38 +++++- .../shared/charts/CustomPlot/index.js | 30 ++++- .../charts/CustomPlot/plotUtils.test.ts | 6 +- .../{plotUtils.js => plotUtils.tsx} | 46 +++++-- .../__snapshots__/CustomPlot.test.js.snap | 11 ++ .../components/shared/charts/Legend/index.js | 3 +- .../apm/public/context/ChartsSyncContext.tsx | 32 ++++- .../plugins/apm/public/utils/testHelpers.tsx | 61 ++++++---- .../__fixtures__/multiple-versions.json | 34 ++++++ .../annotations/__fixtures__/no-versions.json | 25 ++++ .../annotations/__fixtures__/one-version.json | 30 +++++ .../__fixtures__/versions-first-seen.json | 24 ++++ .../lib/services/annotations/index.test.ts | 98 +++++++++++++++ .../server/lib/services/annotations/index.ts | 114 ++++++++++++++++++ .../apm/server/routes/create_apm_api.ts | 4 +- .../plugins/apm/server/routes/services.ts | 27 +++++ .../legacy/plugins/apm/typings/react-vis.d.ts | 7 ++ .../legacy/plugins/apm/typings/timeseries.ts | 6 +- 20 files changed, 639 insertions(+), 47 deletions(-) create mode 100644 x-pack/legacy/plugins/apm/common/annotations.ts create mode 100644 x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx rename x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/{plotUtils.js => plotUtils.tsx} (74%) create mode 100644 x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/multiple-versions.json create mode 100644 x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/no-versions.json create mode 100644 x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/one-version.json create mode 100644 x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/versions-first-seen.json create mode 100644 x-pack/legacy/plugins/apm/server/lib/services/annotations/index.test.ts create mode 100644 x-pack/legacy/plugins/apm/server/lib/services/annotations/index.ts create mode 100644 x-pack/legacy/plugins/apm/typings/react-vis.d.ts diff --git a/x-pack/legacy/plugins/apm/common/annotations.ts b/x-pack/legacy/plugins/apm/common/annotations.ts new file mode 100644 index 00000000000000..33122f55d88006 --- /dev/null +++ b/x-pack/legacy/plugins/apm/common/annotations.ts @@ -0,0 +1,16 @@ +/* + * 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 enum AnnotationType { + VERSION = 'version' +} + +export interface Annotation { + type: AnnotationType; + id: string; + time: number; + text: string; +} diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx new file mode 100644 index 00000000000000..fb087612f8e3d4 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx @@ -0,0 +1,74 @@ +/* + * 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 React from 'react'; +import { VerticalGridLines } from 'react-vis'; +import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { + EuiIcon, + EuiToolTip, + EuiFlexGroup, + EuiFlexItem, + EuiText +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { Maybe } from '../../../../../typings/common'; +import { Annotation } from '../../../../../common/annotations'; +import { PlotValues, SharedPlot } from './plotUtils'; +import { asAbsoluteDateTime } from '../../../../utils/formatters'; + +interface Props { + annotations: Annotation[]; + plotValues: PlotValues; + width: number; + overlay: Maybe; +} + +const style = { + stroke: theme.euiColorSecondary, + strokeDasharray: 'none' +}; + +export function AnnotationsPlot(props: Props) { + const { plotValues, annotations } = props; + + const tickValues = annotations.map(annotation => annotation.time); + + return ( + <> + + + + {annotations.map(annotation => ( +
+ + + + {i18n.translate('xpack.apm.version', { + defaultMessage: 'Version' + })} + + + {annotation.text} + + } + > + + +
+ ))} + + ); +} diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js index 11755e13bfdd68..848c975942ff64 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js @@ -16,6 +16,8 @@ import { truncate } from '../../../../style/variables'; import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { i18n } from '@kbn/i18n'; +import { EuiIcon } from '@elastic/eui'; const Container = styled.div` display: flex; @@ -73,9 +75,12 @@ export default function Legends({ noHits, series, seriesEnabledState, - truncateLegends + truncateLegends, + hasAnnotations, + showAnnotations, + onAnnotationsToggle }) { - if (noHits) { + if (noHits && !hasAnnotations) { return null; } @@ -107,6 +112,30 @@ export default function Legends({ /> ); })} + {hasAnnotations && ( + { + if (onAnnotationsToggle) { + onAnnotationsToggle(); + } + }} + text={ + + {i18n.translate('xpack.apm.serviceVersion', { + defaultMessage: 'Service version' + })} + + } + indicator={() => ( +
+ +
+ )} + disabled={!showAnnotations} + color={theme.euiColorSecondary} + /> + )} ); @@ -118,5 +147,8 @@ Legends.propTypes = { noHits: PropTypes.bool.isRequired, series: PropTypes.array.isRequired, seriesEnabledState: PropTypes.array.isRequired, - truncateLegends: PropTypes.bool.isRequired + truncateLegends: PropTypes.bool.isRequired, + hasAnnotations: PropTypes.bool, + showAnnotations: PropTypes.bool, + onAnnotationsToggle: PropTypes.func }; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/index.js b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/index.js index e87d60c9b3fe80..f59c30d2f4d2f3 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/index.js +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/index.js @@ -13,6 +13,7 @@ import Legends from './Legends'; import StaticPlot from './StaticPlot'; import InteractivePlot from './InteractivePlot'; import VoronoiPlot from './VoronoiPlot'; +import { AnnotationsPlot } from './AnnotationsPlot'; import { createSelector } from 'reselect'; import { getPlotValues } from './plotUtils'; import { isValidCoordinateValue } from '../../../../utils/isValidCoordinateValue'; @@ -28,7 +29,8 @@ export class InnerCustomPlot extends PureComponent { seriesEnabledState: [], isDrawing: false, selectionStart: null, - selectionEnd: null + selectionEnd: null, + showAnnotations: true }; getEnabledSeries = createSelector( @@ -122,7 +124,7 @@ export class InnerCustomPlot extends PureComponent { } render() { - const { series, truncateLegends, width } = this.props; + const { series, truncateLegends, width, annotations } = this.props; if (!width) { return null; @@ -166,6 +168,14 @@ export class InnerCustomPlot extends PureComponent { tickFormatX={this.props.tickFormatX} /> + {this.state.showAnnotations && !isEmpty(annotations) && ( + + )} + { + this.setState(({ showAnnotations }) => ({ + showAnnotations: !showAnnotations + })); + }} /> ); @@ -209,7 +226,14 @@ InnerCustomPlot.propTypes = { truncateLegends: PropTypes.bool, width: PropTypes.number.isRequired, height: PropTypes.number, - stackBy: PropTypes.string + stackBy: PropTypes.string, + annotations: PropTypes.arrayOf( + PropTypes.shape({ + type: PropTypes.string, + id: PropTypes.string, + firstSeen: PropTypes.number + }) + ) }; InnerCustomPlot.defaultProps = { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts index 55bfb490e85882..b130deed7f098c 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts @@ -6,6 +6,7 @@ // @ts-ignore import * as plotUtils from './plotUtils'; +import { TimeSeries, Coordinate } from '../../../../../typings/timeseries'; describe('plotUtils', () => { describe('getPlotValues', () => { @@ -34,7 +35,10 @@ describe('plotUtils', () => { expect( plotUtils .getPlotValues( - [{ data: { x: 0, y: 200 } }, { data: { x: 0, y: 300 } }], + [ + { data: [{ x: 0, y: 200 }] }, + { data: [{ x: 0, y: 300 }] } + ] as Array>, [], { height: 1, diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.js b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx similarity index 74% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.js rename to x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx index 4186f6c8997506..10eb4659ea6951 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.js +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx @@ -11,6 +11,7 @@ import d3 from 'd3'; import PropTypes from 'prop-types'; import React from 'react'; +import { TimeSeries, Coordinate } from '../../../../../typings/timeseries'; import { unit } from '../../../../style/variables'; import { getTimezoneOffsetInMs } from './getTimezoneOffsetInMs'; @@ -22,20 +23,23 @@ const XY_MARGIN = { bottom: unit * 2 }; -const getXScale = (xMin, xMax, width) => { +const getXScale = (xMin: number, xMax: number, width: number) => { return scaleLinear() .domain([xMin, xMax]) .range([XY_MARGIN.left, width - XY_MARGIN.right]); }; -const getYScale = (yMin, yMax) => { +const getYScale = (yMin: number, yMax: number) => { return scaleLinear() .domain([yMin, yMax]) .range([XY_HEIGHT, 0]) .nice(); }; -function getFlattenedCoordinates(visibleSeries, enabledSeries) { +function getFlattenedCoordinates( + visibleSeries: Array>, + enabledSeries: Array> +) { const enabledCoordinates = flatten(enabledSeries.map(serie => serie.data)); if (!isEmpty(enabledCoordinates)) { return enabledCoordinates; @@ -44,10 +48,24 @@ function getFlattenedCoordinates(visibleSeries, enabledSeries) { return flatten(visibleSeries.map(serie => serie.data)); } +export type PlotValues = ReturnType; + export function getPlotValues( - visibleSeries, - enabledSeries, - { width, yMin = 0, yMax = 'max', height, stackBy } + visibleSeries: Array>, + enabledSeries: Array>, + { + width, + yMin = 0, + yMax = 'max', + height, + stackBy + }: { + width: number; + yMin?: number | 'min'; + yMax?: number | 'max'; + height: number; + stackBy?: 'x' | 'y'; + } ) { const flattenedCoordinates = getFlattenedCoordinates( visibleSeries, @@ -59,10 +77,10 @@ export function getPlotValues( const xMax = d3.max(flattenedCoordinates, d => d.x); if (yMax === 'max') { - yMax = d3.max(flattenedCoordinates, d => d.y); + yMax = d3.max(flattenedCoordinates, d => d.y ?? 0); } if (yMin === 'min') { - yMin = d3.min(flattenedCoordinates, d => d.y); + yMin = d3.min(flattenedCoordinates, d => d.y ?? 0); } const [xMinZone, xMaxZone] = [xMin, xMax].map(x => { @@ -101,11 +119,19 @@ export function getPlotValues( }; } -export function SharedPlot({ plotValues, ...props }) { +export function SharedPlot({ + plotValues, + ...props +}: { + plotValues: PlotValues; + children: React.ReactNode; +}) { const { XY_HEIGHT: height, XY_MARGIN: margin, XY_WIDTH: width } = plotValues; return ( -
+
- + {indicator ? indicator() : } {text} ); diff --git a/x-pack/legacy/plugins/apm/public/context/ChartsSyncContext.tsx b/x-pack/legacy/plugins/apm/public/context/ChartsSyncContext.tsx index c2676a35d8e788..afce0811b48f67 100644 --- a/x-pack/legacy/plugins/apm/public/context/ChartsSyncContext.tsx +++ b/x-pack/legacy/plugins/apm/public/context/ChartsSyncContext.tsx @@ -7,6 +7,8 @@ import React, { useMemo, useState } from 'react'; import { toQuery, fromQuery } from '../components/shared/Links/url_helpers'; import { history } from '../utils/history'; +import { useUrlParams } from '../hooks/useUrlParams'; +import { useFetcher } from '../hooks/useFetcher'; const ChartsSyncContext = React.createContext<{ hoverX: number | null; @@ -17,6 +19,31 @@ const ChartsSyncContext = React.createContext<{ const ChartsSyncContextProvider: React.FC = ({ children }) => { const [time, setTime] = useState(null); + const { urlParams, uiFilters } = useUrlParams(); + + const { start, end, serviceName } = urlParams; + const { environment } = uiFilters; + + const { data = { annotations: [] } } = useFetcher( + callApmApi => { + if (start && end && serviceName) { + return callApmApi({ + pathname: '/api/apm/services/{serviceName}/annotations', + params: { + path: { + serviceName + }, + query: { + start, + end, + environment + } + } + }); + } + }, + [start, end, environment, serviceName] + ); const value = useMemo(() => { const hoverXHandlers = { @@ -43,11 +70,12 @@ const ChartsSyncContextProvider: React.FC = ({ children }) => { }) }); }, - hoverX: time + hoverX: time, + annotations: data.annotations }; return { ...hoverXHandlers }; - }, [time, setTime]); + }, [time, data.annotations]); return ; }; diff --git a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx index 0c8a7cbc17884d..862c982d6b5ac5 100644 --- a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx @@ -19,7 +19,11 @@ import { MemoryRouter } from 'react-router-dom'; import { APMConfig } from '../../../../../plugins/apm/server'; import { LocationProvider } from '../context/LocationContext'; import { PromiseReturnType } from '../../typings/common'; -import { ESFilter } from '../../typings/elasticsearch'; +import { + ESFilter, + ESSearchResponse, + ESSearchRequest +} from '../../typings/elasticsearch'; import { ApmPluginContext, ApmPluginContextValue @@ -117,29 +121,41 @@ interface MockSetup { }; } +interface Options { + mockResponse?: ( + request: ESSearchRequest + ) => ESSearchResponse; +} + export async function inspectSearchParams( - fn: (mockSetup: MockSetup) => Promise + fn: (mockSetup: MockSetup) => Promise, + options: Options = {} ) { - const clientSpy = jest.fn().mockReturnValueOnce({ - hits: { - total: 0 - } + const spy = jest.fn().mockImplementation(async request => { + return options.mockResponse + ? options.mockResponse(request) + : { + hits: { + hits: { + total: { + value: 0 + } + } + } + }; }); - const internalClientSpy = jest.fn().mockReturnValueOnce({ - hits: { - total: 0 - } - }); + let response; + let error; const mockSetup = { start: 1528113600000, end: 1528977600000, client: { - search: clientSpy + search: spy } as any, internalClient: { - search: internalClientSpy + search: spy } as any, config: new Proxy( {}, @@ -164,21 +180,18 @@ export async function inspectSearchParams( dynamicIndexPattern: null as any }; try { - await fn(mockSetup); - } catch { + response = await fn(mockSetup); + } catch (err) { + error = err; // we're only extracting the search params } - let params; - if (clientSpy.mock.calls.length) { - params = clientSpy.mock.calls[0][0]; - } else { - params = internalClientSpy.mock.calls[0][0]; - } - return { - params, - teardown: () => clientSpy.mockClear() + params: spy.mock.calls[0][0], + response, + error, + spy, + teardown: () => spy.mockClear() }; } diff --git a/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/multiple-versions.json b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/multiple-versions.json new file mode 100644 index 00000000000000..7e2d2405d681cd --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/multiple-versions.json @@ -0,0 +1,34 @@ +{ + "took": 444, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 10000, + "relation": "gte" + }, + "max_score": null, + "hits": [] + }, + "aggregations": { + "versions": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "8.0.0", + "doc_count": 615285 + }, + { + "key": "7.5.0", + "doc_count": 615285 + } + ] + } + } +} diff --git a/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/no-versions.json b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/no-versions.json new file mode 100644 index 00000000000000..fa5c63f1b9a543 --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/no-versions.json @@ -0,0 +1,25 @@ +{ + "took": 398, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 10000, + "relation": "gte" + }, + "max_score": null, + "hits": [] + }, + "aggregations": { + "versions": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [] + } + } +} diff --git a/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/one-version.json b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/one-version.json new file mode 100644 index 00000000000000..56303909bcd6f3 --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/one-version.json @@ -0,0 +1,30 @@ +{ + "took": 444, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 10000, + "relation": "gte" + }, + "max_score": null, + "hits": [] + }, + "aggregations": { + "versions": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "8.0.0", + "doc_count": 615285 + } + ] + } + } +} diff --git a/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/versions-first-seen.json b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/versions-first-seen.json new file mode 100644 index 00000000000000..c53b28c8bf5943 --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/services/annotations/__fixtures__/versions-first-seen.json @@ -0,0 +1,24 @@ +{ + "took": 4750, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 10000, + "relation": "gte" + }, + "max_score": null, + "hits": [] + }, + "aggregations": { + "first_seen": { + "value": 1.5281138E12, + "value_as_string": "2018-06-04T12:00:00.000Z" + } + } +} diff --git a/x-pack/legacy/plugins/apm/server/lib/services/annotations/index.test.ts b/x-pack/legacy/plugins/apm/server/lib/services/annotations/index.test.ts new file mode 100644 index 00000000000000..75ac0642a1b8cc --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/services/annotations/index.test.ts @@ -0,0 +1,98 @@ +/* + * 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 { getServiceAnnotations } from '.'; +import { + SearchParamsMock, + inspectSearchParams +} from '../../../../public/utils/testHelpers'; +import noVersions from './__fixtures__/no-versions.json'; +import oneVersion from './__fixtures__/one-version.json'; +import multipleVersions from './__fixtures__/multiple-versions.json'; +import versionsFirstSeen from './__fixtures__/versions-first-seen.json'; + +describe('getServiceAnnotations', () => { + let mock: SearchParamsMock; + + afterEach(() => { + mock.teardown(); + }); + + describe('with 0 versions', () => { + it('returns no annotations', async () => { + mock = await inspectSearchParams( + setup => + getServiceAnnotations({ + setup, + serviceName: 'foo', + environment: 'bar' + }), + { + mockResponse: () => noVersions + } + ); + + expect(mock.response).toEqual({ annotations: [] }); + }); + }); + + describe('with 1 version', () => { + it('returns no annotations', async () => { + mock = await inspectSearchParams( + setup => + getServiceAnnotations({ + setup, + serviceName: 'foo', + environment: 'bar' + }), + { + mockResponse: () => oneVersion + } + ); + + expect(mock.response).toEqual({ annotations: [] }); + }); + }); + + describe('with more than 1 version', () => { + it('returns two annotations', async () => { + const responses = [ + multipleVersions, + versionsFirstSeen, + versionsFirstSeen + ]; + mock = await inspectSearchParams( + setup => + getServiceAnnotations({ + setup, + serviceName: 'foo', + environment: 'bar' + }), + { + mockResponse: () => responses.shift() + } + ); + + expect(mock.spy.mock.calls.length).toBe(3); + + expect(mock.response).toEqual({ + annotations: [ + { + id: '8.0.0', + text: '8.0.0', + time: 1.5281138e12, + type: 'version' + }, + { + id: '7.5.0', + text: '7.5.0', + time: 1.5281138e12, + type: 'version' + } + ] + }); + }); + }); +}); diff --git a/x-pack/legacy/plugins/apm/server/lib/services/annotations/index.ts b/x-pack/legacy/plugins/apm/server/lib/services/annotations/index.ts new file mode 100644 index 00000000000000..c03746ca220ee4 --- /dev/null +++ b/x-pack/legacy/plugins/apm/server/lib/services/annotations/index.ts @@ -0,0 +1,114 @@ +/* + * 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 { isNumber } from 'lodash'; +import { Annotation, AnnotationType } from '../../../../common/annotations'; +import { ESFilter } from '../../../../typings/elasticsearch'; +import { + SERVICE_NAME, + SERVICE_ENVIRONMENT, + PROCESSOR_EVENT +} from '../../../../common/elasticsearch_fieldnames'; +import { Setup, SetupTimeRange } from '../../helpers/setup_request'; +import { rangeFilter } from '../../helpers/range_filter'; +import { SERVICE_VERSION } from '../../../../common/elasticsearch_fieldnames'; + +export async function getServiceAnnotations({ + setup, + serviceName, + environment +}: { + serviceName: string; + environment?: string; + setup: Setup & SetupTimeRange; +}) { + const { start, end, client, indices } = setup; + + const filter: ESFilter[] = [ + { term: { [PROCESSOR_EVENT]: 'transaction' } }, + { range: rangeFilter(start, end) }, + { term: { [SERVICE_NAME]: serviceName } } + ]; + + if (environment) { + filter.push({ term: { [SERVICE_ENVIRONMENT]: environment } }); + } + + const versions = + ( + await client.search({ + index: indices['apm_oss.transactionIndices'], + body: { + size: 0, + track_total_hits: false, + query: { + bool: { + filter + } + }, + aggs: { + versions: { + terms: { + field: SERVICE_VERSION + } + } + } + } + }) + ).aggregations?.versions.buckets.map(bucket => bucket.key) ?? []; + + if (versions.length > 1) { + const annotations = await Promise.all( + versions.map(async version => { + const response = await client.search({ + index: indices['apm_oss.transactionIndices'], + body: { + size: 0, + query: { + bool: { + filter: filter + .filter(esFilter => !Object.keys(esFilter).includes('range')) + .concat({ + term: { + [SERVICE_VERSION]: version + } + }) + } + }, + aggs: { + first_seen: { + min: { + field: '@timestamp' + } + } + }, + track_total_hits: false + } + }); + + const firstSeen = response.aggregations?.first_seen.value; + + if (!isNumber(firstSeen)) { + throw new Error( + 'First seen for version was unexpectedly undefined or null.' + ); + } + + if (firstSeen < start || firstSeen > end) { + return null; + } + + return { + type: AnnotationType.VERSION, + id: version, + time: firstSeen, + text: version + }; + }) + ); + return { annotations: annotations.filter(Boolean) as Annotation[] }; + } + return { annotations: [] }; +} diff --git a/x-pack/legacy/plugins/apm/server/routes/create_apm_api.ts b/x-pack/legacy/plugins/apm/server/routes/create_apm_api.ts index 95488591d4b89f..e98842151da847 100644 --- a/x-pack/legacy/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/legacy/plugins/apm/server/routes/create_apm_api.ts @@ -17,7 +17,8 @@ import { serviceAgentNameRoute, serviceTransactionTypesRoute, servicesRoute, - serviceNodeMetadataRoute + serviceNodeMetadataRoute, + serviceAnnotationsRoute } from './services'; import { agentConfigurationRoute, @@ -75,6 +76,7 @@ const createApmApi = () => { .add(serviceTransactionTypesRoute) .add(servicesRoute) .add(serviceNodeMetadataRoute) + .add(serviceAnnotationsRoute) // Agent configuration .add(agentConfigurationAgentNameRoute) diff --git a/x-pack/legacy/plugins/apm/server/routes/services.ts b/x-pack/legacy/plugins/apm/server/routes/services.ts index 91495bb96b032b..78cb092b85db66 100644 --- a/x-pack/legacy/plugins/apm/server/routes/services.ts +++ b/x-pack/legacy/plugins/apm/server/routes/services.ts @@ -19,6 +19,7 @@ import { getServiceNodeMetadata } from '../lib/services/get_service_node_metadat import { createRoute } from './create_route'; import { uiFiltersRt, rangeRt } from './default_api_types'; import { getServiceMap } from '../lib/services/map'; +import { getServiceAnnotations } from '../lib/services/annotations'; export const servicesRoute = createRoute(() => ({ path: '/api/apm/services', @@ -98,3 +99,29 @@ export const serviceMapRoute = createRoute(() => ({ return new Boom('Not found', { statusCode: 404 }); } })); + +export const serviceAnnotationsRoute = createRoute(() => ({ + path: '/api/apm/services/{serviceName}/annotations', + params: { + path: t.type({ + serviceName: t.string + }), + query: t.intersection([ + rangeRt, + t.partial({ + environment: t.string + }) + ]) + }, + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; + const { environment } = context.params.query; + + return getServiceAnnotations({ + setup, + serviceName, + environment + }); + } +})); diff --git a/x-pack/legacy/plugins/apm/typings/react-vis.d.ts b/x-pack/legacy/plugins/apm/typings/react-vis.d.ts new file mode 100644 index 00000000000000..aef8efc30d5550 --- /dev/null +++ b/x-pack/legacy/plugins/apm/typings/react-vis.d.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +declare module 'react-vis'; diff --git a/x-pack/legacy/plugins/apm/typings/timeseries.ts b/x-pack/legacy/plugins/apm/typings/timeseries.ts index d64486d8e71e91..600be15ea229f5 100644 --- a/x-pack/legacy/plugins/apm/typings/timeseries.ts +++ b/x-pack/legacy/plugins/apm/typings/timeseries.ts @@ -15,12 +15,14 @@ export interface RectCoordinate { x0: number; } -export interface TimeSeries { +export interface TimeSeries< + TCoordinate extends { x: number } = Coordinate | RectCoordinate +> { title: string; titleShort?: string; hideLegend?: boolean; hideTooltipValue?: boolean; - data: Array; + data: TCoordinate[]; legendValue?: string; type: string; color: string; From 966dd82b6474566d647b81a504eda502f60661f1 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 18 Dec 2019 07:48:56 -0700 Subject: [PATCH 56/60] [Maps] gather field formatters in data request (#53311) * [Maps] gather field formatters in data request so they can be used sync in vector_style * review feedback * hasMatchingMetricField * review feedback * fix typo in function name --- .../legacy/plugins/maps/common/constants.js | 2 + .../maps/public/layers/joins/inner_join.js | 6 +- .../public/layers/sources/es_agg_source.js | 5 + .../layers/styles/vector/vector_style.js | 60 +++++++++--- .../maps/public/layers/util/can_skip_fetch.js | 12 +++ .../maps/public/layers/vector_layer.js | 93 +++++++++++++++++-- 6 files changed, 156 insertions(+), 22 deletions(-) diff --git a/x-pack/legacy/plugins/maps/common/constants.js b/x-pack/legacy/plugins/maps/common/constants.js index afe30f3492147b..a6bdee3d2ed129 100644 --- a/x-pack/legacy/plugins/maps/common/constants.js +++ b/x-pack/legacy/plugins/maps/common/constants.js @@ -59,6 +59,8 @@ export const FIELD_ORIGIN = { export const SOURCE_DATA_ID_ORIGIN = 'source'; export const META_ID_ORIGIN_SUFFIX = 'meta'; export const SOURCE_META_ID_ORIGIN = `${SOURCE_DATA_ID_ORIGIN}_${META_ID_ORIGIN_SUFFIX}`; +export const FORMATTERS_ID_ORIGIN_SUFFIX = 'formatters'; +export const SOURCE_FORMATTERS_ID_ORIGIN = `${SOURCE_DATA_ID_ORIGIN}_${FORMATTERS_ID_ORIGIN_SUFFIX}`; export const GEOJSON_FILE = 'GEOJSON_FILE'; diff --git a/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js b/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js index 6671914bce74f1..13a2e05ab8eeb4 100644 --- a/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js +++ b/x-pack/legacy/plugins/maps/public/layers/joins/inner_join.js @@ -6,7 +6,7 @@ import { ESTermSource } from '../sources/es_term_source'; import { getComputedFieldNamePrefix } from '../styles/vector/style_util'; -import { META_ID_ORIGIN_SUFFIX } from '../../../common/constants'; +import { META_ID_ORIGIN_SUFFIX, FORMATTERS_ID_ORIGIN_SUFFIX } from '../../../common/constants'; export class InnerJoin { constructor(joinDescriptor, leftSource) { @@ -45,6 +45,10 @@ export class InnerJoin { return `${this.getSourceDataRequestId()}_${META_ID_ORIGIN_SUFFIX}`; } + getSourceFormattersDataRequestId() { + return `${this.getSourceDataRequestId()}_${FORMATTERS_ID_ORIGIN_SUFFIX}`; + } + getLeftField() { return this._leftField; } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js index c07b51c20ab85f..fd3ae8f0ab7e3a 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_agg_source.js @@ -82,6 +82,11 @@ export class AbstractESAggSource extends AbstractESSource { }); } + hasMatchingMetricField(fieldName) { + const matchingField = this.getMetricFieldForName(fieldName); + return !!matchingField; + } + getMetricFieldForName(fieldName) { return this.getMetricFields().find(metricField => { return metricField.getName() === fieldName; diff --git a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js index d386c0ad4a5e0e..161c0ea69e86ce 100644 --- a/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js +++ b/x-pack/legacy/plugins/maps/public/layers/styles/vector/vector_style.js @@ -19,6 +19,7 @@ import { FIELD_ORIGIN, STYLE_TYPE, SOURCE_META_ID_ORIGIN, + SOURCE_FORMATTERS_ID_ORIGIN, LAYER_STYLE_TYPE, } from '../../../../common/constants'; import { VectorIcon } from './components/legend/vector_icon'; @@ -294,14 +295,17 @@ export class VectorStyle extends AbstractStyle { return this._isOnlySingleFeatureType(VECTOR_SHAPE_TYPES.POLYGON); }; - _getFieldMeta = fieldName => { - const fieldMetaFromLocalFeatures = _.get(this._descriptor, ['__styleMeta', fieldName]); - + _getDynamicPropertyByFieldName(fieldName) { const dynamicProps = this.getDynamicPropertiesArray(); - const dynamicProp = dynamicProps.find(dynamicProp => { + return dynamicProps.find(dynamicProp => { return fieldName === dynamicProp.getField().getName(); }); + } + _getFieldMeta = fieldName => { + const fieldMetaFromLocalFeatures = _.get(this._descriptor, ['__styleMeta', fieldName]); + + const dynamicProp = this._getDynamicPropertyByFieldName(fieldName); if (!dynamicProp || !dynamicProp.isFieldMetaEnabled()) { return fieldMetaFromLocalFeatures; } @@ -311,8 +315,7 @@ export class VectorStyle extends AbstractStyle { dataRequestId = SOURCE_META_ID_ORIGIN; } else { const join = this._layer.getValidJoins().find(join => { - const matchingField = join.getRightJoinSource().getMetricFieldForName(fieldName); - return !!matchingField; + return join.getRightJoinSource().hasMatchingMetricField(fieldName); }); if (join) { dataRequestId = join.getSourceMetaDataRequestId(); @@ -323,7 +326,7 @@ export class VectorStyle extends AbstractStyle { return fieldMetaFromLocalFeatures; } - const styleMetaDataRequest = this._layer._findDataRequestForSource(dataRequestId); + const styleMetaDataRequest = this._layer._findDataRequestById(dataRequestId); if (!styleMetaDataRequest || !styleMetaDataRequest.hasData()) { return fieldMetaFromLocalFeatures; } @@ -334,6 +337,37 @@ export class VectorStyle extends AbstractStyle { return fieldMeta ? fieldMeta : fieldMetaFromLocalFeatures; }; + _getFieldFormatter(fieldName) { + const dynamicProp = this._getDynamicPropertyByFieldName(fieldName); + if (!dynamicProp) { + return null; + } + + let dataRequestId; + if (dynamicProp.getFieldOrigin() === FIELD_ORIGIN.SOURCE) { + dataRequestId = SOURCE_FORMATTERS_ID_ORIGIN; + } else { + const join = this._layer.getValidJoins().find(join => { + return join.getRightJoinSource().hasMatchingMetricField(fieldName); + }); + if (join) { + dataRequestId = join.getSourceFormattersDataRequestId(); + } + } + + if (!dataRequestId) { + return null; + } + + const formattersDataRequest = this._layer._findDataRequestById(dataRequestId); + if (!formattersDataRequest || !formattersDataRequest.hasData()) { + return null; + } + + const formatters = formattersDataRequest.getData(); + return formatters[fieldName]; + } + _getStyleMeta = () => { return _.get(this._descriptor, '__styleMeta', {}); }; @@ -382,7 +416,7 @@ export class VectorStyle extends AbstractStyle { const promises = styles.map(async style => { return { label: await style.getField().getLabel(), - fieldFormatter: await this._source.getFieldFormatter(style.getField().getName()), + fieldFormatter: this._getFieldFormatter(style.getField().getName()), meta: this._getFieldMeta(style.getField().getName()), style, }; @@ -539,14 +573,10 @@ export class VectorStyle extends AbstractStyle { fieldName: fieldDescriptor.name, }); } else if (fieldDescriptor.origin === FIELD_ORIGIN.JOIN) { - let matchingField = null; - const joins = this._layer.getValidJoins(); - joins.find(join => { - const aggSource = join.getRightJoinSource(); - matchingField = aggSource.getMetricFieldForName(fieldDescriptor.name); - return !!matchingField; + const join = this._layer.getValidJoins().find(join => { + return join.getRightJoinSource().hasMatchingMetricField(fieldDescriptor.name); }); - return matchingField; + return join ? join.getRightJoinSource().getMetricFieldForName(fieldDescriptor.name) : null; } else { throw new Error(`Unknown origin-type ${fieldDescriptor.origin}`); } diff --git a/x-pack/legacy/plugins/maps/public/layers/util/can_skip_fetch.js b/x-pack/legacy/plugins/maps/public/layers/util/can_skip_fetch.js index 41f6de65e40321..d9182be56a75fc 100644 --- a/x-pack/legacy/plugins/maps/public/layers/util/can_skip_fetch.js +++ b/x-pack/legacy/plugins/maps/public/layers/util/can_skip_fetch.js @@ -158,3 +158,15 @@ export function canSkipStyleMetaUpdate({ prevDataRequest, nextMeta }) { !updateDueToFields && !updateDueToSourceQuery && !updateDueToIsTimeAware && !updateDueToTime ); } + +export function canSkipFormattersUpdate({ prevDataRequest, nextMeta }) { + if (!prevDataRequest) { + return false; + } + const prevMeta = prevDataRequest.getMeta(); + if (!prevMeta) { + return false; + } + + return !_.isEqual(prevMeta.fieldNames, nextMeta.fieldNames); +} diff --git a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js index 16129087de1f88..30c47658bb3279 100644 --- a/x-pack/legacy/plugins/maps/public/layers/vector_layer.js +++ b/x-pack/legacy/plugins/maps/public/layers/vector_layer.js @@ -13,6 +13,7 @@ import { FEATURE_ID_PROPERTY_NAME, SOURCE_DATA_ID_ORIGIN, SOURCE_META_ID_ORIGIN, + SOURCE_FORMATTERS_ID_ORIGIN, FEATURE_VISIBLE_PROPERTY_NAME, EMPTY_FEATURE_COLLECTION, LAYER_TYPE, @@ -24,7 +25,11 @@ import { JoinTooltipProperty } from './tooltips/join_tooltip_property'; import { EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { DataRequestAbortError } from './util/data_request'; -import { canSkipSourceUpdate, canSkipStyleMetaUpdate } from './util/can_skip_fetch'; +import { + canSkipSourceUpdate, + canSkipStyleMetaUpdate, + canSkipFormattersUpdate, +} from './util/can_skip_fetch'; import { assignFeatureIds } from './util/assign_feature_ids'; import { getFillFilterExpression, @@ -220,7 +225,7 @@ export class VectorLayer extends AbstractLayer { return indexPatternIds; } - _findDataRequestForSource(sourceDataId) { + _findDataRequestById(sourceDataId) { return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId); } @@ -241,7 +246,7 @@ export class VectorLayer extends AbstractLayer { sourceQuery: joinSource.getWhereQuery(), applyGlobalQuery: joinSource.getApplyGlobalQuery(), }; - const prevDataRequest = this._findDataRequestForSource(sourceDataId); + const prevDataRequest = this._findDataRequestById(sourceDataId); const canSkipFetch = await canSkipSourceUpdate({ source: joinSource, @@ -286,6 +291,7 @@ export class VectorLayer extends AbstractLayer { async _syncJoins(syncContext) { const joinSyncs = this.getValidJoins().map(async join => { await this._syncJoinStyleMeta(syncContext, join); + await this._syncJoinFormatters(syncContext, join); return this._syncJoin({ join, ...syncContext }); }); @@ -355,7 +361,7 @@ export class VectorLayer extends AbstractLayer { registerCancelCallback, dataFilters, }) { - const requestToken = Symbol(`layer-source-data:${this.getId()}`); + const requestToken = Symbol(`layer-${this.getId()}-${SOURCE_DATA_ID_ORIGIN}`); const searchFilters = this._getSearchFilters(dataFilters); const prevDataRequest = this.getSourceDataRequest(); @@ -459,13 +465,13 @@ export class VectorLayer extends AbstractLayer { isTimeAware: this._style.isTimeAware() && (await source.isTimeAware()), timeFilters: dataFilters.timeFilters, }; - const prevDataRequest = this._findDataRequestForSource(dataRequestId); + const prevDataRequest = this._findDataRequestById(dataRequestId); const canSkipFetch = canSkipStyleMetaUpdate({ prevDataRequest, nextMeta }); if (canSkipFetch) { return; } - const requestToken = Symbol(`layer-${this.getId()}-style-meta`); + const requestToken = Symbol(`layer-${this.getId()}-${dataRequestId}`); try { startLoading(dataRequestId, requestToken, nextMeta); const layerName = await this.getDisplayName(); @@ -484,12 +490,87 @@ export class VectorLayer extends AbstractLayer { } } + async _syncSourceFormatters(syncContext) { + if (this._style.constructor.type !== LAYER_STYLE_TYPE.VECTOR) { + return; + } + + return this._syncFormatters({ + source: this._source, + dataRequestId: SOURCE_FORMATTERS_ID_ORIGIN, + fields: this._style + .getDynamicPropertiesArray() + .filter(dynamicStyleProp => { + return dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.SOURCE; + }) + .map(dynamicStyleProp => { + return dynamicStyleProp.getField(); + }), + ...syncContext, + }); + } + + async _syncJoinFormatters(syncContext, join) { + const joinSource = join.getRightJoinSource(); + return this._syncFormatters({ + source: joinSource, + dataRequestId: join.getSourceFormattersDataRequestId(), + fields: this._style + .getDynamicPropertiesArray() + .filter(dynamicStyleProp => { + const matchingField = joinSource.getMetricFieldForName( + dynamicStyleProp.getField().getName() + ); + return dynamicStyleProp.getFieldOrigin() === FIELD_ORIGIN.JOIN && !!matchingField; + }) + .map(dynamicStyleProp => { + return dynamicStyleProp.getField(); + }), + ...syncContext, + }); + } + + async _syncFormatters({ source, dataRequestId, fields, startLoading, stopLoading, onLoadError }) { + if (fields.length === 0) { + return; + } + + const fieldNames = fields.map(field => { + return field.getName(); + }); + const nextMeta = { + fieldNames: _.uniq(fieldNames).sort(), + }; + const prevDataRequest = this._findDataRequestById(dataRequestId); + const canSkipUpdate = canSkipFormattersUpdate({ prevDataRequest, nextMeta }); + if (canSkipUpdate) { + return; + } + + const requestToken = Symbol(`layer-${this.getId()}-${dataRequestId}`); + try { + startLoading(dataRequestId, requestToken, nextMeta); + + const formatters = {}; + const promises = fields.map(async field => { + const fieldName = field.getName(); + formatters[fieldName] = await source.getFieldFormatter(fieldName); + }); + await Promise.all(promises); + + stopLoading(dataRequestId, requestToken, formatters, nextMeta); + } catch (error) { + onLoadError(dataRequestId, requestToken, error.message); + } + } + async syncData(syncContext) { if (!this.isVisible() || !this.showAtZoomLevel(syncContext.dataFilters.zoom)) { return; } await this._syncSourceStyleMeta(syncContext); + await this._syncSourceFormatters(syncContext); const sourceResult = await this._syncSource(syncContext); if ( !sourceResult.featureCollection || From 27b6e1c4795044cbd67080643a3df5224c55b28d Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Wed, 18 Dec 2019 16:04:12 +0100 Subject: [PATCH 57/60] Upgrade typescript-eslint to 2.12 (#53477) --- package.json | 4 +-- packages/eslint-config-kibana/package.json | 4 +-- yarn.lock | 40 +++++++++++----------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 985fbfd1b6a2f9..a771a130d08b1e 100644 --- a/package.json +++ b/package.json @@ -365,8 +365,8 @@ "@types/uuid": "^3.4.4", "@types/vinyl-fs": "^2.4.11", "@types/zen-observable": "^0.8.0", - "@typescript-eslint/eslint-plugin": "^2.10.0", - "@typescript-eslint/parser": "^2.10.0", + "@typescript-eslint/eslint-plugin": "^2.12.0", + "@typescript-eslint/parser": "^2.12.0", "angular-mocks": "^1.7.8", "archiver": "^3.1.1", "axe-core": "^3.3.2", diff --git a/packages/eslint-config-kibana/package.json b/packages/eslint-config-kibana/package.json index 7917297883b033..04602d196a7f36 100644 --- a/packages/eslint-config-kibana/package.json +++ b/packages/eslint-config-kibana/package.json @@ -15,8 +15,8 @@ }, "homepage": "https://github.com/elastic/eslint-config-kibana#readme", "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^2.10.0", - "@typescript-eslint/parser": "^2.10.0", + "@typescript-eslint/eslint-plugin": "^2.12.0", + "@typescript-eslint/parser": "^2.12.0", "babel-eslint": "^10.0.3", "eslint": "^6.5.1", "eslint-plugin-babel": "^5.3.0", diff --git a/yarn.lock b/yarn.lock index 7ffd19d49bf55c..ef35e06a52f7cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4454,24 +4454,24 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d" integrity sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg== -"@typescript-eslint/eslint-plugin@^2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.10.0.tgz#c4cb103275e555e8a7e9b3d14c5951eb6d431e70" - integrity sha512-rT51fNLW0u3fnDGnAHVC5nu+Das+y2CpW10yqvf6/j5xbuUV3FxA3mBaIbM24CXODXjbgUznNb4Kg9XZOUxKAw== +"@typescript-eslint/eslint-plugin@^2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.12.0.tgz#0da7cbca7b24f4c6919e9eb31c704bfb126f90ad" + integrity sha512-1t4r9rpLuEwl3hgt90jY18wJHSyb0E3orVL3DaqwmpiSDHmHiSspVsvsFF78BJ/3NNG3qmeso836jpuBWYziAA== dependencies: - "@typescript-eslint/experimental-utils" "2.10.0" + "@typescript-eslint/experimental-utils" "2.12.0" eslint-utils "^1.4.3" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.10.0.tgz#8db1656cdfd3d9dcbdbf360b8274dea76f0b2c2c" - integrity sha512-FZhWq6hWWZBP76aZ7bkrfzTMP31CCefVIImrwP3giPLcoXocmLTmr92NLZxuIcTL4GTEOE33jQMWy9PwelL+yQ== +"@typescript-eslint/experimental-utils@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.12.0.tgz#e0a76ffb6293e058748408a191921e453c31d40d" + integrity sha512-jv4gYpw5N5BrWF3ntROvCuLe1IjRenLy5+U57J24NbPGwZFAjhnM45qpq0nDH1y/AZMb3Br25YiNVwyPbz6RkA== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.10.0" + "@typescript-eslint/typescript-estree" "2.12.0" eslint-scope "^5.0.0" "@typescript-eslint/experimental-utils@^1.13.0": @@ -4483,14 +4483,14 @@ "@typescript-eslint/typescript-estree" "1.13.0" eslint-scope "^4.0.0" -"@typescript-eslint/parser@^2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.10.0.tgz#24b2e48384ab6d5a6121e4c4faf8892c79657ad3" - integrity sha512-wQNiBokcP5ZsTuB+i4BlmVWq6o+oAhd8en2eSm/EE9m7BgZUIfEeYFd6z3S+T7bgNuloeiHA1/cevvbBDLr98g== +"@typescript-eslint/parser@^2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.12.0.tgz#393f1604943a4ca570bb1a45bc8834e9b9158884" + integrity sha512-lPdkwpdzxEfjI8TyTzZqPatkrswLSVu4bqUgnB03fHSOwpC7KSerPgJRgIAf11UGNf7HKjJV6oaPZI4AghLU6g== dependencies: "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.10.0" - "@typescript-eslint/typescript-estree" "2.10.0" + "@typescript-eslint/experimental-utils" "2.12.0" + "@typescript-eslint/typescript-estree" "2.12.0" eslint-visitor-keys "^1.1.0" "@typescript-eslint/typescript-estree@1.13.0": @@ -4501,10 +4501,10 @@ lodash.unescape "4.0.1" semver "5.5.0" -"@typescript-eslint/typescript-estree@2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.10.0.tgz#89cdabd5e8c774e9d590588cb42fb9afd14dcbd9" - integrity sha512-oOYnplddQNm/LGVkqbkAwx4TIBuuZ36cAQq9v3nFIU9FmhemHuVzAesMSXNQDdAzCa5bFgCrfD3JWhYVKlRN2g== +"@typescript-eslint/typescript-estree@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz#bd9e547ccffd17dfab0c3ab0947c80c8e2eb914c" + integrity sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ== dependencies: debug "^4.1.1" eslint-visitor-keys "^1.1.0" From aa1af60ea4b8bf84dee80ec3c5bf36c3a9e614a0 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Wed, 18 Dec 2019 15:34:58 +0000 Subject: [PATCH 58/60] [SIEM] Alerts view - adding alerts table (#51959) * add alert view to hosts page * add defaultHeaders * add alerts table * fix dsl query * add alerts histogram * add i18n for alerts table * fix types error * fix type issue * whitespace cleanup * fix types * fix types * fix types * fix types * fix types * rename params * fix unit test * fix types * revert change on updateHostsSort * remove unused prop * update unit test * pair programming with angela to get filter working * update alerts query * clean up * fix queries * align type for pageFilters * apply page filter for network page * simplify filter props for alerts view * clean up * replace hard coded tab name --- .../components/alerts_viewer/alerts_table.tsx | 85 +++++++++++++ .../alerts_viewer/default_headers.ts | 68 ++++++++++ .../public/components/alerts_viewer/index.tsx | 59 +++++++++ .../components/alerts_viewer/translations.ts | 19 +++ .../public/components/alerts_viewer/types.ts | 26 ++++ .../public/components/events_viewer/index.tsx | 12 +- .../navigation/breadcrumbs/index.test.ts | 32 ++++- .../navigation/breadcrumbs/index.ts | 48 ++++--- .../page/hosts/alerts_over_time/index.tsx | 30 +++++ .../hosts/alerts_over_time/translation.ts | 24 ++++ .../public/components/url_state/index.tsx | 5 +- .../alerts_over_time.gql_query.ts | 37 ++++++ .../alerts/alerts_over_time/index.tsx | 108 ++++++++++++++++ .../siem/public/graphql/introspection.json | 106 +++++++++++++++- .../plugins/siem/public/graphql/types.ts | 73 ++++++++++- .../plugins/siem/public/mock/global_state.ts | 6 + .../pages/hosts/details/details_tabs.tsx | 6 + .../siem/public/pages/hosts/details/index.tsx | 53 ++++---- .../public/pages/hosts/details/nav_tabs.tsx | 7 ++ .../siem/public/pages/hosts/details/types.ts | 4 +- .../siem/public/pages/hosts/details/utils.ts | 14 ++- .../plugins/siem/public/pages/hosts/hosts.tsx | 13 +- .../siem/public/pages/hosts/hosts_tabs.tsx | 5 + .../plugins/siem/public/pages/hosts/index.tsx | 6 +- .../siem/public/pages/hosts/nav_tabs.tsx | 7 ++ .../navigation/alerts_query_tab_body.tsx | 54 ++++++++ .../public/pages/hosts/navigation/index.ts | 1 + .../public/pages/hosts/navigation/types.ts | 15 ++- .../siem/public/pages/hosts/translations.ts | 4 + .../public/pages/network/ip_details/utils.ts | 42 +++++-- .../navigation/alerts_query_tab_body.tsx | 68 ++++++++++ .../pages/network/navigation/nav_tabs.tsx | 7 ++ .../network/navigation/network_routes.tsx | 5 + .../public/pages/network/navigation/types.ts | 7 +- .../public/pages/network/navigation/utils.ts | 5 +- .../siem/public/pages/network/network.tsx | 17 ++- .../siem/public/pages/network/translations.ts | 4 + .../siem/public/store/hosts/helpers.test.ts | 16 +++ .../siem/public/store/hosts/helpers.ts | 8 ++ .../plugins/siem/public/store/hosts/model.ts | 2 + .../siem/public/store/hosts/reducer.ts | 8 ++ .../siem/public/store/hosts/selectors.ts | 3 + .../siem/public/store/network/helpers.test.ts | 8 ++ .../siem/public/store/network/model.ts | 2 + .../siem/public/store/network/reducer.ts | 4 + .../plugins/siem/public/utils/route/types.ts | 12 +- .../siem/server/graphql/alerts/index.ts | 8 ++ .../siem/server/graphql/alerts/resolvers.ts | 38 ++++++ .../siem/server/graphql/alerts/schema.gql.ts | 23 ++++ .../plugins/siem/server/graphql/index.ts | 2 + .../plugins/siem/server/graphql/types.ts | 83 ++++++++++-- .../legacy/plugins/siem/server/init_server.ts | 2 + .../lib/alerts/elasticsearch_adapter.ts | 63 ++++++++++ .../lib/alerts/elasticseatch_adapter.test.ts | 57 +++++++++ .../plugins/siem/server/lib/alerts/index.ts | 21 ++++ .../plugins/siem/server/lib/alerts/mock.ts | 115 +++++++++++++++++ .../siem/server/lib/alerts/query.dsl.ts | 118 ++++++++++++++++++ .../plugins/siem/server/lib/alerts/types.ts | 27 ++++ .../plugins/siem/server/lib/compose/kibana.ts | 2 + .../lib/events/elasticsearch_adapter.ts | 1 - .../legacy/plugins/siem/server/lib/types.ts | 2 + 61 files changed, 1608 insertions(+), 99 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/public/components/alerts_viewer/alerts_table.tsx create mode 100644 x-pack/legacy/plugins/siem/public/components/alerts_viewer/default_headers.ts create mode 100644 x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx create mode 100644 x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts create mode 100644 x-pack/legacy/plugins/siem/public/components/alerts_viewer/types.ts create mode 100644 x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/index.tsx create mode 100644 x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/translation.ts create mode 100644 x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/alerts_over_time.gql_query.ts create mode 100644 x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/index.tsx create mode 100644 x-pack/legacy/plugins/siem/public/pages/hosts/navigation/alerts_query_tab_body.tsx create mode 100644 x-pack/legacy/plugins/siem/public/pages/network/navigation/alerts_query_tab_body.tsx create mode 100644 x-pack/legacy/plugins/siem/server/graphql/alerts/index.ts create mode 100644 x-pack/legacy/plugins/siem/server/graphql/alerts/resolvers.ts create mode 100644 x-pack/legacy/plugins/siem/server/graphql/alerts/schema.gql.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/alerts/elasticsearch_adapter.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/alerts/elasticseatch_adapter.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/alerts/index.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/alerts/mock.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/alerts/query.dsl.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/alerts/types.ts diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/alerts_table.tsx b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/alerts_table.tsx new file mode 100644 index 00000000000000..e0101dc3ab74be --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/alerts_table.tsx @@ -0,0 +1,85 @@ +/* + * 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 React, { useMemo } from 'react'; + +import { esFilters } from '../../../../../../../src/plugins/data/common/es_query'; +import { StatefulEventsViewer } from '../events_viewer'; +import * as i18n from './translations'; +import { alertsDefaultModel } from './default_headers'; + +export interface OwnProps { + end: number; + id: string; + start: number; +} + +const ALERTS_TABLE_ID = 'timeline-alerts-table'; +const defaultAlertsFilters: esFilters.Filter[] = [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'event.kind', + params: { + query: 'alert', + }, + }, + query: { + bool: { + filter: [ + { + bool: { + should: [ + { + match: { + 'event.kind': 'alert', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + }, +]; + +export const AlertsTable = React.memo( + ({ + endDate, + startDate, + pageFilters = [], + }: { + endDate: number; + startDate: number; + pageFilters?: esFilters.Filter[]; + }) => { + const alertsFilter = useMemo(() => [...defaultAlertsFilters, ...pageFilters], [pageFilters]); + return ( + ({ + documentType: i18n.ALERTS_DOCUMENT_TYPE, + footerText: i18n.TOTAL_COUNT_OF_ALERTS, + showCheckboxes: false, + showRowRenderers: false, + title: i18n.ALERTS_TABLE_TITLE, + }), + [] + )} + /> + ); + } +); diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/default_headers.ts b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/default_headers.ts new file mode 100644 index 00000000000000..52990f521b58de --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/default_headers.ts @@ -0,0 +1,68 @@ +/* + * 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 { ColumnHeader } from '../timeline/body/column_headers/column_header'; +import { defaultColumnHeaderType } from '../timeline/body/column_headers/default_headers'; +import { DEFAULT_COLUMN_MIN_WIDTH, DEFAULT_DATE_COLUMN_MIN_WIDTH } from '../timeline/body/helpers'; +import { timelineDefaults, SubsetTimelineModel } from '../../store/timeline/model'; + +export const alertsHeaders: ColumnHeader[] = [ + { + columnHeaderType: defaultColumnHeaderType, + id: '@timestamp', + width: DEFAULT_DATE_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'event.module', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'event.dataset', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'event.category', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'event.severity', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'observer.name', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'host.name', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'message', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'agent.id', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, + { + columnHeaderType: defaultColumnHeaderType, + id: 'agent.type', + width: DEFAULT_COLUMN_MIN_WIDTH, + }, +]; + +export const alertsDefaultModel: SubsetTimelineModel = { + ...timelineDefaults, + columns: alertsHeaders, +}; diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx new file mode 100644 index 00000000000000..c8f1bb22789178 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx @@ -0,0 +1,59 @@ +/* + * 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 { noop } from 'lodash/fp'; +import React from 'react'; + +import { EuiSpacer } from '@elastic/eui'; +import { manageQuery } from '../page/manage_query'; +import { AlertsOverTimeHistogram } from '../page/hosts/alerts_over_time'; +import { AlertsComponentsQueryProps } from './types'; +import { AlertsOverTimeQuery } from '../../containers/alerts/alerts_over_time'; +import { hostsModel } from '../../store/model'; +import { AlertsTable } from './alerts_table'; + +const AlertsOverTimeManage = manageQuery(AlertsOverTimeHistogram); +export const AlertsView = ({ + defaultFilters, + deleteQuery, + endDate, + filterQuery, + pageFilters, + skip, + setQuery, + startDate, + type, + updateDateRange = noop, +}: AlertsComponentsQueryProps) => ( + <> + + {({ alertsOverTime, loading, id, inspect, refetch, totalCount }) => ( + + )} + + + + +); + +AlertsView.displayName = 'AlertsView'; diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts new file mode 100644 index 00000000000000..987665c9413e36 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/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 ALERTS_DOCUMENT_TYPE = i18n.translate('xpack.siem.hosts.alertsDocumentType', { + defaultMessage: 'Alerts', +}); + +export const TOTAL_COUNT_OF_ALERTS = i18n.translate('xpack.siem.hosts.totalCountOfAlerts', { + defaultMessage: 'alerts match the search criteria', +}); + +export const ALERTS_TABLE_TITLE = i18n.translate('xpack.siem.hosts.alertsDocumentType', { + defaultMessage: 'Alerts', +}); diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/types.ts b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/types.ts new file mode 100644 index 00000000000000..8a17c1102e7764 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/types.ts @@ -0,0 +1,26 @@ +/* + * 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 { esFilters } from '../../../../../../../src/plugins/data/common'; +import { HostsComponentsQueryProps } from '../../pages/hosts/navigation/types'; +import { NetworkComponentQueryProps } from '../../pages/network/navigation/types'; + +type CommonQueryProps = HostsComponentsQueryProps | NetworkComponentQueryProps; +export interface AlertsComponentsQueryProps + extends Pick< + CommonQueryProps, + | 'deleteQuery' + | 'endDate' + | 'filterQuery' + | 'skip' + | 'setQuery' + | 'startDate' + | 'type' + | 'updateDateRange' + > { + pageFilters: esFilters.Filter[]; + defaultFilters?: esFilters.Filter[]; +} diff --git a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx index 21292e4ac32545..b614776cd90cfb 100644 --- a/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/events_viewer/index.tsx @@ -5,7 +5,7 @@ */ import { isEqual } from 'lodash/fp'; -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState, useMemo } from 'react'; import { connect } from 'react-redux'; import { ActionCreator } from 'typescript-fsa'; import chrome from 'ui/chrome'; @@ -32,6 +32,7 @@ export interface OwnProps { id: string; start: number; headerFilterGroup?: React.ReactNode; + pageFilters?: esFilters.Filter[]; timelineTypeContext?: TimelineTypeContextProps; utilityBar?: (totalCount: number) => React.ReactNode; } @@ -150,7 +151,7 @@ const StatefulEventsViewerComponent = React.memo( const handleOnMouseEnter = useCallback(() => setShowInspect(true), []); const handleOnMouseLeave = useCallback(() => setShowInspect(false), []); - + const eventsFilter = useMemo(() => [...filters], [defaultFilters]); return (
( id={id} dataProviders={dataProviders!} end={end} - filters={[...filters, ...defaultFilters]} + filters={eventsFilter} headerFilterGroup={headerFilterGroup} indexPattern={indexPatterns ?? { fields: [], title: '' }} isLive={isLive} @@ -192,7 +193,8 @@ const StatefulEventsViewerComponent = React.memo( isEqual(prevProps.query, nextProps.query) && prevProps.pageCount === nextProps.pageCount && isEqual(prevProps.sort, nextProps.sort) && - prevProps.start === nextProps.start + prevProps.start === nextProps.start && + isEqual(prevProps.defaultFilters, nextProps.defaultFilters) ); StatefulEventsViewerComponent.displayName = 'StatefulEventsViewerComponent'; @@ -227,7 +229,7 @@ export const StatefulEventsViewer = connect(makeMapStateToProps, { createTimeline: timelineActions.createTimeline, deleteEventQuery: inputsActions.deleteOneQuery, updateItemsPerPage: timelineActions.updateItemsPerPage, - updateSort: timelineActions.updateSort, removeColumn: timelineActions.removeColumn, upsertColumn: timelineActions.upsertColumn, + setSearchBarFilter: inputsActions.setSearchBarFilter, })(StatefulEventsViewerComponent); diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.test.ts b/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.test.ts index 02135348957ff3..f9d63a8594180e 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.test.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.test.ts @@ -9,8 +9,9 @@ import { encodeIpv6 } from '../../../lib/helpers'; import { getBreadcrumbsForRoute, setBreadcrumbs } from '.'; import { HostsTableType } from '../../../store/hosts/model'; -import { RouteSpyState } from '../../../utils/route/types'; +import { RouteSpyState, SiemRouteType } from '../../../utils/route/types'; import { TabNavigationProps } from '../tab_navigation/types'; +import { NetworkRouteType } from '../../../pages/network/navigation/types'; jest.mock('ui/chrome', () => ({ getBasePath: () => { @@ -30,6 +31,17 @@ jest.mock('../../search_bar', () => ({ }, })); +const mockDefaultTab = (pageName: string): SiemRouteType | undefined => { + switch (pageName) { + case 'hosts': + return HostsTableType.authentications; + case 'network': + return NetworkRouteType.flows; + default: + return undefined; + } +}; + const getMockObject = ( pageName: string, pathName: string, @@ -69,7 +81,7 @@ const getMockObject = ( pageName, pathName, search: '', - tabName: HostsTableType.authentications, + tabName: mockDefaultTab(pageName) as HostsTableType, query: { query: '', language: 'kuery' }, filters: [], timeline: { @@ -136,6 +148,10 @@ describe('Navigation Breadcrumbs', () => { href: '#/link-to/network?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))', }, + { + text: 'Flows', + href: '', + }, ]); }); @@ -176,7 +192,11 @@ describe('Navigation Breadcrumbs', () => { href: '#/link-to/network?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))', }, - { text: '192.0.2.255', href: '' }, + { + text: ipv4, + href: `#/link-to/network/ip/${ipv4}?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))`, + }, + { text: 'Flows', href: '' }, ]); }); @@ -189,7 +209,11 @@ describe('Navigation Breadcrumbs', () => { href: '#/link-to/network?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))', }, - { text: '2001:db8:ffff:ffff:ffff:ffff:ffff:ffff', href: '' }, + { + text: ipv6, + href: `#/link-to/network/ip/${ipv6Encoded}?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))`, + }, + { text: 'Flows', href: '' }, ]); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.ts b/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.ts index 8d9ebb964ce631..9eee5b21e83f3c 100644 --- a/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.ts +++ b/x-pack/legacy/plugins/siem/public/components/navigation/breadcrumbs/index.ts @@ -6,20 +6,20 @@ import chrome, { Breadcrumb } from 'ui/chrome'; -import { getOr } from 'lodash/fp'; +import { getOr, omit } from 'lodash/fp'; import { APP_NAME } from '../../../../common/constants'; import { getBreadcrumbs as getHostDetailsBreadcrumbs } from '../../../pages/hosts/details/utils'; import { getBreadcrumbs as getIPDetailsBreadcrumbs } from '../../../pages/network/ip_details'; import { SiemPageName } from '../../../pages/home/types'; -import { RouteSpyState } from '../../../utils/route/types'; +import { RouteSpyState, HostRouteSpyState, NetworkRouteSpyState } from '../../../utils/route/types'; import { getOverviewUrl } from '../../link_to'; import { TabNavigationProps } from '../tab_navigation/types'; import { getSearch } from '../helpers'; import { SearchNavTab } from '../types'; -export const setBreadcrumbs = (object: RouteSpyState & TabNavigationProps) => { - const breadcrumbs = getBreadcrumbsForRoute(object); +export const setBreadcrumbs = (spyState: RouteSpyState & TabNavigationProps) => { + const breadcrumbs = getBreadcrumbsForRoute(spyState); if (breadcrumbs) { chrome.breadcrumbs.set(breadcrumbs); } @@ -32,19 +32,26 @@ export const siemRootBreadcrumb: Breadcrumb[] = [ }, ]; +const isNetworkRoutes = (spyState: RouteSpyState): spyState is NetworkRouteSpyState => + spyState != null && spyState.pageName === SiemPageName.network; + +const isHostsRoutes = (spyState: RouteSpyState): spyState is HostRouteSpyState => + spyState != null && spyState.pageName === SiemPageName.hosts; + export const getBreadcrumbsForRoute = ( object: RouteSpyState & TabNavigationProps ): Breadcrumb[] | null => { - if (object != null && object.navTabs && object.pageName === SiemPageName.hosts) { + const spyState: RouteSpyState = omit('navTabs', object); + if (isHostsRoutes(spyState) && object.navTabs) { const tempNav: SearchNavTab = { urlKey: 'host', isDetailPage: false }; - let urlStateKeys = [getOr(tempNav, object.pageName, object.navTabs)]; - if (object.tabName != null) { - urlStateKeys = [...urlStateKeys, getOr(tempNav, object.tabName, object.navTabs)]; + let urlStateKeys = [getOr(tempNav, spyState.pageName, object.navTabs)]; + if (spyState.tabName != null) { + urlStateKeys = [...urlStateKeys, getOr(tempNav, spyState.tabName, object.navTabs)]; } return [ ...siemRootBreadcrumb, ...getHostDetailsBreadcrumbs( - object, + spyState, urlStateKeys.reduce( (acc: string[], item: SearchNavTab) => [...acc, getSearch(item, object)], [] @@ -52,22 +59,33 @@ export const getBreadcrumbsForRoute = ( ), ]; } - if (object != null && object.navTabs && object.pageName === SiemPageName.network) { + if (isNetworkRoutes(spyState) && object.navTabs) { const tempNav: SearchNavTab = { urlKey: 'network', isDetailPage: false }; - const urlStateKeys = [getOr(tempNav, object.pageName, object.navTabs)]; + let urlStateKeys = [getOr(tempNav, spyState.pageName, object.navTabs)]; + if (spyState.tabName != null) { + urlStateKeys = [...urlStateKeys, getOr(tempNav, spyState.tabName, object.navTabs)]; + } return [ ...siemRootBreadcrumb, ...getIPDetailsBreadcrumbs( - object.detailName, - urlStateKeys.reduce((acc: string[], item) => [...acc, getSearch(item, object)], []) + spyState, + urlStateKeys.reduce( + (acc: string[], item: SearchNavTab) => [...acc, getSearch(item, object)], + [] + ) ), ]; } - if (object != null && object.navTabs && object.pageName && object.navTabs[object.pageName]) { + if ( + spyState != null && + object.navTabs && + spyState.pageName && + object.navTabs[spyState.pageName] + ) { return [ ...siemRootBreadcrumb, { - text: object.navTabs[object.pageName].name, + text: object.navTabs[spyState.pageName].name, href: '', }, ]; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/index.tsx new file mode 100644 index 00000000000000..031e1cd767be8e --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/index.tsx @@ -0,0 +1,30 @@ +/* + * 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 React from 'react'; + +import * as i18n from './translation'; +import { MatrixHistogram } from '../../../matrix_histogram'; +import { MatrixHistogramBasicProps } from '../../../matrix_histogram/types'; +import { MatrixOverTimeHistogramData } from '../../../../graphql/types'; + +export const AlertsOverTimeHistogram = ( + props: MatrixHistogramBasicProps +) => { + const dataKey = 'alertsOverTime'; + const { totalCount } = props; + const subtitle = `${i18n.SHOWING}: ${totalCount.toLocaleString()} ${i18n.UNIT(totalCount)}`; + const { ...matrixOverTimeProps } = props; + + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/translation.ts b/x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/translation.ts new file mode 100644 index 00000000000000..380ca0cd3baaf9 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/alerts_over_time/translation.ts @@ -0,0 +1,24 @@ +/* + * 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 ALERTS_COUNT_FREQUENCY_BY_MODULE = i18n.translate( + 'xpack.siem.alertsOverTime.alertsCountFrequencyByModuleTitle', + { + defaultMessage: 'Alerts count by module', + } +); + +export const SHOWING = i18n.translate('xpack.siem.alertsOverTime.showing', { + defaultMessage: 'Showing', +}); + +export const UNIT = (totalCount: number) => + i18n.translate('xpack.siem.alertsOverTime.unit', { + values: { totalCount }, + defaultMessage: `{totalCount, plural, =1 {alert} other {alerts}}`, + }); diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx index 8164348620b507..a7e7729de2e27e 100644 --- a/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/url_state/index.tsx @@ -43,6 +43,9 @@ export const UrlStateRedux = compose(props => { const [routeProps] = useRouteSpy(); - const urlStateReduxProps: RouteSpyState & UrlStateProps = { ...routeProps, ...props }; + const urlStateReduxProps: RouteSpyState & UrlStateProps = { + ...routeProps, + ...props, + }; return ; }); diff --git a/x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/alerts_over_time.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/alerts_over_time.gql_query.ts new file mode 100644 index 00000000000000..428cf25ea1b8eb --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/alerts_over_time.gql_query.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. + */ + +import gql from 'graphql-tag'; + +export const AlertsOverTimeGqlQuery = gql` + query GetAlertsOverTimeQuery( + $sourceId: ID! + $timerange: TimerangeInput! + $defaultIndex: [String!]! + $filterQuery: String + $inspect: Boolean! + ) { + source(id: $sourceId) { + id + AlertsHistogram( + timerange: $timerange + filterQuery: $filterQuery + defaultIndex: $defaultIndex + ) { + alertsOverTimeByModule { + x + y + g + } + totalCount + inspect @include(if: $inspect) { + dsl + response + } + } + } + } +`; diff --git a/x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/index.tsx b/x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/index.tsx new file mode 100644 index 00000000000000..98dcef51292ae3 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/containers/alerts/alerts_over_time/index.tsx @@ -0,0 +1,108 @@ +/* + * 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 { getOr } from 'lodash/fp'; +import React from 'react'; +import { Query } from 'react-apollo'; +import { connect } from 'react-redux'; + +import chrome from 'ui/chrome'; +import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; +import { inputsModel, State, inputsSelectors, hostsModel } from '../../../store'; +import { createFilter, getDefaultFetchPolicy } from '../../helpers'; +import { QueryTemplate, QueryTemplateProps } from '../../query_template'; + +import { AlertsOverTimeGqlQuery } from './alerts_over_time.gql_query'; +import { MatrixOverTimeHistogramData, GetAlertsOverTimeQuery } from '../../../graphql/types'; + +const ID = 'alertsOverTimeQuery'; + +export interface AlertsArgs { + endDate: number; + alertsOverTime: MatrixOverTimeHistogramData[]; + id: string; + inspect: inputsModel.InspectQuery; + loading: boolean; + refetch: inputsModel.Refetch; + startDate: number; + totalCount: number; +} + +export interface OwnProps extends QueryTemplateProps { + children?: (args: AlertsArgs) => React.ReactNode; + type: hostsModel.HostsType; +} + +export interface AlertsOverTimeComponentReduxProps { + isInspected: boolean; +} + +type AlertsOverTimeProps = OwnProps & AlertsOverTimeComponentReduxProps; + +class AlertsOverTimeComponentQuery extends QueryTemplate< + AlertsOverTimeProps, + GetAlertsOverTimeQuery.Query, + GetAlertsOverTimeQuery.Variables +> { + public render() { + const { + children, + endDate, + filterQuery, + id = ID, + isInspected, + sourceId, + startDate, + } = this.props; + return ( + + query={AlertsOverTimeGqlQuery} + fetchPolicy={getDefaultFetchPolicy()} + notifyOnNetworkStatusChange + variables={{ + filterQuery: createFilter(filterQuery), + sourceId, + timerange: { + interval: '12h', + from: startDate!, + to: endDate!, + }, + defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY), + inspect: isInspected, + }} + > + {({ data, loading, refetch }) => { + const source = getOr({}, `source.AlertsHistogram`, data); + const alertsOverTime = getOr([], `alertsOverTimeByModule`, source); + const totalCount = getOr(-1, 'totalCount', source); + return children!({ + endDate: endDate!, + alertsOverTime, + id, + inspect: getOr(null, 'inspect', source), + loading, + refetch, + startDate: startDate!, + totalCount, + }); + }} + + ); + } +} + +const makeMapStateToProps = () => { + const getQuery = inputsSelectors.globalQueryByIdSelector(); + const mapStateToProps = (state: State, { type, id = ID }: OwnProps) => { + const { isInspected } = getQuery(state, id); + return { + isInspected, + }; + }; + return mapStateToProps; +}; + +export const AlertsOverTimeQuery = connect(makeMapStateToProps)(AlertsOverTimeComponentQuery); diff --git a/x-pack/legacy/plugins/siem/public/graphql/introspection.json b/x-pack/legacy/plugins/siem/public/graphql/introspection.json index 7c173a9a90626b..8ebc66b7f38a70 100644 --- a/x-pack/legacy/plugins/siem/public/graphql/introspection.json +++ b/x-pack/legacy/plugins/siem/public/graphql/introspection.json @@ -666,6 +666,53 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "AlertsHistogram", + "description": "", + "args": [ + { + "name": "filterQuery", + "description": "", + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "defaultValue": null + }, + { + "name": "defaultIndex", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + } + } + }, + "defaultValue": null + }, + { + "name": "timerange", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null } + }, + "defaultValue": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "AlertsOverTimeData", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "AnomaliesOverTime", "description": "", @@ -2540,7 +2587,7 @@ }, { "kind": "OBJECT", - "name": "AnomaliesOverTimeData", + "name": "AlertsOverTimeData", "description": "", "fields": [ { @@ -2552,7 +2599,7 @@ "deprecationReason": null }, { - "name": "anomaliesOverTime", + "name": "alertsOverTimeByModule", "description": "", "args": [], "type": { @@ -2691,6 +2738,61 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "AnomaliesOverTimeData", + "description": "", + "fields": [ + { + "name": "inspect", + "description": "", + "args": [], + "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "anomaliesOverTime", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "MatrixOverTimeHistogramData", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "totalCount", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "PaginationInputPaginated", diff --git a/x-pack/legacy/plugins/siem/public/graphql/types.ts b/x-pack/legacy/plugins/siem/public/graphql/types.ts index 1464b556480351..6dfde08058f7cb 100644 --- a/x-pack/legacy/plugins/siem/public/graphql/types.ts +++ b/x-pack/legacy/plugins/siem/public/graphql/types.ts @@ -457,6 +457,8 @@ export interface Source { /** The status of the source */ status: SourceStatus; + AlertsHistogram: AlertsOverTimeData; + AnomaliesOverTime: AnomaliesOverTimeData; /** Gets Authentication success and failures based on a timerange */ Authentications: AuthenticationsData; @@ -558,10 +560,10 @@ export interface IndexField { format?: Maybe; } -export interface AnomaliesOverTimeData { +export interface AlertsOverTimeData { inspect?: Maybe; - anomaliesOverTime: MatrixOverTimeHistogramData[]; + alertsOverTimeByModule: MatrixOverTimeHistogramData[]; totalCount: number; } @@ -580,6 +582,14 @@ export interface MatrixOverTimeHistogramData { g: string; } +export interface AnomaliesOverTimeData { + inspect?: Maybe; + + anomaliesOverTime: MatrixOverTimeHistogramData[]; + + totalCount: number; +} + export interface AuthenticationsData { edges: AuthenticationsEdges[]; @@ -2137,6 +2147,13 @@ export interface GetAllTimelineQueryArgs { onlyUserFavorite?: Maybe; } +export interface AlertsHistogramSourceArgs { + filterQuery?: Maybe; + + defaultIndex: string[]; + + timerange: TimerangeInput; +} export interface AnomaliesOverTimeSourceArgs { timerange: TimerangeInput; @@ -2438,6 +2455,58 @@ export interface DeleteTimelineMutationArgs { // Documents // ==================================================== +export namespace GetAlertsOverTimeQuery { + export type Variables = { + sourceId: string; + timerange: TimerangeInput; + defaultIndex: string[]; + filterQuery?: Maybe; + inspect: boolean; + }; + + export type Query = { + __typename?: 'Query'; + + source: Source; + }; + + export type Source = { + __typename?: 'Source'; + + id: string; + + AlertsHistogram: AlertsHistogram; + }; + + export type AlertsHistogram = { + __typename?: 'AlertsOverTimeData'; + + alertsOverTimeByModule: AlertsOverTimeByModule[]; + + totalCount: number; + + inspect: Maybe; + }; + + export type AlertsOverTimeByModule = { + __typename?: 'MatrixOverTimeHistogramData'; + + x: number; + + y: number; + + g: string; + }; + + export type Inspect = { + __typename?: 'Inspect'; + + dsl: string[]; + + response: string[]; + }; +} + export namespace GetAnomaliesOverTimeQuery { export type Variables = { sourceId: string; diff --git a/x-pack/legacy/plugins/siem/public/mock/global_state.ts b/x-pack/legacy/plugins/siem/public/mock/global_state.ts index ada34acbc19460..750d5292950beb 100644 --- a/x-pack/legacy/plugins/siem/public/mock/global_state.ts +++ b/x-pack/legacy/plugins/siem/public/mock/global_state.ts @@ -45,6 +45,7 @@ export const mockGlobalState: State = { events: { activePage: 0, limit: 10 }, uncommonProcesses: { activePage: 0, limit: 10 }, anomalies: null, + alerts: { activePage: 0, limit: 10 }, }, }, details: { @@ -59,6 +60,7 @@ export const mockGlobalState: State = { events: { activePage: 0, limit: 10 }, uncommonProcesses: { activePage: 0, limit: 10 }, anomalies: null, + alerts: { activePage: 0, limit: 10 }, }, }, }, @@ -101,6 +103,10 @@ export const mockGlobalState: State = { limit: 10, sort: { direction: Direction.desc }, }, + [networkModel.NetworkTableType.alerts]: { + activePage: 0, + limit: 10, + }, }, }, details: { diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx index a09e21f2d1a352..5774feb46240d4 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/details_tabs.tsx @@ -21,10 +21,12 @@ import { AuthenticationsQueryTabBody, UncommonProcessQueryTabBody, EventsQueryTabBody, + HostAlertsQueryTabBody, } from '../navigation'; const HostDetailsTabs = React.memo( ({ + pageFilters, deleteQuery, filterQuery, from, @@ -93,6 +95,10 @@ const HostDetailsTabs = React.memo( path={`${hostDetailsPagePath}/:tabName(${HostsTableType.events})`} render={() => } /> + } + /> ); } diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx index d8bcc6fe3c294d..e062e65bde4966 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/index.tsx @@ -34,7 +34,7 @@ import { inputsSelectors, State } from '../../../store'; import { setHostDetailsTablesActivePageToZero as dispatchHostDetailsTablesActivePageToZero } from '../../../store/hosts/actions'; import { setAbsoluteRangeDatePicker as dispatchAbsoluteRangeDatePicker } from '../../../store/inputs/actions'; import { SpyRoute } from '../../../utils/route/spy_routes'; -import { esQuery } from '../../../../../../../../src/plugins/data/public'; +import { esQuery, esFilters } from '../../../../../../../../src/plugins/data/public'; import { HostsEmptyPage } from '../hosts_empty_page'; import { HostDetailsTabs } from './details_tabs'; @@ -64,6 +64,30 @@ const HostDetailsComponent = React.memo( }, [setHostDetailsTablesActivePageToZero, detailName]); const capabilities = useContext(MlCapabilitiesContext); const core = useKibanaCore(); + const hostDetailsPageFilters: esFilters.Filter[] = [ + { + meta: { + alias: null, + negate: false, + disabled: false, + type: 'phrase', + key: 'host.name', + value: detailName, + params: { + query: detailName, + }, + }, + query: { + match: { + 'host.name': { + query: detailName, + type: 'phrase', + }, + }, + }, + }, + ]; + const getFilters = () => [...hostDetailsPageFilters, ...filters]; const narrowDateRange = useCallback( (min: number, max: number) => { setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); @@ -79,32 +103,8 @@ const HostDetailsComponent = React.memo( config: esQuery.getEsQueryConfig(core.uiSettings), indexPattern, queries: [query], - filters: [ - { - meta: { - alias: null, - negate: false, - disabled: false, - type: 'phrase', - key: 'host.name', - value: detailName, - params: { - query: detailName, - }, - }, - query: { - match: { - 'host.name': { - query: detailName, - type: 'phrase', - }, - }, - }, - }, - ...filters, - ], + filters: getFilters(), }); - return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( @@ -198,6 +198,7 @@ const HostDetailsComponent = React.memo( ; export type HostDetailsTabsProps = HostBodyComponentDispatchProps & HostsQueryProps & { + pageFilters?: esFilters.Filter[]; + filterQuery: string; indexPattern: IIndexPattern; type: hostsModel.HostsType; - filterQuery: string; }; export type SetAbsoluteRangeDatePicker = ActionCreator<{ diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts index 7483636cfe03df..52e016502940b1 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/details/utils.ts @@ -6,30 +6,33 @@ import { Breadcrumb } from 'ui/chrome'; +import { get } from 'lodash/fp'; import { hostsModel } from '../../../store'; import { HostsTableType } from '../../../store/hosts/model'; import { getHostsUrl, getHostDetailsUrl } from '../../../components/link_to/redirect_to_hosts'; import * as i18n from '../translations'; -import { RouteSpyState } from '../../../utils/route/types'; +import { HostRouteSpyState } from '../../../utils/route/types'; export const type = hostsModel.HostsType.details; -const TabNameMappedToI18nKey = { +const TabNameMappedToI18nKey: Record = { [HostsTableType.hosts]: i18n.NAVIGATION_ALL_HOSTS_TITLE, [HostsTableType.authentications]: i18n.NAVIGATION_AUTHENTICATIONS_TITLE, [HostsTableType.uncommonProcesses]: i18n.NAVIGATION_UNCOMMON_PROCESSES_TITLE, [HostsTableType.anomalies]: i18n.NAVIGATION_ANOMALIES_TITLE, [HostsTableType.events]: i18n.NAVIGATION_EVENTS_TITLE, + [HostsTableType.alerts]: i18n.NAVIGATION_ALERTS_TITLE, }; -export const getBreadcrumbs = (params: RouteSpyState, search: string[]): Breadcrumb[] => { +export const getBreadcrumbs = (params: HostRouteSpyState, search: string[]): Breadcrumb[] => { let breadcrumb = [ { text: i18n.PAGE_TITLE, href: `${getHostsUrl()}${search && search[0] ? search[0] : ''}`, }, ]; + if (params.detailName != null) { breadcrumb = [ ...breadcrumb, @@ -40,10 +43,13 @@ export const getBreadcrumbs = (params: RouteSpyState, search: string[]): Breadcr ]; } if (params.tabName != null) { + const tabName = get('tabName', params); + if (!tabName) return breadcrumb; + breadcrumb = [ ...breadcrumb, { - text: TabNameMappedToI18nKey[params.tabName], + text: TabNameMappedToI18nKey[tabName], href: '', }, ]; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx index 0c058f25854c01..6d217a9301884b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -10,6 +10,7 @@ import { connect } from 'react-redux'; import { StickyContainer } from 'react-sticky'; import { compose } from 'redux'; +import { useParams } from 'react-router-dom'; import { FiltersGlobal } from '../../components/filters_global'; import { HeaderPage } from '../../components/header_page'; import { LastEventTime } from '../../components/last_event_time'; @@ -35,6 +36,8 @@ import { HostsTabs } from './hosts_tabs'; import { navTabsHosts } from './nav_tabs'; import * as i18n from './translations'; import { HostsComponentProps, HostsComponentReduxProps } from './types'; +import { filterAlertsHosts } from './navigation'; +import { HostsTableType } from '../../store/hosts/model'; const KpiHostsComponentManage = manageQuery(KpiHostsComponent); @@ -52,6 +55,14 @@ const HostsComponent = React.memo( }) => { const capabilities = React.useContext(MlCapabilitiesContext); const core = useKibanaCore(); + const { tabName } = useParams(); + + const hostsFilters = React.useMemo(() => { + if (tabName === HostsTableType.alerts) { + return filters.length > 0 ? [...filters, ...filterAlertsHosts] : filterAlertsHosts; + } + return filters; + }, [tabName]); const narrowDateRange = useCallback( (min: number, max: number) => { setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); @@ -67,7 +78,7 @@ const HostsComponent = React.memo( config: esQuery.getEsQueryConfig(core.uiSettings), indexPattern, queries: [query], - filters, + filters: hostsFilters, }); return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx index d6e76deb276bd2..9c13fc4ac386e5 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx @@ -20,6 +20,7 @@ import { UncommonProcessQueryTabBody, EventsQueryTabBody, } from './navigation'; +import { HostAlertsQueryTabBody } from './navigation/alerts_query_tab_body'; const HostsTabs = memo( ({ @@ -80,6 +81,10 @@ const HostsTabs = memo( path={`${hostsPagePath}/:tabName(${HostsTableType.events})`} render={() => } /> + } + /> ); } diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx index c8d450a62cc570..fff5c5218c0039 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/index.tsx @@ -21,14 +21,16 @@ const getHostsTabPath = (pagePath: string) => `${HostsTableType.authentications}|` + `${HostsTableType.uncommonProcesses}|` + `${HostsTableType.anomalies}|` + - `${HostsTableType.events})`; + `${HostsTableType.events}|` + + `${HostsTableType.alerts})`; const getHostDetailsTabPath = (pagePath: string) => `${hostDetailsPagePath}/:tabName(` + `${HostsTableType.authentications}|` + `${HostsTableType.uncommonProcesses}|` + `${HostsTableType.anomalies}|` + - `${HostsTableType.events})`; + `${HostsTableType.events}|` + + `${HostsTableType.alerts})`; type Props = Partial> & { url: string }; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/nav_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/nav_tabs.tsx index 0756efe1f9b6e2..4109feff099e06 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/nav_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/nav_tabs.tsx @@ -49,6 +49,13 @@ export const navTabsHosts = (hasMlUserPermissions: boolean): HostsNavTab => { disabled: false, urlKey: 'host', }, + [HostsTableType.alerts]: { + id: HostsTableType.alerts, + name: i18n.NAVIGATION_ALERTS_TITLE, + href: getTabsOnHostsUrl(HostsTableType.alerts), + disabled: false, + urlKey: 'host', + }, }; return hasMlUserPermissions ? hostsNavTabs : omit([HostsTableType.anomalies], hostsNavTabs); diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/alerts_query_tab_body.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/alerts_query_tab_body.tsx new file mode 100644 index 00000000000000..b893acd4dbb3b9 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/alerts_query_tab_body.tsx @@ -0,0 +1,54 @@ +/* + * 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 React, { useMemo } from 'react'; + +import { esFilters } from '../../../../../../../../src/plugins/data/common/es_query'; +import { AlertsView } from '../../../components/alerts_viewer'; +import { AlertsComponentQueryProps } from './types'; + +export const filterAlertsHosts: esFilters.Filter[] = [ + { + query: { + bool: { + filter: [ + { + bool: { + should: [ + { + exists: { + field: 'host.name', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + meta: { + alias: '', + disabled: false, + key: 'bool', + negate: false, + type: 'custom', + value: + '{"query": {"bool": {"filter": [{"bool": {"should": [{"exists": {"field": "host.name"}}],"minimum_should_match": 1}}]}}}', + }, + }, +]; +export const HostAlertsQueryTabBody = React.memo((alertsProps: AlertsComponentQueryProps) => { + const { pageFilters, ...rest } = alertsProps; + const hostPageFilters = useMemo( + () => (pageFilters != null ? [...filterAlertsHosts, ...pageFilters] : filterAlertsHosts), + [pageFilters] + ); + + return ; +}); + +HostAlertsQueryTabBody.displayName = 'HostAlertsQueryTabBody'; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/index.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/index.ts index f20138f5206205..a93c4dfcbcef4f 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/index.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/index.ts @@ -8,3 +8,4 @@ export * from './authentications_query_tab_body'; export * from './events_query_tab_body'; export * from './hosts_query_tab_body'; export * from './uncommon_process_query_tab_body'; +export * from './alerts_query_tab_body'; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts index cfe7953f16ceeb..107b35edc7f7a9 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/types.ts @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IIndexPattern } from 'src/plugins/data/public'; +import { IIndexPattern } from '../../../../../../../../src/plugins/data/common/'; import { NarrowDateRange } from '../../../components/ml/types'; -import { hostsModel } from '../../../store'; import { ESTermQuery } from '../../../../common/typed_json'; import { InspectQuery, Refetch } from '../../../store/inputs/model'; -import { HostsTableType } from '../../../store/hosts/model'; +import { HostsTableType, HostsType } from '../../../store/hosts/model'; import { NavTab } from '../../../components/navigation/types'; import { UpdateDateRange } from '../../../components/charts/common'; +import { esFilters } from '../../../../../../../../src/plugins/data/common/es_query'; export type KeyHostsNavTabWithoutMlPermission = HostsTableType.hosts & HostsTableType.authentications & @@ -37,8 +37,8 @@ export type SetQuery = ({ refetch: Refetch; }) => void; -interface QueryTabBodyProps { - type: hostsModel.HostsType; +export interface QueryTabBodyProps { + type: HostsType; startDate: number; endDate: number; filterQuery?: string | ESTermQuery; @@ -53,4 +53,9 @@ export type HostsComponentsQueryProps = QueryTabBodyProps & { narrowDateRange?: NarrowDateRange; }; +export type AlertsComponentQueryProps = HostsComponentsQueryProps & { + filterQuery: string; + pageFilters?: esFilters.Filter[]; +}; + export type CommonChildren = (args: HostsComponentsQueryProps) => JSX.Element; diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/translations.ts b/x-pack/legacy/plugins/siem/public/pages/hosts/translations.ts index 1c95cbed71a4a9..87617f6bc5f7fd 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/translations.ts +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/translations.ts @@ -46,6 +46,10 @@ export const NAVIGATION_EVENTS_TITLE = i18n.translate('xpack.siem.hosts.navigati defaultMessage: 'Events', }); +export const NAVIGATION_ALERTS_TITLE = i18n.translate('xpack.siem.hosts.navigation.alertsTitle', { + defaultMessage: 'Alerts', +}); + export const EMPTY_TITLE = i18n.translate('xpack.siem.hosts.emptyTitle', { defaultMessage: 'It looks like you don’t have any indices relevant to hosts in the SIEM application', diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/utils.ts b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/utils.ts index 222bf108b4fadf..c265fb30a24394 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details/utils.ts +++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details/utils.ts @@ -6,30 +6,50 @@ import { Breadcrumb } from 'ui/chrome'; +import { get } from 'lodash/fp'; import { decodeIpv6 } from '../../../lib/helpers'; -import { getNetworkUrl } from '../../../components/link_to/redirect_to_network'; +import { getNetworkUrl, getIPDetailsUrl } from '../../../components/link_to/redirect_to_network'; import { networkModel } from '../../../store/network'; import * as i18n from '../translations'; +import { NetworkRouteType } from '../navigation/types'; +import { NetworkRouteSpyState } from '../../../utils/route/types'; export const type = networkModel.NetworkType.details; +const TabNameMappedToI18nKey: Record = { + [NetworkRouteType.alerts]: i18n.NAVIGATION_ALERTS_TITLE, + [NetworkRouteType.anomalies]: i18n.NAVIGATION_ANOMALIES_TITLE, + [NetworkRouteType.flows]: i18n.NAVIGATION_FLOWS_TITLE, + [NetworkRouteType.dns]: i18n.NAVIGATION_DNS_TITLE, + [NetworkRouteType.http]: i18n.NAVIGATION_HTTP_TITLE, + [NetworkRouteType.tls]: i18n.NAVIGATION_TLS_TITLE, +}; -export const getBreadcrumbs = (ip: string | undefined, search: string[]): Breadcrumb[] => { - const breadcrumbs = [ +export const getBreadcrumbs = (params: NetworkRouteSpyState, search: string[]): Breadcrumb[] => { + let breadcrumb = [ { text: i18n.PAGE_TITLE, href: `${getNetworkUrl()}${search && search[0] ? search[0] : ''}`, }, ]; - - if (ip) { - return [ - ...breadcrumbs, + if (params.detailName != null) { + breadcrumb = [ + ...breadcrumb, { - text: decodeIpv6(ip), - href: '', + text: decodeIpv6(params.detailName), + href: `${getIPDetailsUrl(params.detailName)}${search && search[1] ? search[1] : ''}`, }, ]; - } else { - return breadcrumbs; } + + const tabName = get('tabName', params); + if (!tabName) return breadcrumb; + + breadcrumb = [ + ...breadcrumb, + { + text: TabNameMappedToI18nKey[tabName], + href: '', + }, + ]; + return breadcrumb; }; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/alerts_query_tab_body.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/alerts_query_tab_body.tsx new file mode 100644 index 00000000000000..3eeabd3007afa1 --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/alerts_query_tab_body.tsx @@ -0,0 +1,68 @@ +/* + * 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 React from 'react'; + +import { esFilters } from '../../../../../../../../src/plugins/data/common/es_query'; +import { AlertsView } from '../../../components/alerts_viewer'; +import { NetworkComponentQueryProps } from './types'; + +export const filterAlertsNetwork: esFilters.Filter[] = [ + { + query: { + bool: { + filter: [ + { + bool: { + should: [ + { + bool: { + should: [ + { + exists: { + field: 'source.ip', + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + exists: { + field: 'destination.ip', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + meta: { + alias: '', + disabled: false, + key: 'bool', + negate: false, + type: 'custom', + value: + '{"bool":{"filter":[{"bool":{"should":[{"bool":{"should":[{"exists":{"field": "source.ip"}}],"minimum_should_match":1}},{"bool":{"should":[{"exists":{"field": "destination.ip"}}],"minimum_should_match":1}}],"minimum_should_match":1}}]}}', + }, + }, +]; + +export const NetworkAlertsQueryTabBody = React.memo((alertsProps: NetworkComponentQueryProps) => ( + +)); + +NetworkAlertsQueryTabBody.displayName = 'NetworkAlertsQueryTabBody'; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx index fbf137df398729..61f1a5aacb9c0c 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx @@ -47,6 +47,13 @@ export const navTabsNetwork = (hasMlUserPermissions: boolean): NetworkNavTab => disabled: false, urlKey: 'network', }, + [NetworkRouteType.alerts]: { + id: NetworkRouteType.alerts, + name: i18n.NAVIGATION_ALERTS_TITLE, + href: getTabsOnNetworkUrl(NetworkRouteType.alerts), + disabled: false, + urlKey: 'network', + }, }; return hasMlUserPermissions ? networkNavTabs : omit([NetworkRouteType.anomalies], networkNavTabs); diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx index d1c792ade09852..acc5d02299f1fb 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx @@ -21,6 +21,7 @@ import { ConditionalFlexGroup } from './conditional_flex_group'; import { NetworkRoutesProps, NetworkRouteType } from './types'; import { TlsQueryTabBody } from './tls_query_tab_body'; import { Anomaly } from '../../../components/ml/types'; +import { NetworkAlertsQueryTabBody } from './alerts_query_tab_body'; export const NetworkRoutes = ({ networkPagePath, @@ -143,6 +144,10 @@ export const NetworkRoutes = ({ /> )} /> + } + /> ); }; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts b/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts index b8ad8877bf3c1b..b6063a81f31f65 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IIndexPattern } from 'src/plugins/data/public'; +import { IIndexPattern } from '../../../../../../../../src/plugins/data/common/'; import { NavTab } from '../../../components/navigation/types'; import { FlowTargetSourceDest } from '../../../graphql/types'; @@ -52,7 +52,9 @@ export type NetworkRoutesProps = GlobalTimeArgs & { export type KeyNetworkNavTabWithoutMlPermission = NetworkRouteType.dns & NetworkRouteType.flows & - NetworkRouteType.tls; + NetworkRouteType.http & + NetworkRouteType.tls & + NetworkRouteType.alerts; type KeyNetworkNavTabWithMlPermission = KeyNetworkNavTabWithoutMlPermission & NetworkRouteType.anomalies; @@ -67,6 +69,7 @@ export enum NetworkRouteType { anomalies = 'anomalies', tls = 'tls', http = 'http', + alerts = 'alerts', } export type GetNetworkRoutePath = ( diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts b/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts index 059949bf518373..24c2011fd38007 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts +++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts @@ -12,7 +12,7 @@ export const getNetworkRoutePath: GetNetworkRoutePath = ( hasMlUserPermission ) => { if (capabilitiesFetched && !hasMlUserPermission) { - return `${pagePath}/:tabName(${NetworkRouteType.flows}|${NetworkRouteType.dns}|${NetworkRouteType.http}|${NetworkRouteType.tls})`; + return `${pagePath}/:tabName(${NetworkRouteType.flows}|${NetworkRouteType.dns}|${NetworkRouteType.http}|${NetworkRouteType.tls}|${NetworkRouteType.alerts})`; } return ( @@ -21,6 +21,7 @@ export const getNetworkRoutePath: GetNetworkRoutePath = ( `${NetworkRouteType.dns}|` + `${NetworkRouteType.anomalies}|` + `${NetworkRouteType.http}|` + - `${NetworkRouteType.tls})` + `${NetworkRouteType.tls}|` + + `${NetworkRouteType.alerts})` ); }; diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx index 116664fef6ddcc..0d8d3a6753c59f 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx @@ -5,10 +5,12 @@ */ import { EuiSpacer } from '@elastic/eui'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { connect } from 'react-redux'; +import { useParams } from 'react-router-dom'; import { StickyContainer } from 'react-sticky'; +import { esQuery } from '../../../../../../../src/plugins/data/public'; import { EmbeddedMap } from '../../components/embeddables/embedded_map'; import { FiltersGlobal } from '../../components/filters_global'; import { HeaderPage } from '../../components/header_page'; @@ -27,10 +29,11 @@ import { networkModel, State, inputsSelectors } from '../../store'; import { setAbsoluteRangeDatePicker as dispatchSetAbsoluteRangeDatePicker } from '../../store/inputs/actions'; import { SpyRoute } from '../../utils/route/spy_routes'; import { navTabsNetwork, NetworkRoutes, NetworkRoutesLoading } from './navigation'; +import { filterAlertsNetwork } from './navigation/alerts_query_tab_body'; import { NetworkEmptyPage } from './network_empty_page'; import * as i18n from './translations'; import { NetworkComponentProps } from './types'; -import { esQuery } from '../../../../../../../src/plugins/data/public'; +import { NetworkRouteType } from './navigation/types'; const KpiNetworkComponentManage = manageQuery(KpiNetworkComponent); const sourceId = 'default'; @@ -49,6 +52,14 @@ const NetworkComponent = React.memo( capabilitiesFetched, }) => { const core = useKibanaCore(); + const { tabName } = useParams(); + + const networkFilters = useMemo(() => { + if (tabName === NetworkRouteType.alerts) { + return filters.length > 0 ? [...filters, ...filterAlertsNetwork] : filterAlertsNetwork; + } + return filters; + }, [tabName]); const narrowDateRange = useCallback( (min: number, max: number) => { setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); @@ -64,7 +75,7 @@ const NetworkComponent = React.memo( config: esQuery.getEsQueryConfig(core.uiSettings), indexPattern, queries: [query], - filters, + filters: networkFilters, }); return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? ( diff --git a/x-pack/legacy/plugins/siem/public/pages/network/translations.ts b/x-pack/legacy/plugins/siem/public/pages/network/translations.ts index be222bf5f2531f..91c3338ff79030 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/translations.ts +++ b/x-pack/legacy/plugins/siem/public/pages/network/translations.ts @@ -49,3 +49,7 @@ export const NAVIGATION_ANOMALIES_TITLE = i18n.translate( defaultMessage: 'Anomalies', } ); + +export const NAVIGATION_ALERTS_TITLE = i18n.translate('xpack.siem.network.navigation.alertsTitle', { + defaultMessage: 'Alerts', +}); diff --git a/x-pack/legacy/plugins/siem/public/store/hosts/helpers.test.ts b/x-pack/legacy/plugins/siem/public/store/hosts/helpers.test.ts index 8721121295aadb..a4eddb31b3e31e 100644 --- a/x-pack/legacy/plugins/siem/public/store/hosts/helpers.test.ts +++ b/x-pack/legacy/plugins/siem/public/store/hosts/helpers.test.ts @@ -31,6 +31,10 @@ export const mockHostsState: HostsModel = { limit: DEFAULT_TABLE_LIMIT, }, [HostsTableType.anomalies]: null, + [HostsTableType.alerts]: { + activePage: 4, + limit: DEFAULT_TABLE_LIMIT, + }, }, }, details: { @@ -54,6 +58,10 @@ export const mockHostsState: HostsModel = { limit: DEFAULT_TABLE_LIMIT, }, [HostsTableType.anomalies]: null, + [HostsTableType.alerts]: { + activePage: 4, + limit: DEFAULT_TABLE_LIMIT, + }, }, }, }; @@ -81,6 +89,10 @@ describe('Hosts redux store', () => { activePage: 0, limit: 10, }, + alerts: { + activePage: 0, + limit: 10, + }, }); }); @@ -105,6 +117,10 @@ describe('Hosts redux store', () => { activePage: 0, limit: 10, }, + alerts: { + activePage: 0, + limit: 10, + }, }); }); }); diff --git a/x-pack/legacy/plugins/siem/public/store/hosts/helpers.ts b/x-pack/legacy/plugins/siem/public/store/hosts/helpers.ts index 3e32dde465401e..f6b5596b382f63 100644 --- a/x-pack/legacy/plugins/siem/public/store/hosts/helpers.ts +++ b/x-pack/legacy/plugins/siem/public/store/hosts/helpers.ts @@ -26,6 +26,10 @@ export const setHostPageQueriesActivePageToZero = (state: HostsModel): Queries = ...state.page.queries[HostsTableType.uncommonProcesses], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, + [HostsTableType.alerts]: { + ...state.page.queries[HostsTableType.alerts], + activePage: DEFAULT_TABLE_ACTIVE_PAGE, + }, }); export const setHostDetailsQueriesActivePageToZero = (state: HostsModel): Queries => ({ @@ -46,6 +50,10 @@ export const setHostDetailsQueriesActivePageToZero = (state: HostsModel): Querie ...state.details.queries[HostsTableType.uncommonProcesses], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, + [HostsTableType.alerts]: { + ...state.page.queries[HostsTableType.alerts], + activePage: DEFAULT_TABLE_ACTIVE_PAGE, + }, }); export const setHostsQueriesActivePageToZero = (state: HostsModel, type: HostsType): Queries => { diff --git a/x-pack/legacy/plugins/siem/public/store/hosts/model.ts b/x-pack/legacy/plugins/siem/public/store/hosts/model.ts index 8b215372922078..b3764224633b8f 100644 --- a/x-pack/legacy/plugins/siem/public/store/hosts/model.ts +++ b/x-pack/legacy/plugins/siem/public/store/hosts/model.ts @@ -17,6 +17,7 @@ export enum HostsTableType { events = 'events', uncommonProcesses = 'uncommonProcesses', anomalies = 'anomalies', + alerts = 'alerts', } export interface BasicQueryPaginated { @@ -35,6 +36,7 @@ export interface Queries { [HostsTableType.events]: BasicQueryPaginated; [HostsTableType.uncommonProcesses]: BasicQueryPaginated; [HostsTableType.anomalies]: null | undefined; + [HostsTableType.alerts]: BasicQueryPaginated; } export interface GenericHostsModel { diff --git a/x-pack/legacy/plugins/siem/public/store/hosts/reducer.ts b/x-pack/legacy/plugins/siem/public/store/hosts/reducer.ts index 11b0a985c5762e..53fe9a3ea6a2c2 100644 --- a/x-pack/legacy/plugins/siem/public/store/hosts/reducer.ts +++ b/x-pack/legacy/plugins/siem/public/store/hosts/reducer.ts @@ -46,6 +46,10 @@ export const initialHostsState: HostsState = { limit: DEFAULT_TABLE_LIMIT, }, [HostsTableType.anomalies]: null, + [HostsTableType.alerts]: { + activePage: DEFAULT_TABLE_ACTIVE_PAGE, + limit: DEFAULT_TABLE_LIMIT, + }, }, }, details: { @@ -69,6 +73,10 @@ export const initialHostsState: HostsState = { limit: DEFAULT_TABLE_LIMIT, }, [HostsTableType.anomalies]: null, + [HostsTableType.alerts]: { + activePage: DEFAULT_TABLE_ACTIVE_PAGE, + limit: DEFAULT_TABLE_LIMIT, + }, }, }, }; diff --git a/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts b/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts index 8ebeae4bba392b..e50968db31f604 100644 --- a/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts +++ b/x-pack/legacy/plugins/siem/public/store/hosts/selectors.ts @@ -24,3 +24,6 @@ export const eventsSelector = () => createSelector(selectHosts, hosts => hosts.q export const uncommonProcessesSelector = () => createSelector(selectHosts, hosts => hosts.queries.uncommonProcesses); + +export const alertsSelector = () => + createSelector(selectHosts, hosts => hosts.queries[HostsTableType.alerts]); diff --git a/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts b/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts index a15e187b95e605..933c2f05a57ba6 100644 --- a/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts +++ b/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts @@ -73,6 +73,10 @@ export const mockNetworkState: NetworkModel = { limit: DEFAULT_TABLE_LIMIT, sort: { direction: Direction.desc }, }, + [NetworkTableType.alerts]: { + activePage: 0, + limit: DEFAULT_TABLE_LIMIT, + }, }, }, details: { @@ -186,6 +190,10 @@ describe('Network redux store', () => { field: 'bytes_out', }, }, + [NetworkTableType.alerts]: { + activePage: 0, + limit: 10, + }, }); }); diff --git a/x-pack/legacy/plugins/siem/public/store/network/model.ts b/x-pack/legacy/plugins/siem/public/store/network/model.ts index 45c49d65988811..4ddfb84024970e 100644 --- a/x-pack/legacy/plugins/siem/public/store/network/model.ts +++ b/x-pack/legacy/plugins/siem/public/store/network/model.ts @@ -19,6 +19,7 @@ export enum NetworkType { } export enum NetworkTableType { + alerts = 'alerts', dns = 'dns', http = 'http', topCountriesDestination = 'topCountriesDestination', @@ -103,6 +104,7 @@ export interface NetworkQueries { [NetworkTableType.topNFlowDestination]: TopNFlowQuery; [NetworkTableType.topNFlowSource]: TopNFlowQuery; [NetworkTableType.tls]: TlsQuery; + [NetworkTableType.alerts]: BasicQueryPaginated; } export interface NetworkPageModel { diff --git a/x-pack/legacy/plugins/siem/public/store/network/reducer.ts b/x-pack/legacy/plugins/siem/public/store/network/reducer.ts index 373bedb63c3e79..8e4d4555d3bd91 100644 --- a/x-pack/legacy/plugins/siem/public/store/network/reducer.ts +++ b/x-pack/legacy/plugins/siem/public/store/network/reducer.ts @@ -89,6 +89,10 @@ export const initialNetworkState: NetworkState = { direction: Direction.desc, }, }, + [NetworkTableType.alerts]: { + activePage: DEFAULT_TABLE_ACTIVE_PAGE, + limit: DEFAULT_TABLE_LIMIT, + }, }, }, details: { diff --git a/x-pack/legacy/plugins/siem/public/utils/route/types.ts b/x-pack/legacy/plugins/siem/public/utils/route/types.ts index 62f6b67df245fb..002cd4d23786d2 100644 --- a/x-pack/legacy/plugins/siem/public/utils/route/types.ts +++ b/x-pack/legacy/plugins/siem/public/utils/route/types.ts @@ -9,16 +9,26 @@ import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { HostsTableType } from '../../store/hosts/model'; +import { NetworkRouteType } from '../../pages/network/navigation/types'; +export type SiemRouteType = HostsTableType | NetworkRouteType; export interface RouteSpyState { pageName: string; detailName: string | undefined; - tabName: HostsTableType | undefined; + tabName: SiemRouteType | undefined; search: string; pathName: string; history?: H.History; } +export interface HostRouteSpyState extends RouteSpyState { + tabName: HostsTableType | undefined; +} + +export interface NetworkRouteSpyState extends RouteSpyState { + tabName: NetworkRouteType | undefined; +} + export type RouteSpyAction = | { type: 'updateSearch'; diff --git a/x-pack/legacy/plugins/siem/server/graphql/alerts/index.ts b/x-pack/legacy/plugins/siem/server/graphql/alerts/index.ts new file mode 100644 index 00000000000000..f2beae525ed6b7 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/graphql/alerts/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { createAlertsResolvers } from './resolvers'; +export { alertsSchema } from './schema.gql'; diff --git a/x-pack/legacy/plugins/siem/server/graphql/alerts/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/alerts/resolvers.ts new file mode 100644 index 00000000000000..3becaa4d169d91 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/graphql/alerts/resolvers.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 { Alerts } from '../../lib/alerts'; +import { AppResolverOf, ChildResolverOf } from '../../lib/framework'; +import { createOptions } from '../../utils/build_query/create_options'; +import { QuerySourceResolver } from '../sources/resolvers'; +import { SourceResolvers } from '../types'; + +export interface AlertsResolversDeps { + alerts: Alerts; +} + +type QueryAlertsHistogramResolver = ChildResolverOf< + AppResolverOf, + QuerySourceResolver +>; + +export const createAlertsResolvers = ( + libs: AlertsResolversDeps +): { + Source: { + AlertsHistogram: QueryAlertsHistogramResolver; + }; +} => ({ + Source: { + async AlertsHistogram(source, args, { req }, info) { + const options = { + ...createOptions(source, args, info), + defaultIndex: args.defaultIndex, + }; + return libs.alerts.getAlertsHistogramData(req, options); + }, + }, +}); diff --git a/x-pack/legacy/plugins/siem/server/graphql/alerts/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/alerts/schema.gql.ts new file mode 100644 index 00000000000000..f29b64772b8f6b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/graphql/alerts/schema.gql.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import gql from 'graphql-tag'; + +export const alertsSchema = gql` + type AlertsOverTimeData { + inspect: Inspect + alertsOverTimeByModule: [MatrixOverTimeHistogramData!]! + totalCount: Float! + } + + extend type Source { + AlertsHistogram( + filterQuery: String + defaultIndex: [String!]! + timerange: TimerangeInput! + ): AlertsOverTimeData! + } +`; diff --git a/x-pack/legacy/plugins/siem/server/graphql/index.ts b/x-pack/legacy/plugins/siem/server/graphql/index.ts index 4e28605f6c0b21..762b9002a466da 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/index.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/index.ts @@ -29,7 +29,9 @@ import { timelineSchema } from './timeline'; import { tlsSchema } from './tls'; import { uncommonProcessesSchema } from './uncommon_processes'; import { whoAmISchema } from './who_am_i'; +import { alertsSchema } from './alerts'; export const schemas = [ + alertsSchema, anomaliesSchema, authenticationsSchema, ecsSchema, diff --git a/x-pack/legacy/plugins/siem/server/graphql/types.ts b/x-pack/legacy/plugins/siem/server/graphql/types.ts index fda79ad543bf6a..776444b1502b19 100644 --- a/x-pack/legacy/plugins/siem/server/graphql/types.ts +++ b/x-pack/legacy/plugins/siem/server/graphql/types.ts @@ -459,6 +459,8 @@ export interface Source { /** The status of the source */ status: SourceStatus; + AlertsHistogram: AlertsOverTimeData; + AnomaliesOverTime: AnomaliesOverTimeData; /** Gets Authentication success and failures based on a timerange */ Authentications: AuthenticationsData; @@ -560,10 +562,10 @@ export interface IndexField { format?: Maybe; } -export interface AnomaliesOverTimeData { +export interface AlertsOverTimeData { inspect?: Maybe; - anomaliesOverTime: MatrixOverTimeHistogramData[]; + alertsOverTimeByModule: MatrixOverTimeHistogramData[]; totalCount: number; } @@ -582,6 +584,14 @@ export interface MatrixOverTimeHistogramData { g: string; } +export interface AnomaliesOverTimeData { + inspect?: Maybe; + + anomaliesOverTime: MatrixOverTimeHistogramData[]; + + totalCount: number; +} + export interface AuthenticationsData { edges: AuthenticationsEdges[]; @@ -2139,6 +2149,13 @@ export interface GetAllTimelineQueryArgs { onlyUserFavorite?: Maybe; } +export interface AlertsHistogramSourceArgs { + filterQuery?: Maybe; + + defaultIndex: string[]; + + timerange: TimerangeInput; +} export interface AnomaliesOverTimeSourceArgs { timerange: TimerangeInput; @@ -2781,6 +2798,8 @@ export namespace SourceResolvers { /** The status of the source */ status?: StatusResolver; + AlertsHistogram?: AlertsHistogramResolver; + AnomaliesOverTime?: AnomaliesOverTimeResolver; /** Gets Authentication success and failures based on a timerange */ Authentications?: AuthenticationsResolver; @@ -2853,6 +2872,19 @@ export namespace SourceResolvers { Parent, TContext >; + export type AlertsHistogramResolver< + R = AlertsOverTimeData, + Parent = Source, + TContext = SiemContext + > = Resolver; + export interface AlertsHistogramArgs { + filterQuery?: Maybe; + + defaultIndex: string[]; + + timerange: TimerangeInput; + } + export type AnomaliesOverTimeResolver< R = AnomaliesOverTimeData, Parent = Source, @@ -3407,11 +3439,11 @@ export namespace IndexFieldResolvers { > = Resolver; } -export namespace AnomaliesOverTimeDataResolvers { - export interface Resolvers { +export namespace AlertsOverTimeDataResolvers { + export interface Resolvers { inspect?: InspectResolver, TypeParent, TContext>; - anomaliesOverTime?: AnomaliesOverTimeResolver< + alertsOverTimeByModule?: AlertsOverTimeByModuleResolver< MatrixOverTimeHistogramData[], TypeParent, TContext @@ -3422,17 +3454,17 @@ export namespace AnomaliesOverTimeDataResolvers { export type InspectResolver< R = Maybe, - Parent = AnomaliesOverTimeData, + Parent = AlertsOverTimeData, TContext = SiemContext > = Resolver; - export type AnomaliesOverTimeResolver< + export type AlertsOverTimeByModuleResolver< R = MatrixOverTimeHistogramData[], - Parent = AnomaliesOverTimeData, + Parent = AlertsOverTimeData, TContext = SiemContext > = Resolver; export type TotalCountResolver< R = number, - Parent = AnomaliesOverTimeData, + Parent = AlertsOverTimeData, TContext = SiemContext > = Resolver; } @@ -3482,6 +3514,36 @@ export namespace MatrixOverTimeHistogramDataResolvers { > = Resolver; } +export namespace AnomaliesOverTimeDataResolvers { + export interface Resolvers { + inspect?: InspectResolver, TypeParent, TContext>; + + anomaliesOverTime?: AnomaliesOverTimeResolver< + MatrixOverTimeHistogramData[], + TypeParent, + TContext + >; + + totalCount?: TotalCountResolver; + } + + export type InspectResolver< + R = Maybe, + Parent = AnomaliesOverTimeData, + TContext = SiemContext + > = Resolver; + export type AnomaliesOverTimeResolver< + R = MatrixOverTimeHistogramData[], + Parent = AnomaliesOverTimeData, + TContext = SiemContext + > = Resolver; + export type TotalCountResolver< + R = number, + Parent = AnomaliesOverTimeData, + TContext = SiemContext + > = Resolver; +} + export namespace AuthenticationsDataResolvers { export interface Resolvers { edges?: EdgesResolver; @@ -8707,9 +8769,10 @@ export type IResolvers = { SourceFields?: SourceFieldsResolvers.Resolvers; SourceStatus?: SourceStatusResolvers.Resolvers; IndexField?: IndexFieldResolvers.Resolvers; - AnomaliesOverTimeData?: AnomaliesOverTimeDataResolvers.Resolvers; + AlertsOverTimeData?: AlertsOverTimeDataResolvers.Resolvers; Inspect?: InspectResolvers.Resolvers; MatrixOverTimeHistogramData?: MatrixOverTimeHistogramDataResolvers.Resolvers; + AnomaliesOverTimeData?: AnomaliesOverTimeDataResolvers.Resolvers; AuthenticationsData?: AuthenticationsDataResolvers.Resolvers; AuthenticationsEdges?: AuthenticationsEdgesResolvers.Resolvers; AuthenticationItem?: AuthenticationItemResolvers.Resolvers; diff --git a/x-pack/legacy/plugins/siem/server/init_server.ts b/x-pack/legacy/plugins/siem/server/init_server.ts index 08c481164d5394..5ecbb51c6770dd 100644 --- a/x-pack/legacy/plugins/siem/server/init_server.ts +++ b/x-pack/legacy/plugins/siem/server/init_server.ts @@ -29,10 +29,12 @@ import { createUncommonProcessesResolvers } from './graphql/uncommon_processes'; import { createWhoAmIResolvers } from './graphql/who_am_i'; import { AppBackendLibs } from './lib/types'; import { createTlsResolvers } from './graphql/tls'; +import { createAlertsResolvers } from './graphql/alerts'; export const initServer = (libs: AppBackendLibs) => { const schema = makeExecutableSchema({ resolvers: [ + createAlertsResolvers(libs) as IResolvers, createAnomaliesResolvers(libs) as IResolvers, createAuthenticationsResolvers(libs) as IResolvers, createEsValueResolvers() as IResolvers, diff --git a/x-pack/legacy/plugins/siem/server/lib/alerts/elasticsearch_adapter.ts b/x-pack/legacy/plugins/siem/server/lib/alerts/elasticsearch_adapter.ts new file mode 100644 index 00000000000000..6667f34b1b738b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/alerts/elasticsearch_adapter.ts @@ -0,0 +1,63 @@ +/* + * 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 { AlertsOverTimeData, MatrixOverTimeHistogramData } from '../../graphql/types'; + +import { inspectStringifyObject } from '../../utils/build_query'; + +import { FrameworkAdapter, FrameworkRequest, RequestBasicOptions } from '../framework'; +import { buildAlertsHistogramQuery } from './query.dsl'; + +import { AlertsAdapter, AlertsGroupData, AlertsBucket } from './types'; +import { TermAggregation } from '../types'; +import { EventHit } from '../events/types'; + +export class ElasticsearchAlertsAdapter implements AlertsAdapter { + constructor(private readonly framework: FrameworkAdapter) {} + + public async getAlertsHistogramData( + request: FrameworkRequest, + options: RequestBasicOptions + ): Promise { + const dsl = buildAlertsHistogramQuery(options); + const response = await this.framework.callWithRequest( + request, + 'search', + dsl + ); + const totalCount = getOr(0, 'hits.total.value', response); + const alertsOverTimeByModule = getOr([], 'aggregations.alertsByModuleGroup.buckets', response); + const inspect = { + dsl: [inspectStringifyObject(dsl)], + response: [inspectStringifyObject(response)], + }; + return { + inspect, + alertsOverTimeByModule: getAlertsOverTimeByModule(alertsOverTimeByModule), + totalCount, + }; + } +} + +const getAlertsOverTimeByModule = (data: AlertsGroupData[]): MatrixOverTimeHistogramData[] => { + let result: MatrixOverTimeHistogramData[] = []; + data.forEach(({ key: group, alerts }) => { + const alertsData: AlertsBucket[] = get('buckets', alerts); + + result = [ + ...result, + ...alertsData.map(({ key, doc_count }: AlertsBucket) => ({ + x: key, + y: doc_count, + g: group, + })), + ]; + }); + + return result; +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/alerts/elasticseatch_adapter.test.ts b/x-pack/legacy/plugins/siem/server/lib/alerts/elasticseatch_adapter.test.ts new file mode 100644 index 00000000000000..a24fb5f511d246 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/alerts/elasticseatch_adapter.test.ts @@ -0,0 +1,57 @@ +/* + * 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 { FrameworkAdapter, FrameworkRequest, RequestBasicOptions } from '../framework'; + +import expect from '@kbn/expect'; +import { ElasticsearchAlertsAdapter } from './elasticsearch_adapter'; +import { + mockRequest, + mockOptions, + mockAlertsHistogramDataResponse, + mockAlertsHistogramQueryDsl, + mockAlertsHistogramDataFormattedResponse, +} from './mock'; + +jest.mock('./query.dsl', () => { + return { + buildAlertsHistogramQuery: jest.fn(() => mockAlertsHistogramQueryDsl), + }; +}); + +describe('alerts elasticsearch_adapter', () => { + describe('getAlertsHistogramData', () => { + test('Happy Path ', async () => { + const mockCallWithRequest = jest.fn(); + mockCallWithRequest.mockImplementation((req: FrameworkRequest, method: string) => { + return mockAlertsHistogramDataResponse; + }); + const mockFramework: FrameworkAdapter = { + version: 'mock', + callWithRequest: mockCallWithRequest, + registerGraphQLEndpoint: jest.fn(), + getIndexPatternsService: jest.fn(), + }; + jest.doMock('../framework', () => ({ + callWithRequest: mockCallWithRequest, + })); + + const EsNetworkTimelineAlerts = new ElasticsearchAlertsAdapter(mockFramework); + const data = await EsNetworkTimelineAlerts.getAlertsHistogramData( + (mockRequest as unknown) as FrameworkRequest, + (mockOptions as unknown) as RequestBasicOptions + ); + + expect(data).to.eql({ + alertsOverTimeByModule: mockAlertsHistogramDataFormattedResponse, + inspect: { + dsl: ['"mockAlertsHistogramQueryDsl"'], + response: [JSON.stringify(mockAlertsHistogramDataResponse, null, 2)], + }, + totalCount: 1599508, + }); + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/alerts/index.ts b/x-pack/legacy/plugins/siem/server/lib/alerts/index.ts new file mode 100644 index 00000000000000..13a693a6e1fbb2 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/alerts/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 { FrameworkRequest, RequestBasicOptions } from '../framework'; +export * from './elasticsearch_adapter'; +import { AlertsAdapter } from './types'; +import { AlertsOverTimeData } from '../../graphql/types'; + +export class Alerts { + constructor(private readonly adapter: AlertsAdapter) {} + + public async getAlertsHistogramData( + req: FrameworkRequest, + options: RequestBasicOptions + ): Promise { + return this.adapter.getAlertsHistogramData(req, options); + } +} diff --git a/x-pack/legacy/plugins/siem/server/lib/alerts/mock.ts b/x-pack/legacy/plugins/siem/server/lib/alerts/mock.ts new file mode 100644 index 00000000000000..fe0b6673f3191a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/alerts/mock.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { defaultIndexPattern } from '../../../default_index_pattern'; + +export const mockAlertsHistogramDataResponse = { + took: 513, + timed_out: false, + _shards: { + total: 62, + successful: 61, + skipped: 0, + failed: 1, + failures: [ + { + shard: 0, + index: 'auditbeat-7.2.0', + node: 'jBC5kcOeT1exvECDMrk5Ug', + reason: { + type: 'illegal_argument_exception', + reason: + 'Fielddata is disabled on text fields by default. Set fielddata=true on [event.module] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.', + }, + }, + ], + }, + hits: { + total: { + value: 1599508, + relation: 'eq', + }, + max_score: null, + hits: [], + }, + aggregations: { + alertsByModuleGroup: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 802087, + buckets: [ + { + key: 'All others', + doc_count: 451519, + alerts: { + buckets: [ + { + key_as_string: '2019-12-15T09:30:00.000Z', + key: 1576402200000, + doc_count: 3008, + }, + { + key_as_string: '2019-12-15T10:00:00.000Z', + key: 1576404000000, + doc_count: 8671, + }, + ], + }, + }, + { + key: 'suricata', + doc_count: 345902, + alerts: { + buckets: [ + { + key_as_string: '2019-12-15T09:30:00.000Z', + key: 1576402200000, + doc_count: 1785, + }, + { + key_as_string: '2019-12-15T10:00:00.000Z', + key: 1576404000000, + doc_count: 5342, + }, + ], + }, + }, + ], + }, + }, +}; +export const mockAlertsHistogramDataFormattedResponse = [ + { + x: 1576402200000, + y: 3008, + g: 'All others', + }, + { + x: 1576404000000, + y: 8671, + g: 'All others', + }, + { + x: 1576402200000, + y: 1785, + g: 'suricata', + }, + { + x: 1576404000000, + y: 5342, + g: 'suricata', + }, +]; +export const mockAlertsHistogramQueryDsl = 'mockAlertsHistogramQueryDsl'; +export const mockRequest = 'mockRequest'; +export const mockOptions = { + sourceConfiguration: { field: {} }, + timerange: { + to: 9999, + from: 1234, + }, + defaultIndex: defaultIndexPattern, + filterQuery: '', +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/alerts/query.dsl.ts b/x-pack/legacy/plugins/siem/server/lib/alerts/query.dsl.ts new file mode 100644 index 00000000000000..efa6ee01f2124f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/alerts/query.dsl.ts @@ -0,0 +1,118 @@ +/* + * 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 { createQueryFilterClauses, calculateTimeseriesInterval } from '../../utils/build_query'; +import { buildTimelineQuery } from '../events/query.dsl'; +import { RequestOptions, RequestBasicOptions } from '../framework'; + +export const buildAlertsQuery = (options: RequestOptions) => { + const eventsQuery = buildTimelineQuery(options); + const eventsFilter = eventsQuery.body.query.bool.filter; + const alertsFilter = [ + ...createQueryFilterClauses({ match: { 'event.kind': { query: 'alert' } } }), + ]; + + return { + ...eventsQuery, + body: { + ...eventsQuery.body, + query: { + bool: { + filter: [...eventsFilter, ...alertsFilter], + }, + }, + }, + }; +}; + +export const buildAlertsHistogramQuery = ({ + filterQuery, + timerange: { from, to }, + defaultIndex, + sourceConfiguration: { + fields: { timestamp }, + }, +}: RequestBasicOptions) => { + const filter = [ + ...createQueryFilterClauses(filterQuery), + { + bool: { + filter: [ + { + bool: { + should: [ + { + match: { + 'event.kind': 'alert', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + { + range: { + [timestamp]: { + gte: from, + lte: to, + }, + }, + }, + ]; + + const getHistogramAggregation = () => { + const interval = calculateTimeseriesInterval(from, to); + const histogramTimestampField = '@timestamp'; + const dateHistogram = { + date_histogram: { + field: histogramTimestampField, + fixed_interval: `${interval}s`, + }, + }; + const autoDateHistogram = { + auto_date_histogram: { + field: histogramTimestampField, + buckets: 36, + }, + }; + return { + alertsByModuleGroup: { + terms: { + field: 'event.module', + missing: 'All others', + order: { + _count: 'desc', + }, + size: 10, + }, + aggs: { + alerts: interval ? dateHistogram : autoDateHistogram, + }, + }, + }; + }; + + const dslQuery = { + index: defaultIndex, + allowNoIndices: true, + ignoreUnavailable: true, + body: { + aggregations: getHistogramAggregation(), + query: { + bool: { + filter, + }, + }, + size: 0, + track_total_hits: true, + }, + }; + + return dslQuery; +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/alerts/types.ts b/x-pack/legacy/plugins/siem/server/lib/alerts/types.ts new file mode 100644 index 00000000000000..e6a4ff4b7c9d17 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/alerts/types.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. + */ + +import { AlertsOverTimeData } from '../../graphql/types'; +import { FrameworkRequest, RequestBasicOptions } from '../framework'; + +export interface AlertsBucket { + key: number; + doc_count: number; +} + +export interface AlertsGroupData { + key: string; + doc_count: number; + alerts: { + buckets: AlertsBucket[]; + }; +} +export interface AlertsAdapter { + getAlertsHistogramData( + request: FrameworkRequest, + options: RequestBasicOptions + ): Promise; +} diff --git a/x-pack/legacy/plugins/siem/server/lib/compose/kibana.ts b/x-pack/legacy/plugins/siem/server/lib/compose/kibana.ts index 9d5ac6db7bbb79..2e4dfbc31b65bc 100644 --- a/x-pack/legacy/plugins/siem/server/lib/compose/kibana.ts +++ b/x-pack/legacy/plugins/siem/server/lib/compose/kibana.ts @@ -31,6 +31,7 @@ import { ElasticsearchUncommonProcessesAdapter, UncommonProcesses } from '../unc import { Note } from '../note/saved_object'; import { PinnedEvent } from '../pinned_event/saved_object'; import { Timeline } from '../timeline/saved_object'; +import { Alerts, ElasticsearchAlertsAdapter } from '../alerts'; export function compose(core: CoreSetup, env: PluginInitializerContext['env']): AppBackendLibs { const framework = new KibanaBackendFrameworkAdapter(core, env); @@ -42,6 +43,7 @@ export function compose(core: CoreSetup, env: PluginInitializerContext['env']): const pinnedEvent = new PinnedEvent(); const domainLibs: AppDomainLibs = { + alerts: new Alerts(new ElasticsearchAlertsAdapter(framework)), anomalies: new Anomalies(new ElasticsearchAnomaliesAdapter(framework)), authentications: new Authentications(new ElasticsearchAuthenticationAdapter(framework)), events: new Events(new ElasticsearchEventsAdapter(framework)), diff --git a/x-pack/legacy/plugins/siem/server/lib/events/elasticsearch_adapter.ts b/x-pack/legacy/plugins/siem/server/lib/events/elasticsearch_adapter.ts index 6dbb75d28149b3..dfa81122f9c23e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/events/elasticsearch_adapter.ts +++ b/x-pack/legacy/plugins/siem/server/lib/events/elasticsearch_adapter.ts @@ -61,7 +61,6 @@ export class ElasticsearchEventsAdapter implements EventsAdapter { ...reduceFields(queryOptions.fields, eventFieldsMap), ]); delete queryOptions.fieldRequested; - const dsl = buildTimelineQuery(queryOptions); const response = await this.framework.callWithRequest( request, diff --git a/x-pack/legacy/plugins/siem/server/lib/types.ts b/x-pack/legacy/plugins/siem/server/lib/types.ts index 9e4e477aa78d21..9034ab4e6af83d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/types.ts @@ -23,10 +23,12 @@ import { Note } from './note/saved_object'; import { PinnedEvent } from './pinned_event/saved_object'; import { Timeline } from './timeline/saved_object'; import { TLS } from './tls'; +import { Alerts } from './alerts'; export * from './hosts'; export interface AppDomainLibs { + alerts: Alerts; anomalies: Anomalies; authentications: Authentications; events: Events; From 3ab4b7f2fd7fbefaa35dd7e66e5d45063d19b748 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 18 Dec 2019 07:38:59 -0800 Subject: [PATCH 59/60] [ML] Keep rule editor flyout open on refresh (#53458) * [ML] prevent AnomaliesTable re-render * [ML] 50935 update titles to sentence case * [ML] update snapshots --- .../rule_editor_flyout.test.js.snap | 8 +++---- .../rule_editor/rule_editor_flyout.js | 6 ++--- .../rule_action_panel.test.js.snap | 24 ++++++++++++++----- .../select_rule_action/rule_action_panel.js | 9 +++++-- .../select_rule_action/select_rule_action.js | 2 +- .../timeseriesexplorer/timeseriesexplorer.js | 8 +++---- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/__snapshots__/rule_editor_flyout.test.js.snap b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/__snapshots__/rule_editor_flyout.test.js.snap index 11dca03c938a2b..4486899efb0018 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/__snapshots__/rule_editor_flyout.test.js.snap +++ b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/__snapshots__/rule_editor_flyout.test.js.snap @@ -26,7 +26,7 @@ exports[`RuleEditorFlyout renders the flyout after adding a condition to a rule id="flyoutTitle" > @@ -276,7 +276,7 @@ exports[`RuleEditorFlyout renders the flyout after setting the rule to edit 1`] id="flyoutTitle" > @@ -540,7 +540,7 @@ exports[`RuleEditorFlyout renders the flyout for creating a rule with conditions id="flyoutTitle" > @@ -782,7 +782,7 @@ exports[`RuleEditorFlyout renders the select action component for a detector wit id="flyoutTitle" > diff --git a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.js b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.js index 032bb92418c12b..232419cc7dca24 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.js +++ b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.js @@ -510,7 +510,7 @@ export const RuleEditorFlyout = injectI18n(

@@ -569,12 +569,12 @@ export const RuleEditorFlyout = injectI18n( {isCreate === true ? ( ) : ( )} diff --git a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/rule_action_panel.test.js.snap b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/rule_action_panel.test.js.snap index 463d0b5dbed53e..d82f78cbc4e1a1 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/rule_action_panel.test.js.snap +++ b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/__snapshots__/rule_action_panel.test.js.snap @@ -11,7 +11,7 @@ exports[`RuleActionPanel renders panel for rule with a condition 1`] = ` Object { "description": "skip result when actual is less than 1", "title": , @@ -40,7 +40,11 @@ exports[`RuleActionPanel renders panel for rule with a condition 1`] = ` conditionValue={1} updateConditionValue={[Function]} />, - "title": "actions", + "title": , }, Object { "description": , @@ -90,7 +94,11 @@ exports[`RuleActionPanel renders panel for rule with a condition and scope, valu fieldValue="AAL" filterId="eu-airlines" />, - "title": "actions", + "title": , }, Object { "description": , @@ -144,7 +152,11 @@ exports[`RuleActionPanel renders panel for rule with scope, value in filter list values={Object {}} /> , - "title": "actions", + "title": , }, Object { "description": ), description: buildRuleDescription(this.rule, this.props.anomaly), @@ -186,7 +186,12 @@ export class RuleActionPanel extends Component { }); } - descriptionListItems[1].title = 'actions'; + descriptionListItems[1].title = ( + + ); return ( diff --git a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/select_rule_action.js b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/select_rule_action.js index 4d7a8f1b67b74b..309e271ad26a41 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/select_rule_action.js +++ b/x-pack/legacy/plugins/ml/public/application/components/rule_editor/select_rule_action/select_rule_action.js @@ -59,7 +59,7 @@ export function SelectRuleAction({ diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 62bb2de3fcb313..0f9ef2b54fdc23 100644 --- a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -1530,13 +1530,11 @@ export class TimeSeriesExplorer extends React.Component { - )} + {arePartitioningFieldsProvided && jobs.length > 0 && ( + + )} ); } From 13c2ed4e439520d32e070e2ab52b7b8362264056 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Wed, 18 Dec 2019 09:35:04 -0700 Subject: [PATCH 60/60] [Metrics UI] Customize "node info" section per Inventory Model (#53325) --- .../inventory_models/aws_ec2/layout.tsx | 204 +++--- .../inventory_models/aws_rds/layout.tsx | 321 ++++----- .../common/inventory_models/aws_s3/layout.tsx | 247 +++---- .../inventory_models/aws_sqs/layout.tsx | 247 +++---- .../inventory_models/container/layout.tsx | 402 +++++------ .../common/inventory_models/host/layout.tsx | 668 +++++++++--------- .../common/inventory_models/pod/layout.tsx | 267 +++---- .../metrics/components/layout_content.tsx | 12 + ...{node_details.tsx => metadata_details.tsx} | 66 +- .../metrics/components/node_details_page.tsx | 26 +- .../metrics/containers/metadata_context.ts | 9 + 11 files changed, 1281 insertions(+), 1188 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/components/layout_content.tsx rename x-pack/legacy/plugins/infra/public/pages/metrics/components/{node_details.tsx => metadata_details.tsx} (72%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/metrics/containers/metadata_context.ts diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx index 01009b478951a8..a3074b78f9f3b6 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx @@ -8,109 +8,123 @@ import { i18n } from '@kbn/i18n'; import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; import { Section } from '../../../public/pages/metrics/components/section'; import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; import { withTheme } from '../../../../../common/eui_styled_components'; +import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( -
- + +
- - - - - - - - -
+ + + + + + + + + +
+
)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx index 5f1185666a35dc..debb569fcd5bb3 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx @@ -10,171 +10,174 @@ import { Section } from '../../../public/pages/metrics/components/section'; import { SubSection } from '../../../public/pages/metrics/components/sub_section'; import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; import { withTheme } from '../../../../../common/eui_styled_components'; +import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( -
- +
- - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + +
+
)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx index 80089f15b04b2b..955960f5baeda1 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx @@ -10,134 +10,137 @@ import { Section } from '../../../public/pages/metrics/components/section'; import { SubSection } from '../../../public/pages/metrics/components/sub_section'; import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; import { withTheme } from '../../../../../common/eui_styled_components'; +import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( -
- +
- - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + +
+
)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx index 40cb0a64d83cc5..5d460c971ec3bf 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx @@ -10,134 +10,137 @@ import { Section } from '../../../public/pages/metrics/components/section'; import { SubSection } from '../../../public/pages/metrics/components/sub_section'; import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; import { withTheme } from '../../../../../common/eui_styled_components'; +import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( -
- +
- - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + +
+
)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.tsx index 00da70f1d96a5b..e207687cf8643b 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/layout.tsx @@ -11,212 +11,220 @@ import { SubSection } from '../../../public/pages/metrics/components/sub_section import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; import { withTheme } from '../../../../../common/eui_styled_components'; +import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( -
- - - - + +
- - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + +
+
)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.tsx index fee79d8364c422..ca53193e64ca26 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/layout.tsx @@ -5,348 +5,366 @@ */ import React from 'react'; import { i18n } from '@kbn/i18n'; +import { withTheme } from '../../../../../common/eui_styled_components/eui_styled_components'; import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; import { Section } from '../../../public/pages/metrics/components/section'; import { SubSection } from '../../../public/pages/metrics/components/sub_section'; import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; -import { withTheme } from '../../../../../common/eui_styled_components'; import * as Aws from '../shared/layouts/aws'; import * as Ngnix from '../shared/layouts/nginx'; +import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; +import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( -
- - - - + +
- - - + + + + + + + + + + + + + + +
+
- - - - - - - - -
-
- - - - - - - - - - - - - - - -
- - + + + + + + + + + + + + + + + +
+ + +
)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.tsx index 401e25c4defb86..f0c27ccff13b1c 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/layout.tsx @@ -12,143 +12,148 @@ import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauge import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; import { withTheme } from '../../../../../common/eui_styled_components'; import * as Nginx from '../shared/layouts/nginx'; +import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; +import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( -
- - - - + +
- - - - - - - - -
- + + + + + + + + + + + + +
+ +
)); diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/layout_content.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/layout_content.tsx new file mode 100644 index 00000000000000..a2bd9cdc13179b --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/layout_content.tsx @@ -0,0 +1,12 @@ +/* + * 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 { EuiPageContent } from '@elastic/eui'; +import { euiStyled } from '../../../../../../common/eui_styled_components'; + +export const LayoutContent = euiStyled(EuiPageContent)` + position: relative; +`; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/metadata_details.tsx similarity index 72% rename from x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details.tsx rename to x-pack/legacy/plugins/infra/public/pages/metrics/components/metadata_details.tsx index 5329ea992c493d..c43f2d10d71635 100644 --- a/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/metadata_details.tsx @@ -4,16 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, useCallback, useMemo } from 'react'; +import React, { useContext, useState, useCallback, useMemo } from 'react'; import { EuiButtonIcon, EuiFlexGrid, EuiFlexItem, EuiTitle, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import { InfraMetadata } from '../../../../common/http_api'; import euiStyled from '../../../../../../common/eui_styled_components'; - -interface Props { - metadata?: InfraMetadata | null; -} +import { MetadataContext } from '../containers/metadata_context'; interface FieldDef { field: string; @@ -101,7 +98,13 @@ const getValueForField = (metadata: InfraMetadata, { field, isBoolean }: FieldDe return value; }; -export const NodeDetails = ({ metadata }: Props) => { +interface Props { + fields?: string[]; +} + +const NUMBER_OF_COLUMNS = 4; + +export const MetadataDetails = (props: Props) => { const [isOpen, setControlState] = useState(false); const toggleIsOpen = useCallback( @@ -109,38 +112,58 @@ export const NodeDetails = ({ metadata }: Props) => { [isOpen] ); - const fields = useMemo(() => (isOpen ? FIELDS : FIELDS.slice(0, 4)), [isOpen]); + const filteredFields = useMemo(() => { + if (props.fields && props.fields.length) { + return props.fields + .map(field => { + const fieldDef = FIELDS.find(f => f.field === field); + if (fieldDef) { + return fieldDef; + } + }) + .filter(f => f) as FieldDef[]; + } else { + return FIELDS; + } + }, [props.fields]); + const fields = useMemo( + () => (isOpen ? filteredFields : filteredFields.slice(0, NUMBER_OF_COLUMNS)), + [filteredFields, isOpen] + ); + const metadata = useContext(MetadataContext); if (!metadata) { return null; } return ( - - - - - + + {filteredFields.length > NUMBER_OF_COLUMNS ? ( + + + + ) : null} + {fields.map(field => ( -

{getLabelForField(field)}

+
{getLabelForField(field)}
{getValueForField(metadata, field)}
))}
-
+ ); }; -const NodeDetailsContainer = euiStyled.div` +const MetadataContainer = euiStyled.div` border-top: ${props => props.theme.eui.euiBorderWidthThin} solid ${props => props.theme.eui.euiBorderColor}; border-bottom: ${props => props.theme.eui.euiBorderWidthThin} solid ${props => @@ -153,4 +176,5 @@ display: flex; const Controls = euiStyled.div` flex-grow: 0; margin-right: ${props => props.theme.eui.paddingSizes.m}; +min-width: 0px; `; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details_page.tsx b/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details_page.tsx index 933831c6ec87df..2f4eb57cd5161f 100644 --- a/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details_page.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/components/node_details_page.tsx @@ -12,7 +12,6 @@ import { EuiPageHeaderSection, EuiHideFor, EuiTitle, - EuiPageContent, } from '@elastic/eui'; import { InventoryMetric } from '../../../../common/inventory_models/types'; import { useNodeDetails } from '../../../containers/node_details/use_node_details'; @@ -20,13 +19,13 @@ import { InfraNodeType, InfraTimerangeInput } from '../../../graphql/types'; import { MetricsSideNav } from './side_nav'; import { AutoSizer } from '../../../components/auto_sizer'; import { MetricsTimeControls } from './time_controls'; -import { NodeDetails } from './node_details'; import { SideNavContext, NavItem } from '../lib/side_nav_context'; import { PageBody } from './page_body'; import euiStyled from '../../../../../../common/eui_styled_components'; import { MetricsTimeInput } from '../containers/with_metrics_time'; import { InfraMetadata } from '../../../../common/http_api/metadata_api'; import { PageError } from './page_error'; +import { MetadataContext } from '../../../pages/metrics/containers/metadata_context'; interface Props { name: string; @@ -100,14 +99,13 @@ export const NodeDetailsPage = (props: Props) => { - - - + + 0 && props.isAutoReloading ? false : loading} refetch={refetch} @@ -117,8 +115,8 @@ export const NodeDetailsPage = (props: Props) => { isLiveStreaming={props.isAutoReloading} stopLiveStreaming={() => props.setAutoReload(false)} /> - - + + ); @@ -128,10 +126,6 @@ export const NodeDetailsPage = (props: Props) => { ); }; -const EuiPageContentWithRelative = euiStyled(EuiPageContent)` - position: relative; -`; - const MetricsDetailsPageColumn = euiStyled.div` flex: 1 0 0%; display: flex; diff --git a/x-pack/legacy/plugins/infra/public/pages/metrics/containers/metadata_context.ts b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/metadata_context.ts new file mode 100644 index 00000000000000..4ecf7fa15548cb --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/metrics/containers/metadata_context.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. + */ + +import React from 'react'; +import { InfraMetadata } from '../../../../common/http_api'; +export const MetadataContext = React.createContext(null);