diff --git a/dev_docs/tutorials/debugging.mdx b/dev_docs/tutorials/debugging.mdx new file mode 100644 index 00000000000000..c0efd249be0668 --- /dev/null +++ b/dev_docs/tutorials/debugging.mdx @@ -0,0 +1,61 @@ +--- +id: kibDevTutorialDebugging +slug: /kibana-dev-docs/tutorial/debugging +title: Debugging in development +summary: Learn how to debug Kibana while running from source +date: 2021-04-26 +tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'debugging'] +--- + +There are multiple ways to go about debugging Kibana when running from source. + +## Debugging using Chrome DevTools + +You will need to run Node using `--inspect` or `--inspect-brk` in order to enable the inspector. Additional information can be found in the [Node.js docs](https://nodejs.org/en/docs/guides/debugging-getting-started/). + +Once Node is running with the inspector enabled, you can open `chrome://inspect` in your Chrome browser. You should see a remote target for the inspector running. Click "inspect". You can now begin using the debugger. + +Next we will go over how to exactly enable the inspector for different aspects of the codebase. + +### Jest Unit Tests + +You will need to run Jest directly from the Node script: + +`node --inspect-brk scripts/jest [TestPathPattern]` + +### Functional Test Runner + +`node --inspect-brk scripts/functional_test_runner` + +### Development Server + +`node --inspect-brk scripts/kibana` + +## Debugging using logging + +When running Kibana, it's sometimes helpful to enable verbose logging. + +`yarn start --verbose` + +Using verbose logging usually results in much more information than you're interested in. The [logging documentation](https://www.elastic.co/guide/en/kibana/current/logging-settings.html) covers ways to change the log level of certain types. + +In the following example of a configuration stored in `config/kibana.dev.yml` we are logging all Elasticsearch queries and any logs created by the Management plugin. + +``` +logging: + appenders: + console: + type: console + layout: + type: pattern + highlight: true + root: + appenders: [default, console] + level: info + + loggers: + - name: plugins.management + level: debug + - name: elasticsearch.query + level: debug +``` \ No newline at end of file diff --git a/package.json b/package.json index 8f56d80c584ea6..22eedde59c5e7d 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,7 @@ "@elastic/safer-lodash-set": "link:bazel-bin/packages/elastic-safer-lodash-set", "@elastic/search-ui-app-search-connector": "^1.6.0", "@elastic/ui-ace": "0.2.3", + "@emotion/react": "^11.4.0", "@hapi/accept": "^5.0.2", "@hapi/boom": "^9.1.1", "@hapi/cookie": "^11.0.2", @@ -454,6 +455,8 @@ "@elastic/eslint-plugin-eui": "0.0.2", "@elastic/github-checks-reporter": "0.0.20b3", "@elastic/makelogs": "^6.0.0", + "@emotion/babel-preset-css-prop": "^11.2.0", + "@emotion/jest": "^11.3.0", "@istanbuljs/schema": "^0.1.2", "@jest/reporters": "^26.6.2", "@kbn/babel-code-parser": "link:bazel-bin/packages/kbn-babel-code-parser", diff --git a/packages/elastic-eslint-config-kibana/.eslintrc.js b/packages/elastic-eslint-config-kibana/.eslintrc.js index 3220a01184004f..d3cf7cf964a60d 100644 --- a/packages/elastic-eslint-config-kibana/.eslintrc.js +++ b/packages/elastic-eslint-config-kibana/.eslintrc.js @@ -1,3 +1,5 @@ +const { USES_STYLED_COMPONENTS } = require('@kbn/dev-utils'); + module.exports = { extends: [ './javascript.js', @@ -79,7 +81,13 @@ module.exports = { from: 'react-intl', to: '@kbn/i18n/react', disallowedMessage: `import from @kbn/i18n/react instead` - } + }, + { + from: 'styled-components', + to: false, + exclude: USES_STYLED_COMPONENTS, + disallowedMessage: `Prefer using @emotion/react instead. To use styled-components, ensure you plugin is enabled in @kbn/dev-utils/src/babel.ts.` + }, ], ], }, diff --git a/packages/kbn-babel-preset/BUILD.bazel b/packages/kbn-babel-preset/BUILD.bazel index f5ebc153b9e1a0..11eae8bc55ca96 100644 --- a/packages/kbn-babel-preset/BUILD.bazel +++ b/packages/kbn-babel-preset/BUILD.bazel @@ -32,6 +32,7 @@ DEPS = [ "@npm//@babel/preset-env", "@npm//@babel/preset-react", "@npm//@babel/preset-typescript", + "@npm//@emotion/babel-preset-css-prop", "@npm//babel-plugin-add-module-exports", "@npm//babel-plugin-styled-components", "@npm//babel-plugin-transform-react-remove-prop-types", diff --git a/packages/kbn-babel-preset/webpack_preset.js b/packages/kbn-babel-preset/webpack_preset.js index ca7ea40ff0fe1b..186ce87478828c 100644 --- a/packages/kbn-babel-preset/webpack_preset.js +++ b/packages/kbn-babel-preset/webpack_preset.js @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +const { USES_STYLED_COMPONENTS } = require.resolve('@kbn/dev-utils'); + module.exports = () => { return { presets: [ @@ -21,14 +23,6 @@ module.exports = () => { ], require('./common_preset'), ], - plugins: [ - [ - require.resolve('babel-plugin-styled-components'), - { - fileName: false, - }, - ], - ], env: { production: { plugins: [ @@ -42,5 +36,29 @@ module.exports = () => { ], }, }, + overrides: [ + { + include: USES_STYLED_COMPONENTS, + plugins: [ + [ + require.resolve('babel-plugin-styled-components'), + { + fileName: false, + }, + ], + ], + }, + { + exclude: USES_STYLED_COMPONENTS, + presets: [ + [ + require.resolve('@emotion/babel-preset-css-prop'), + { + labelFormat: '[local]', + }, + ], + ], + }, + ], }; }; diff --git a/packages/kbn-crypto/BUILD.bazel b/packages/kbn-crypto/BUILD.bazel index 20793e27de6298..bf1ed3f7789756 100644 --- a/packages/kbn-crypto/BUILD.bazel +++ b/packages/kbn-crypto/BUILD.bazel @@ -38,7 +38,8 @@ TYPES_DEPS = [ "@npm//@types/node", "@npm//@types/node-forge", "@npm//@types/testing-library__jest-dom", - "@npm//resize-observer-polyfill" + "@npm//resize-observer-polyfill", + "@npm//@emotion/react", ] DEPS = SRC_DEPS + TYPES_DEPS diff --git a/packages/kbn-dev-utils/src/babel.ts b/packages/kbn-dev-utils/src/babel.ts index 9daa7d9fe8d7a0..5570055a21d15d 100644 --- a/packages/kbn-dev-utils/src/babel.ts +++ b/packages/kbn-dev-utils/src/babel.ts @@ -46,3 +46,14 @@ export async function transformFileWithBabel(file: File) { file.extname = '.js'; transformedFiles.add(file); } + +/** + * Synchronized regex list of files that use `styled-components`. + * Used by `kbn-babel-preset` and `elastic-eslint-config-kibana`. + */ +export const USES_STYLED_COMPONENTS = [ + /packages[\/\\]kbn-ui-shared-deps[\/\\]/, + /src[\/\\]plugins[\/\\](data|kibana_react)[\/\\]/, + /x-pack[\/\\]plugins[\/\\](apm|beats_management|cases|fleet|infra|lists|observability|osquery|security_solution|timelines|uptime)[\/\\]/, + /x-pack[\/\\]test[\/\\]plugin_functional[\/\\]plugins[\/\\]resolver_test[\/\\]/, +]; diff --git a/packages/kbn-eslint-plugin-eslint/rules/module_migration.js b/packages/kbn-eslint-plugin-eslint/rules/module_migration.js index 87a1bae8eac1af..3175210eccb103 100644 --- a/packages/kbn-eslint-plugin-eslint/rules/module_migration.js +++ b/packages/kbn-eslint-plugin-eslint/rules/module_migration.js @@ -78,6 +78,12 @@ module.exports = { disallowedMessage: { type: 'string', }, + include: { + type: 'array', + }, + exclude: { + type: 'array', + }, }, anyOf: [ { @@ -95,7 +101,22 @@ module.exports = { ], }, create: (context) => { - const mappings = context.options[0]; + const filename = path.relative(KIBANA_ROOT, context.getFilename()); + + const mappings = context.options[0].filter((mapping) => { + // exclude mapping rule if it is explicitly excluded from this file + if (mapping.exclude && mapping.exclude.some((p) => p.test(filename))) { + return false; + } + + // if this mapping rule is only included in specific files, optionally include it + if (mapping.include) { + return mapping.include.some((p) => p.test(filename)); + } + + // include all mapping rules by default + return true; + }); return { ImportDeclaration(node) { diff --git a/packages/kbn-storybook/lib/default_config.ts b/packages/kbn-storybook/lib/default_config.ts index e194c9789daab8..989f707b06fede 100644 --- a/packages/kbn-storybook/lib/default_config.ts +++ b/packages/kbn-storybook/lib/default_config.ts @@ -6,8 +6,11 @@ * Side Public License, v 1. */ +import * as path from 'path'; import { StorybookConfig } from '@storybook/core/types'; +import { REPO_ROOT } from './constants'; +const toPath = (_path: string) => path.join(REPO_ROOT, _path); export const defaultConfig: StorybookConfig = { addons: ['@kbn/storybook/preset', '@storybook/addon-a11y', '@storybook/addon-essentials'], stories: ['../**/*.stories.tsx'], @@ -22,6 +25,21 @@ export const defaultConfig: StorybookConfig = { config.node = { fs: 'empty' }; - return config; + // Remove when @storybook has moved to @emotion v11 + // https://github.com/storybookjs/storybook/issues/13145 + const emotion11CompatibleConfig = { + ...config, + resolve: { + ...config.resolve, + alias: { + ...config.resolve?.alias, + '@emotion/core': toPath('node_modules/@emotion/react'), + '@emotion/styled': toPath('node_modules/@emotion/styled'), + 'emotion-theming': toPath('node_modules/@emotion/react'), + }, + }, + }; + + return emotion11CompatibleConfig; }, }; diff --git a/packages/kbn-storybook/lib/theme_switcher.tsx b/packages/kbn-storybook/lib/theme_switcher.tsx index da62bc7010c4b2..24ddec1fdf51cd 100644 --- a/packages/kbn-storybook/lib/theme_switcher.tsx +++ b/packages/kbn-storybook/lib/theme_switcher.tsx @@ -54,6 +54,7 @@ export function ThemeSwitcher() { closeOnClick tooltip={({ onHide }) => } > + {/* @ts-ignore Remove when @storybook has moved to @emotion v11 */} diff --git a/packages/kbn-telemetry-tools/BUILD.bazel b/packages/kbn-telemetry-tools/BUILD.bazel index d394b0c93d45fb..ef1316cec75a3d 100644 --- a/packages/kbn-telemetry-tools/BUILD.bazel +++ b/packages/kbn-telemetry-tools/BUILD.bazel @@ -47,7 +47,8 @@ TYPES_DEPS = [ "@npm//@types/node", "@npm//@types/normalize-path", "@npm//@types/testing-library__jest-dom", - "@npm//resize-observer-polyfill" + "@npm//resize-observer-polyfill", + "@npm//@emotion/react", ] DEPS = SRC_DEPS + TYPES_DEPS diff --git a/packages/kbn-test/jest-preset.js b/packages/kbn-test/jest-preset.js index c84fe3f7a55b05..abc5cfa8efaa80 100644 --- a/packages/kbn-test/jest-preset.js +++ b/packages/kbn-test/jest-preset.js @@ -66,6 +66,7 @@ module.exports = { snapshotSerializers: [ '/src/plugins/kibana_react/public/util/test_helpers/react_mount_serializer.ts', '/node_modules/enzyme-to-json/serializer', + '/node_modules/@emotion/jest/serializer', ], // The test environment that will be used for testing diff --git a/packages/kbn-test/src/kbn_client/kbn_client_requester.test.ts b/packages/kbn-test/src/kbn_client/kbn_client_requester.test.ts new file mode 100644 index 00000000000000..bb2f923ad1f01f --- /dev/null +++ b/packages/kbn-test/src/kbn_client/kbn_client_requester.test.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { pathWithSpace } from './kbn_client_requester'; + +describe('pathWithSpace()', () => { + it('adds a space to the path', () => { + expect(pathWithSpace('hello')`/foo/bar`).toMatchInlineSnapshot(`"/s/hello/foo/bar"`); + }); + + it('ignores the space when it is empty', () => { + expect(pathWithSpace(undefined)`/foo/bar`).toMatchInlineSnapshot(`"/foo/bar"`); + expect(pathWithSpace('')`/foo/bar`).toMatchInlineSnapshot(`"/foo/bar"`); + }); + + it('ignores the space when it is the default space', () => { + expect(pathWithSpace('default')`/foo/bar`).toMatchInlineSnapshot(`"/foo/bar"`); + }); + + it('uriencodes variables in the path', () => { + expect(pathWithSpace('space')`hello/${'funky/username🏴‍☠️'}`).toMatchInlineSnapshot( + `"/s/space/hello/funky%2Fusername%F0%9F%8F%B4%E2%80%8D%E2%98%A0%EF%B8%8F"` + ); + }); + + it('ensures the path always starts with a slash', () => { + expect(pathWithSpace('foo')`hello/world`).toMatchInlineSnapshot(`"/s/foo/hello/world"`); + expect(pathWithSpace()`hello/world`).toMatchInlineSnapshot(`"/hello/world"`); + }); +}); diff --git a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts index a194b593b3863a..c2e4247df1ab0f 100644 --- a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts +++ b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts @@ -23,6 +23,19 @@ const isIgnorableError = (error: any, ignorableErrors: number[] = []) => { return isAxiosResponseError(error) && ignorableErrors.includes(error.response.status); }; +/** + * Creates a template literal tag which will uriencode the variables in a template literal + * as well as prefix the path with a specific space if one is defined + */ +export const pathWithSpace = (space?: string) => { + const prefix = !space || space === 'default' ? '' : uriencode`/s/${space}`; + + return (strings: TemplateStringsArray, ...args: Array) => { + const path = uriencode(strings, ...args); + return path.startsWith('/') || path === '' ? `${prefix}${path}` : `${prefix}/${path}`; + }; +}; + export const uriencode = ( strings: TemplateStringsArray, ...values: Array diff --git a/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts b/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts index 78155098ef0388..7ea685667d48bf 100644 --- a/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts +++ b/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts @@ -8,7 +8,7 @@ import { ToolingLog } from '@kbn/dev-utils'; -import { KbnClientRequester, uriencode } from './kbn_client_requester'; +import { KbnClientRequester, pathWithSpace } from './kbn_client_requester'; export type UiSettingValues = Record; interface UiSettingsApiResponse { @@ -27,8 +27,8 @@ export class KbnClientUiSettings { private readonly defaults?: UiSettingValues ) {} - async get(setting: string) { - const all = await this.getAll(); + async get(setting: string, { space }: { space?: string } = {}) { + const all = await this.getAll({ space }); const value = all[setting]?.userValue; this.log.verbose('uiSettings.value: %j', value); @@ -45,9 +45,9 @@ export class KbnClientUiSettings { /** * Unset a uiSetting */ - async unset(setting: string) { + async unset(setting: string, { space }: { space?: string } = {}) { const { data } = await this.requester.request({ - path: uriencode`/api/kibana/settings/${setting}`, + path: pathWithSpace(space)`/api/kibana/settings/${setting}`, method: 'DELETE', }); return data; @@ -57,7 +57,10 @@ export class KbnClientUiSettings { * Replace all uiSettings with the `doc` values, `doc` is merged * with some defaults */ - async replace(doc: UiSettingValues, { retries = 5 }: { retries?: number } = {}) { + async replace( + doc: UiSettingValues, + { retries = 5, space }: { retries?: number; space?: string } = {} + ) { this.log.debug('replacing kibana config doc: %j', doc); const changes: Record = { @@ -73,7 +76,7 @@ export class KbnClientUiSettings { await this.requester.request({ method: 'POST', - path: '/api/kibana/settings', + path: pathWithSpace(space)`/api/kibana/settings`, body: { changes }, retries, }); @@ -82,11 +85,11 @@ export class KbnClientUiSettings { /** * Add fields to the config doc (like setting timezone and defaultIndex) */ - async update(updates: UiSettingValues) { + async update(updates: UiSettingValues, { space }: { space?: string } = {}) { this.log.debug('applying update to kibana config: %j', updates); await this.requester.request({ - path: '/api/kibana/settings', + path: pathWithSpace(space)`/api/kibana/settings`, method: 'POST', body: { changes: updates, @@ -95,9 +98,9 @@ export class KbnClientUiSettings { }); } - private async getAll() { + private async getAll({ space }: { space?: string } = {}) { const { data } = await this.requester.request({ - path: '/api/kibana/settings', + path: pathWithSpace(space)`/api/kibana/settings`, method: 'GET', }); diff --git a/packages/kbn-ui-shared-deps/BUILD.bazel b/packages/kbn-ui-shared-deps/BUILD.bazel index 9096905a2586be..f92049292f373f 100644 --- a/packages/kbn-ui-shared-deps/BUILD.bazel +++ b/packages/kbn-ui-shared-deps/BUILD.bazel @@ -40,6 +40,7 @@ SRC_DEPS = [ "@npm//@elastic/charts", "@npm//@elastic/eui", "@npm//@elastic/numeral", + "@npm//@emotion/react", "@npm//abortcontroller-polyfill", "@npm//angular", "@npm//babel-loader", diff --git a/packages/kbn-ui-shared-deps/src/entry.js b/packages/kbn-ui-shared-deps/src/entry.js index 0e91c45ae6392a..20e26ca6a28642 100644 --- a/packages/kbn-ui-shared-deps/src/entry.js +++ b/packages/kbn-ui-shared-deps/src/entry.js @@ -18,6 +18,7 @@ export const KbnI18n = require('@kbn/i18n'); export const KbnI18nAngular = require('@kbn/i18n/angular'); export const KbnI18nReact = require('@kbn/i18n/react'); export const Angular = require('angular'); +export const EmotionReact = require('@emotion/react'); export const Moment = require('moment'); export const MomentTimezone = require('moment-timezone/moment-timezone'); export const KbnMonaco = require('@kbn/monaco'); diff --git a/packages/kbn-ui-shared-deps/src/index.js b/packages/kbn-ui-shared-deps/src/index.js index 36c2e6b02879ee..291c7c471d27ce 100644 --- a/packages/kbn-ui-shared-deps/src/index.js +++ b/packages/kbn-ui-shared-deps/src/index.js @@ -57,6 +57,7 @@ exports.externals = { '@kbn/i18n': '__kbnSharedDeps__.KbnI18n', '@kbn/i18n/angular': '__kbnSharedDeps__.KbnI18nAngular', '@kbn/i18n/react': '__kbnSharedDeps__.KbnI18nReact', + '@emotion/react': '__kbnSharedDeps__.EmotionReact', jquery: '__kbnSharedDeps__.Jquery', moment: '__kbnSharedDeps__.Moment', 'moment-timezone': '__kbnSharedDeps__.MomentTimezone', diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index 82353a96dc33c6..6e33e39b148c4f 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -746,9 +746,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` onResize={[Function]} >
-
+
@@ -1021,9 +1019,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` onResize={[Function]} >
-
+
@@ -1315,9 +1311,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` onResize={[Function]} >
-
+
@@ -1570,9 +1564,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` onResize={[Function]} >
-
+
@@ -1786,9 +1778,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` onResize={[Function]} >
-
+
diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 66d81d058fc77e..b8af7c12d57fcc 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -17,7 +17,6 @@ import { CoreSetup } from 'src/core/public'; import { CoreSetup as CoreSetup_2 } from 'kibana/public'; import { CoreStart } from 'kibana/public'; import { CoreStart as CoreStart_2 } from 'src/core/public'; -import * as CSS from 'csstype'; import { Datatable as Datatable_2 } from 'src/plugins/expressions'; import { Datatable as Datatable_3 } from 'src/plugins/expressions/common'; import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions'; @@ -72,13 +71,12 @@ import { Plugin } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_3 } from 'kibana/public'; import { PopoverAnchorPosition } from '@elastic/eui'; -import * as PropTypes from 'prop-types'; import { PublicContract } from '@kbn/utility-types'; import { PublicMethodsOf } from '@kbn/utility-types'; import { PublicUiSettingsParams } from 'src/core/server/types'; import { RangeFilter as RangeFilter_2 } from 'src/plugins/data/public'; import React from 'react'; -import * as React_3 from 'react'; +import * as React_2 from 'react'; import { RecursiveReadonly } from '@kbn/utility-types'; import { Request as Request_2 } from '@hapi/hapi'; import { RequestAdapter } from 'src/plugins/inspector/common'; diff --git a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap index 0ab3f8a4e34668..1e7b59d8a9e766 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap +++ b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap @@ -1169,7 +1169,6 @@ exports[`Inspector Data View component should render single table without select > { - // Warning: (ae-forgotten-export) The symbol "React" needs to be exported by the entry point index.d.ts - constructor(getFactory: EmbeddableStart_2['getEmbeddableFactory'], getAllFactories: EmbeddableStart_2['getEmbeddableFactories'], overlays: OverlayStart_2, notifications: NotificationsStart_2, SavedObjectFinder: React_2.ComponentType, reportUiCounter?: ((appName: string, type: import("@kbn/analytics").UiCounterMetricType, eventNames: string | string[], count?: number | undefined) => void) | undefined); + constructor(getFactory: EmbeddableStart_2['getEmbeddableFactory'], getAllFactories: EmbeddableStart_2['getEmbeddableFactories'], overlays: OverlayStart_2, notifications: NotificationsStart_2, SavedObjectFinder: React.ComponentType, reportUiCounter?: ((appName: string, type: import("@kbn/analytics").UiCounterMetricType, eventNames: string | string[], count?: number | undefined) => void) | undefined); // (undocumented) execute(context: ActionExecutionContext_2): Promise; // (undocumented) diff --git a/test/functional/apps/discover/_field_data.ts b/test/functional/apps/discover/_field_data.ts index 5ab6495686726c..ec9f9cf65e0fa8 100644 --- a/test/functional/apps/discover/_field_data.ts +++ b/test/functional/apps/discover/_field_data.ts @@ -33,8 +33,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await PageObjects.common.navigateToApp('discover'); }); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/104466 - describe.skip('field data', function () { + + describe('field data', function () { it('search php should show the correct hit count', async function () { const expectedHitCount = '445'; await retry.try(async function () { diff --git a/test/functional/apps/discover/index.ts b/test/functional/apps/discover/index.ts index b396f172f69612..a17bf53e7f4781 100644 --- a/test/functional/apps/discover/index.ts +++ b/test/functional/apps/discover/index.ts @@ -12,7 +12,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const browser = getService('browser'); - describe('discover app', function () { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/104466 + describe.skip('discover app', function () { this.tags('ciGroup6'); before(function () { diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json index b704274a58aa42..e92dc717ae25ed 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json @@ -6,7 +6,8 @@ "types": [ "node", "jest", - "react" + "react", + "@emotion/react/types/css-prop" ] }, "include": [ diff --git a/test/tsconfig.json b/test/tsconfig.json index 8cf33d93a40674..dccbe8d715c513 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -6,7 +6,7 @@ "emitDeclarationOnly": true, "declaration": true, "declarationMap": true, - "types": ["node", "resize-observer-polyfill"] + "types": ["node", "resize-observer-polyfill", "@emotion/react/types/css-prop"] }, "include": [ "**/*", diff --git a/tsconfig.base.json b/tsconfig.base.json index cc8b66848a394c..0c8fec7c88cda8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -12,7 +12,10 @@ // Allows for importing from `kibana` package for the exported types. "kibana": ["./kibana"], "kibana/public": ["src/core/public"], - "kibana/server": ["src/core/server"] + "kibana/server": ["src/core/server"], + "@emotion/core": [ + "typings/@emotion" + ], }, // Support .tsx files and transform JSX into calls to React.createElement "jsx": "react", @@ -62,7 +65,8 @@ "flot", "jest-styled-components", "@testing-library/jest-dom", - "resize-observer-polyfill" + "resize-observer-polyfill", + "@emotion/react/types/css-prop" ] } } diff --git a/typings/@emotion/index.d.ts b/typings/@emotion/index.d.ts new file mode 100644 index 00000000000000..2a5e63a3e29ef6 --- /dev/null +++ b/typings/@emotion/index.d.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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// Stub @emotion/core +// Remove when @storybook has moved to @emotion v11 +// https://github.com/storybookjs/storybook/issues/13145 +export {}; diff --git a/x-pack/plugins/apm/server/index.test.ts b/x-pack/plugins/apm/server/index.test.ts index 6052ec921f9f9c..56c9825db5a5cd 100644 --- a/x-pack/plugins/apm/server/index.test.ts +++ b/x-pack/plugins/apm/server/index.test.ts @@ -30,7 +30,7 @@ describe('mergeConfigs', () => { expect(mergeConfigs(apmOssConfig, apmConfig)).toEqual({ 'apm_oss.errorIndices': 'logs-apm*,apm-*-error-*', - 'apm_oss.indexPattern': 'apm-*', + 'apm_oss.indexPattern': 'traces-apm*,logs-apm*,metrics-apm*,apm-*', 'apm_oss.metricsIndices': 'metrics-apm*,apm-*-metric-*', 'apm_oss.spanIndices': 'traces-apm*,apm-*-span-*', 'apm_oss.transactionIndices': 'traces-apm*,apm-*-transaction-*', diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index f14894a76edb45..9031f454f4a7fb 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -74,7 +74,7 @@ export function mergeConfigs( 'apm_oss.metricsIndices': apmOssConfig.metricsIndices, 'apm_oss.sourcemapIndices': apmOssConfig.sourcemapIndices, 'apm_oss.onboardingIndices': apmOssConfig.onboardingIndices, - 'apm_oss.indexPattern': apmOssConfig.indexPattern, // TODO: add data stream indices: traces-apm*,logs-apm*,metrics-apm*. Blocked by https://github.com/elastic/kibana/issues/87851 + 'apm_oss.indexPattern': apmOssConfig.indexPattern, /* eslint-enable @typescript-eslint/naming-convention */ 'xpack.apm.serviceMapEnabled': apmConfig.serviceMapEnabled, 'xpack.apm.serviceMapFingerprintBucketSize': @@ -119,6 +119,10 @@ export function mergeConfigs( 'apm_oss.metricsIndices' ] = `metrics-apm*,${mergedConfig['apm_oss.metricsIndices']}`; + mergedConfig[ + 'apm_oss.indexPattern' + ] = `traces-apm*,logs-apm*,metrics-apm*,${mergedConfig['apm_oss.indexPattern']}`; + return mergedConfig; } diff --git a/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts b/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts index 82e85e7da9bb3d..291b2fa2af99d8 100644 --- a/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts +++ b/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts @@ -34,7 +34,7 @@ export function getApmPackagePolicyDefinition( ], package: { name: APM_PACKAGE_NAME, - version: '0.3.0-dev.1', + version: '0.3.0', title: 'Elastic APM', }, }; diff --git a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts index 607a7e6227a9d6..a2944d6241d2d9 100644 --- a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts +++ b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts @@ -19,7 +19,8 @@ export async function createStaticIndexPattern( setup: Setup, config: APMRouteHandlerResources['config'], savedObjectsClient: InternalSavedObjectsClient, - spaceId: string | undefined + spaceId: string | undefined, + overwrite = false ): Promise { return withApmSpan('create_static_index_pattern', async () => { // don't autocreate APM index pattern if it's been disabled via the config @@ -45,7 +46,7 @@ export async function createStaticIndexPattern( }, { id: APM_STATIC_INDEX_PATTERN_ID, - overwrite: false, + overwrite, namespace: spaceId, } ) diff --git a/x-pack/plugins/apm/server/routes/fleet.ts b/x-pack/plugins/apm/server/routes/fleet.ts index 6628d29b256f7e..b760014d6af89f 100644 --- a/x-pack/plugins/apm/server/routes/fleet.ts +++ b/x-pack/plugins/apm/server/routes/fleet.ts @@ -25,6 +25,8 @@ import { createCloudApmPackgePolicy } from '../lib/fleet/create_cloud_apm_packag import { getUnsupportedApmServerSchema } from '../lib/fleet/get_unsupported_apm_server_schema'; import { isSuperuser } from '../lib/fleet/is_superuser'; import { getInternalSavedObjectsClient } from '../lib/helpers/get_internal_saved_objects_client'; +import { setupRequest } from '../lib/helpers/setup_request'; +import { createStaticIndexPattern } from '../lib/index_pattern/create_static_index_pattern'; const hasFleetDataRoute = createApmServerRoute({ endpoint: 'GET /api/apm/fleet/has_data', @@ -154,7 +156,7 @@ const createCloudApmPackagePolicyRoute = createApmServerRoute({ endpoint: 'POST /api/apm/fleet/cloud_apm_package_policy', options: { tags: ['access:apm', 'access:apm_write'] }, handler: async (resources) => { - const { plugins, context, config, request, logger } = resources; + const { plugins, context, config, request, logger, core } = resources; const cloudApmMigrationEnabled = config['xpack.apm.agent.migrations.enabled']; if (!plugins.fleet || !plugins.security) { @@ -171,15 +173,34 @@ const createCloudApmPackagePolicyRoute = createApmServerRoute({ if (!hasRequiredRole || !cloudApmMigrationEnabled) { throw Boom.forbidden(CLOUD_SUPERUSER_REQUIRED_MESSAGE); } - return { - cloud_apm_package_policy: await createCloudApmPackgePolicy({ - cloudPluginSetup, - fleetPluginStart, - savedObjectsClient, - esClient, - logger, - }), - }; + + const cloudApmAackagePolicy = await createCloudApmPackgePolicy({ + cloudPluginSetup, + fleetPluginStart, + savedObjectsClient, + esClient, + logger, + }); + + const [setup, internalSavedObjectsClient] = await Promise.all([ + setupRequest(resources), + core + .start() + .then(({ savedObjects }) => savedObjects.createInternalRepository()), + ]); + + const spaceId = plugins.spaces?.setup.spacesService.getSpaceId(request); + + // force update the index pattern title with data streams + await createStaticIndexPattern( + setup, + config, + internalSavedObjectsClient, + spaceId, + true + ); + + return { cloud_apm_package_policy: cloudApmAackagePolicy }; }, }); diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.test.ts b/x-pack/plugins/apm/server/routes/register_routes/index.test.ts index 158d7ee7e76a3f..b9dece866fae55 100644 --- a/x-pack/plugins/apm/server/routes/register_routes/index.test.ts +++ b/x-pack/plugins/apm/server/routes/register_routes/index.test.ts @@ -109,6 +109,11 @@ const initApi = ( params: {}, query: {}, body: null, + events: { + aborted$: { + toPromise: () => new Promise(() => {}), + }, + }, ...request, }, responseMock @@ -202,7 +207,7 @@ describe('createApi', () => { describe('when validating', () => { describe('_inspect', () => { it('allows _inspect=true', async () => { - const handlerMock = jest.fn(); + const handlerMock = jest.fn().mockResolvedValue({}); const { simulateRequest, mocks: { response }, @@ -234,7 +239,7 @@ describe('createApi', () => { }); it('rejects _inspect=1', async () => { - const handlerMock = jest.fn(); + const handlerMock = jest.fn().mockResolvedValue({}); const { simulateRequest, @@ -267,7 +272,7 @@ describe('createApi', () => { }); it('allows omitting _inspect', async () => { - const handlerMock = jest.fn(); + const handlerMock = jest.fn().mockResolvedValue({}); const { simulateRequest, @@ -297,7 +302,11 @@ describe('createApi', () => { simulateRequest, mocks: { response }, } = initApi([ - { endpoint: 'GET /foo', options: { tags: [] }, handler: jest.fn() }, + { + endpoint: 'GET /foo', + options: { tags: [] }, + handler: jest.fn().mockResolvedValue({}), + }, ]); await simulateRequest({ @@ -328,7 +337,7 @@ describe('createApi', () => { }); it('validates path parameters', async () => { - const handlerMock = jest.fn(); + const handlerMock = jest.fn().mockResolvedValue({}); const { simulateRequest, mocks: { response }, @@ -402,7 +411,7 @@ describe('createApi', () => { }); it('validates body parameters', async () => { - const handlerMock = jest.fn(); + const handlerMock = jest.fn().mockResolvedValue({}); const { simulateRequest, mocks: { response }, @@ -448,7 +457,7 @@ describe('createApi', () => { }); it('validates query parameters', async () => { - const handlerMock = jest.fn(); + const handlerMock = jest.fn().mockResolvedValue({}); const { simulateRequest, mocks: { response }, diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.ts b/x-pack/plugins/apm/server/routes/register_routes/index.ts index 136f3c73d80469..8e6070de722bea 100644 --- a/x-pack/plugins/apm/server/routes/register_routes/index.ts +++ b/x-pack/plugins/apm/server/routes/register_routes/index.ts @@ -29,6 +29,13 @@ const inspectRt = t.exact( }) ); +const CLIENT_CLOSED_REQUEST = { + statusCode: 499, + body: { + message: 'Client closed request', + }, +}; + export const inspectableEsQueriesMap = new WeakMap< KibanaRequest, InspectResponse @@ -89,23 +96,40 @@ export function registerRoutes({ runtimeType ); - const data: Record | undefined | null = (await handler({ - request, - context, - config, - logger, - core, - plugins, - params: merge( - { - query: { - _inspect: false, + const { aborted, data } = await Promise.race([ + handler({ + request, + context, + config, + logger, + core, + plugins, + params: merge( + { + query: { + _inspect: false, + }, }, - }, - validatedParams - ), - ruleDataClient, - })) as any; + validatedParams + ), + ruleDataClient, + }).then((value) => { + return { + aborted: false, + data: value as Record | undefined | null, + }; + }), + request.events.aborted$.toPromise().then(() => { + return { + aborted: true, + data: undefined, + }; + }), + ]); + + if (aborted) { + return response.custom(CLIENT_CLOSED_REQUEST); + } if (Array.isArray(data)) { throw new Error('Return type cannot be an array'); @@ -118,9 +142,6 @@ export function registerRoutes({ } : { ...data }; - // cleanup - inspectableEsQueriesMap.delete(request); - if (!options.disableTelemetry && telemetryUsageCounter) { telemetryUsageCounter.incrementCounter({ counterName: `${method.toUpperCase()} ${pathname}`, @@ -131,6 +152,7 @@ export function registerRoutes({ return response.ok({ body }); } catch (error) { logger.error(error); + if (!options.disableTelemetry && telemetryUsageCounter) { telemetryUsageCounter.incrementCounter({ counterName: `${method.toUpperCase()} ${pathname}`, @@ -147,16 +169,18 @@ export function registerRoutes({ }, }; - if (Boom.isBoom(error)) { - opts.statusCode = error.output.statusCode; + if (error instanceof RequestAbortedError) { + return response.custom(merge(opts, CLIENT_CLOSED_REQUEST)); } - if (error instanceof RequestAbortedError) { - opts.statusCode = 499; - opts.body.message = 'Client closed request'; + if (Boom.isBoom(error)) { + opts.statusCode = error.output.statusCode; } return response.custom(opts); + } finally { + // cleanup + inspectableEsQueriesMap.delete(request); } } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx index a7eb2424e797aa..0dd2b0988b3f4c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx @@ -19,6 +19,7 @@ import { EuiFlexItem, EuiSpacer, EuiTitle, + EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -59,14 +60,15 @@ export const ProductSelector: React.FC = ({ access }) => { -

+

{i18n.translate('xpack.enterpriseSearch.overview.heading', { defaultMessage: 'Welcome to Elastic Enterprise Search', })}

- -

+ + +

{config.host ? i18n.translate('xpack.enterpriseSearch.overview.subheading', { defaultMessage: 'Select a product to get started.', @@ -75,7 +77,7 @@ export const ProductSelector: React.FC = ({ access }) => { defaultMessage: 'Choose a product to set up and get started.', })}

-
+
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss index 45bf37def11216..4be8d7322b4c8e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss @@ -21,21 +21,7 @@ &__header { text-align: center; margin: auto; - } - - &__heading { - @include euiBreakpoint('xs', 's') { - font-size: $euiFontSizeXL; - line-height: map-get(map-get($euiTitles, 'm'), 'line-height'); - } - } - - &__subheading { - color: $euiColorMediumShade; - font-size: $euiFontSize; - @include euiBreakpoint('m', 'l', 'xl') { - font-size: $euiFontSizeL; margin-bottom: $euiSizeL; } } diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx index e7dfd6ddf13890..5714cc965827e1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx @@ -33,24 +33,23 @@ import { NAV, CANCEL_BUTTON } from '../../../constants'; import { USERS_AND_ROLES_PATH } from '../../../routes'; import { GroupLogic, MAX_NAME_LENGTH } from '../group_logic'; -import { GroupUsersTable } from './group_users_table'; - export const EMPTY_SOURCES_DESCRIPTION = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.groups.overview.emptySourcesDescription', { defaultMessage: 'No content sources are shared with this group.', } ); -const GROUP_USERS_DESCRIPTION = i18n.translate( - 'xpack.enterpriseSearch.workplaceSearch.groups.overview.groupUsersDescription', +const USERS_SECTION_TITLE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.groups.overview.usersSectionTitle', { - defaultMessage: 'Members will be able to search over the group’s sources.', + defaultMessage: 'Group users', } ); -export const EMPTY_USERS_DESCRIPTION = i18n.translate( - 'xpack.enterpriseSearch.workplaceSearch.groups.overview.emptyUsersDescription', +const GROUP_USERS_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.groups.overview.groupUsersDescription', { - defaultMessage: 'There are no users in this group.', + defaultMessage: + "Users assigned to this group gain access to the sources' data and content defined above. User assignments for this group can be managed in the Users and Roles area.", } ); const MANAGE_SOURCES_BUTTON_TEXT = i18n.translate( @@ -118,7 +117,7 @@ export const GroupOverview: React.FC = () => { onGroupNameInputChange, } = useActions(GroupLogic); const { - group: { name, contentSources, users, canDeleteGroup }, + group: { name, contentSources, canDeleteGroup }, groupNameInputValue, dataLoading, confirmDeleteModalVisible, @@ -158,7 +157,6 @@ export const GroupOverview: React.FC = () => { ); const hasContentSources = contentSources?.length > 0; - const hasUsers = users?.length > 0; const manageSourcesButton = ( @@ -199,12 +197,11 @@ export const GroupOverview: React.FC = () => { const usersSection = ( - {hasUsers && } + {manageUsersButton} ); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx index f98b873aed5bba..770bf8a51efd39 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx @@ -14,8 +14,7 @@ import moment from 'moment'; import { EuiTableRow } from '@elastic/eui'; -import { GroupRow, NO_USERS_MESSAGE, NO_SOURCES_MESSAGE } from './group_row'; -import { GroupUsers } from './group_users'; +import { GroupRow, NO_SOURCES_MESSAGE } from './group_row'; describe('GroupRow', () => { it('renders', () => { @@ -24,12 +23,6 @@ describe('GroupRow', () => { expect(wrapper.find(EuiTableRow)).toHaveLength(1); }); - it('renders group users', () => { - const wrapper = shallow(); - - expect(wrapper.find(GroupUsers)).toHaveLength(1); - }); - it('renders fromNow date string when in range', () => { const wrapper = shallow( @@ -44,12 +37,6 @@ describe('GroupRow', () => { expect(wrapper.find('small').text()).toEqual('Last updated January 1, 2020.'); }); - it('renders empty users message when no users present', () => { - const wrapper = shallow(); - - expect(wrapper.find('.user-group__accounts').text()).toEqual(NO_USERS_MESSAGE); - }); - it('renders empty sources message when no sources present', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx index 94d44fde57aedd..d079eb34fbf890 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx @@ -19,7 +19,6 @@ import { Group } from '../../../types'; import { MAX_NAME_LENGTH } from '../group_logic'; import { GroupSources } from './group_sources'; -import { GroupUsers } from './group_users'; const DAYS_CUTOFF = 8; export const NO_SOURCES_MESSAGE = i18n.translate( @@ -40,14 +39,7 @@ const dateDisplay = (date: string) => ? moment(date).fromNow() : moment(date).format('MMMM D, YYYY'); -export const GroupRow: React.FC = ({ - id, - name, - updatedAt, - contentSources, - users, - usersCount, -}) => { +export const GroupRow: React.FC = ({ id, name, updatedAt, contentSources }) => { const GROUP_UPDATED_TEXT = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.groups.groupUpdatedText', { @@ -76,15 +68,6 @@ export const GroupRow: React.FC = ({ )}
- -
- {usersCount > 0 ? ( - - ) : ( - NO_USERS_MESSAGE - )} -
-
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx index cfb3ed80442358..45175e489f94a8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx @@ -36,12 +36,6 @@ const SOURCES_TABLE_HEADER = i18n.translate( defaultMessage: 'Content sources', } ); -const USERS_TABLE_HEADER = i18n.translate( - 'xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.usersTableHeader', - { - defaultMessage: 'Users', - } -); export const GroupsTable: React.FC<{}> = () => { const { setActivePage } = useActions(GroupsLogic); @@ -77,7 +71,6 @@ export const GroupsTable: React.FC<{}> = () => { {GROUP_TABLE_HEADER} {SOURCES_TABLE_HEADER} - {USERS_TABLE_HEADER} diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts index d0e74f3234c146..f9756119b336cd 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts @@ -403,7 +403,7 @@ describe('EnterpriseSearchRequestHandler', () => { expect(responseMock.customError).toHaveBeenCalledWith({ statusCode: 502, body: 'Cannot authenticate Enterprise Search user', - headers: mockExpectedResponseHeaders, + headers: { ...mockExpectedResponseHeaders, [ERROR_CONNECTING_HEADER]: 'true' }, }); expect(mockLogger.error).toHaveBeenCalled(); }); diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts index 8031fc724f7b37..57b91c2b30c73f 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts @@ -283,12 +283,11 @@ export class EnterpriseSearchRequestHandler { handleConnectionError(response: KibanaResponseFactory, e: Error) { const errorMessage = `Error connecting to Enterprise Search: ${e?.message || e.toString()}`; + const headers = { ...this.headers, [ERROR_CONNECTING_HEADER]: 'true' }; this.log.error(errorMessage); if (e instanceof Error) this.log.debug(e.stack as string); - const headers = { ...this.headers, [ERROR_CONNECTING_HEADER]: 'true' }; - return response.customError({ statusCode: 502, headers, body: errorMessage }); } @@ -298,9 +297,10 @@ export class EnterpriseSearchRequestHandler { */ handleAuthenticationError(response: KibanaResponseFactory) { const errorMessage = 'Cannot authenticate Enterprise Search user'; + const headers = { ...this.headers, [ERROR_CONNECTING_HEADER]: 'true' }; this.log.error(errorMessage); - return response.customError({ statusCode: 502, headers: this.headers, body: errorMessage }); + return response.customError({ statusCode: 502, headers, body: errorMessage }); } /** diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js index ed603357206ad9..39d4dd1a71dd9f 100644 --- a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js +++ b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js @@ -18,13 +18,13 @@ import React, { Component, Fragment, useContext } from 'react'; import memoizeOne from 'memoize-one'; import { EuiBadge, - EuiButtonEmpty, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, EuiLink, EuiLoadingSpinner, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -52,6 +52,19 @@ import { timeFormatter } from '../../../../../common/util/date_utils'; import { MlAnnotationUpdatesContext } from '../../../contexts/ml/ml_annotation_updates_context'; import { DatafeedChartFlyout } from '../../../jobs/jobs_list/components/datafeed_chart_flyout'; +const editAnnotationsText = ( + +); +const viewDataFeedText = ( + +); + const CURRENT_SERIES = 'current_series'; /** * Table component for rendering the lists of annotations for an ML job. @@ -463,82 +476,67 @@ class AnnotationsTableUI extends Component { const actions = []; actions.push({ - render: (annotation) => { - // find the original annotation because the table might not show everything + name: editAnnotationsText, + description: editAnnotationsText, + icon: 'pencil', + type: 'icon', + onClick: (annotation) => { const annotationId = annotation._id; const originalAnnotation = annotations.find((d) => d._id === annotationId); - const editAnnotationsText = ( - - ); - const editAnnotationsAriaLabelText = i18n.translate( - 'xpack.ml.annotationsTable.editAnnotationsTooltipAriaLabel', - { defaultMessage: 'Edit annotation' } - ); - return ( - annotationUpdatesService.setValue(originalAnnotation ?? annotation)} - > - {editAnnotationsText} - - ); + + annotationUpdatesService.setValue(originalAnnotation ?? annotation); }, }); if (this.state.jobId && this.props.jobs[0].analysis_config.bucket_span) { // add datafeed modal action actions.push({ - render: (annotation) => { - const viewDataFeedText = ( - - ); - const viewDataFeedTooltipAriaLabelText = i18n.translate( - 'xpack.ml.annotationsTable.datafeedChartTooltipAriaLabel', - { defaultMessage: 'Datafeed chart' } - ); - return ( - - this.setState({ - datafeedFlyoutVisible: true, - datafeedEnd: annotation.end_timestamp, - }) - } - > - {viewDataFeedText} - - ); + name: viewDataFeedText, + description: viewDataFeedText, + icon: 'visAreaStacked', + type: 'icon', + onClick: (annotation) => { + this.setState({ + datafeedFlyoutVisible: true, + datafeedEnd: annotation.end_timestamp, + }); }, }); } if (isSingleMetricViewerLinkVisible) { actions.push({ - render: (annotation) => { + name: (annotation) => { const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id)); - const openInSingleMetricViewerTooltipText = isDrillDownAvailable ? ( - - ) : ( - + + if (isDrillDownAvailable) { + return ( + + ); + } + return ( + + } + > + + ); - const openInSingleMetricViewerAriaLabelText = isDrillDownAvailable + }, + description: (annotation) => { + const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id)); + + return isDrillDownAvailable ? i18n.translate('xpack.ml.annotationsTable.openInSingleMetricViewerAriaLabel', { defaultMessage: 'Open in Single Metric Viewer', }) @@ -546,19 +544,11 @@ class AnnotationsTableUI extends Component { 'xpack.ml.annotationsTable.jobConfigurationNotSupportedInSingleMetricViewerAriaLabel', { defaultMessage: 'Job configuration not supported in Single Metric Viewer' } ); - - return ( - this.openSingleMetricView(annotation)} - > - {openInSingleMetricViewerTooltipText} - - ); }, + enabled: (annotation) => isTimeSeriesViewJob(this.getJob(annotation.job_id)), + icon: 'visLine', + type: 'icon', + onClick: (annotation) => this.openSingleMetricView(annotation), }); } diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js index a11a42b9b65b2c..31058b62af7fe5 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer.js @@ -261,6 +261,30 @@ export class ExplorerUI extends React.Component { } = this.props.explorerState; const { annotationsData, aggregations, error: annotationsError } = annotations; + const annotationsCnt = Array.isArray(annotationsData) ? annotationsData.length : 0; + const allAnnotationsCnt = Array.isArray(aggregations?.event?.buckets) + ? aggregations.event.buckets.reduce((acc, v) => acc + v.doc_count, 0) + : annotationsCnt; + + const badge = + allAnnotationsCnt > annotationsCnt ? ( + + + + ) : ( + + + + ); + const jobSelectorProps = { dateFormatTz: getDateFormatTz(), }; @@ -404,7 +428,7 @@ export class ExplorerUI extends React.Component { {loading === false && tableData.anomalies?.length ? ( ) : null} - {annotationsData.length > 0 && ( + {annotationsCnt > 0 && ( <> - - - ), + badge, }} /> diff --git a/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap b/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap index 744a3b2d405c3d..8007acad93e4bd 100644 --- a/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap +++ b/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap @@ -424,7 +424,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -481,7 +480,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -523,7 +521,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -1491,7 +1487,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -1533,7 +1528,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -2515,7 +2508,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -2557,7 +2549,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -3586,7 +3576,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -3628,7 +3617,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -4690,7 +4677,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -4732,7 +4718,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -5761,7 +5745,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -5803,7 +5786,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -6832,7 +6813,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -6874,7 +6854,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -7903,7 +7881,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -7945,7 +7922,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -8974,7 +8949,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
@@ -9016,7 +8990,6 @@ exports[`ReportListing Report job listing with some items 1`] = ` className="euiTableCellContent euiTableCellContent--overflowingContent" >
-
+
@@ -752,9 +750,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "print" layout o onResize={[Function]} >
-
+
@@ -1064,9 +1060,7 @@ exports[`ScreenCapturePanelContent renders the default view properly 1`] = ` onResize={[Function]} >
-
+
diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index 1e0d798cf7f07d..cf8c33d38f8fa9 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -178,8 +178,6 @@ export interface HostResultList { request_page_size: number; /* the page index requested */ request_page_index: number; - /* the version of the query strategy */ - query_strategy_version: MetadataQueryStrategyVersions; /* policy IDs and versions */ policy_info?: HostInfo['policy_info']; } @@ -404,21 +402,11 @@ export enum HostStatus { INACTIVE = 'inactive', } -export enum MetadataQueryStrategyVersions { - VERSION_1 = 'v1', - VERSION_2 = 'v2', -} - export type PolicyInfo = Immutable<{ revision: number; id: string; }>; -export interface HostMetadataInfo { - metadata: HostMetadata; - query_strategy_version: MetadataQueryStrategyVersions; -} - export type HostInfo = Immutable<{ metadata: HostMetadata; host_status: HostStatus; @@ -438,8 +426,6 @@ export type HostInfo = Immutable<{ */ endpoint: PolicyInfo; }; - /* the version of the query strategy */ - query_strategy_version: MetadataQueryStrategyVersions; }>; // HostMetadataDetails is now just HostMetadata diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts index ad71d54eb2a7ad..ce00c9b40aead9 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts @@ -6,7 +6,7 @@ */ import { formatMitreAttackDescription } from '../../helpers/rules'; -import { indexPatterns, newRule, newThresholdRule } from '../../objects/rule'; +import { indexPatterns, newRule, newThresholdRule, ThresholdRule } from '../../objects/rule'; import { ALERT_RULE_METHOD, @@ -180,9 +180,9 @@ describe('Detection rules, threshold', () => { cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', rule.riskScore); }); - it('Preview results', () => { - const previewRule = { ...newThresholdRule }; - previewRule.index!.push('.siem-signals*'); + it('Preview results of keyword using "host.name"', () => { + const previewRule: ThresholdRule = { ...newThresholdRule }; + previewRule.index = [...previewRule.index, '.siem-signals*']; createCustomRuleActivated(newRule); goToManageAlertsDetectionRules(); @@ -194,4 +194,23 @@ describe('Detection rules, threshold', () => { cy.get(PREVIEW_HEADER_SUBTITLE).should('have.text', '3 unique hits'); }); + + it('Preview results of "ip" using "source.ip"', () => { + const previewRule: ThresholdRule = { + ...newThresholdRule, + thresholdField: 'source.ip', + threshold: '1', + }; + previewRule.index = [...previewRule.index, '.siem-signals*']; + + createCustomRuleActivated(newRule); + goToManageAlertsDetectionRules(); + waitForRulesTableToBeLoaded(); + goToCreateNewRule(); + selectThresholdRuleType(); + fillDefineThresholdRule(previewRule); + previewResults(); + + cy.get(PREVIEW_HEADER_SUBTITLE).should('have.text', '10 unique hits'); + }); }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts index 9b74110f0ef77d..1b420cd6d1520d 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts @@ -275,7 +275,7 @@ export const fillDefineThresholdRule = (rule: ThresholdRule) => { cy.get(TIMELINE(rule.timeline.id!)).click(); cy.get(COMBO_BOX_CLEAR_BTN).click(); - rule.index!.forEach((index) => { + rule.index.forEach((index) => { cy.get(COMBO_BOX_INPUT).first().type(`${index}{enter}`); }); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx index 3a1a29b63eadf0..329b8e32f057d8 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx @@ -213,7 +213,7 @@ const AlertSummaryViewComponent: React.FC<{ return ( <> - + { - const mount = useMountAppended(); - const mockTheme = getMockTheme({ - eui: { - euiBreakpoints: { - l: '1200px', - }, - paddingSizes: { - m: '8px', - xl: '32px', - }, - }, - }); - - test('renders correct items', () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('[data-test-subj="empty-threat-details-view"]').exists()).toEqual(true); - }); - - test('renders link to docs', () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('a').exists()).toEqual(true); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/empty_threat_details_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/empty_threat_details_view.tsx deleted file mode 100644 index d7e1c4d7754ecd..00000000000000 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/empty_threat_details_view.tsx +++ /dev/null @@ -1,51 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui'; -import React from 'react'; -import styled from 'styled-components'; - -import { useKibana } from '../../../lib/kibana'; -import * as i18n from './translations'; - -const EmptyThreatDetailsViewContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; -`; - -const Span = styled.span` - color: ${({ theme }) => theme.eui.euiColorDarkShade}; - line-height: 1.8em; - text-align: center; - padding: ${({ theme }) => `${theme.eui.paddingSizes.m} ${theme.eui.paddingSizes.xl}`}; -`; - -const EmptyThreatDetailsViewComponent: React.FC<{}> = () => { - const threatIntelDocsUrl = `${ - useKibana().services.docLinks.links.filebeat.base - }/filebeat-module-threatintel.html`; - - return ( - - - -

{i18n.NO_ENRICHMENT_FOUND}

-
- - {i18n.IF_CTI_NOT_ENABLED} - - {i18n.CHECK_DOCS} - - -
- ); -}; - -EmptyThreatDetailsViewComponent.displayName = 'EmptyThreatDetailsView'; - -export const EmptyThreatDetailsView = React.memo(EmptyThreatDetailsViewComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.test.tsx new file mode 100644 index 00000000000000..819c666bd7267e --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.test.tsx @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { mount } from 'enzyme'; + +import { NoEnrichmentsPanel } from './no_enrichments_panel'; +import * as i18n from './translations'; + +jest.mock('../../../lib/kibana'); + +describe('NoEnrichmentsPanelView', () => { + it('renders a qualified container', () => { + const wrapper = mount( + + ); + expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').exists()).toEqual(true); + }); + + it('renders nothing when all enrichments are present', () => { + const wrapper = mount( + + ); + expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').exists()).toEqual(false); + }); + + it('renders expected text when no enrichments are present', () => { + const wrapper = mount( + + ); + expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').hostNodes().text()).toContain( + i18n.NO_ENRICHMENTS_FOUND_TITLE + ); + }); + + it('renders expected text when existing enrichments are absent', () => { + const wrapper = mount( + + ); + expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').hostNodes().text()).toContain( + i18n.NO_INDICATOR_ENRICHMENTS_TITLE + ); + }); + + it('renders expected text when investigation enrichments are absent', () => { + const wrapper = mount( + + ); + expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').hostNodes().text()).toContain( + i18n.NO_INVESTIGATION_ENRICHMENTS_TITLE + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx new file mode 100644 index 00000000000000..b521c3ba92c4d9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiHorizontalRule, EuiLink, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; +import React from 'react'; +import styled from 'styled-components'; +import { useKibana } from '../../../lib/kibana'; + +import * as i18n from './translations'; + +const Container = styled(EuiPanel)` + display: flex; + flex-direction: column; +`; + +const NoEnrichmentsPanelView: React.FC<{ + title: React.ReactNode; + description: React.ReactNode; +}> = ({ title, description }) => { + return ( + + {title} + + + {description} + + + ); +}; + +NoEnrichmentsPanelView.displayName = 'NoEnrichmentsPanelView'; + +export const NoEnrichmentsPanel: React.FC<{ + existingEnrichmentsCount: number; + investigationEnrichmentsCount: number; +}> = ({ existingEnrichmentsCount, investigationEnrichmentsCount }) => { + const threatIntelDocsUrl = `${ + useKibana().services.docLinks.links.filebeat.base + }/filebeat-module-threatintel.html`; + const noIndicatorEnrichmentsDescription = ( + <> + {i18n.IF_CTI_NOT_ENABLED} + + {i18n.CHECK_DOCS} + + + ); + + if (existingEnrichmentsCount === 0 && investigationEnrichmentsCount === 0) { + return ( + {i18n.NO_ENRICHMENTS_FOUND_TITLE}} + description={ + <> +

{noIndicatorEnrichmentsDescription}

+

{i18n.NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION}

+ + } + /> + ); + } else if (existingEnrichmentsCount === 0) { + return ( + <> + + {i18n.NO_INDICATOR_ENRICHMENTS_TITLE}} + description={noIndicatorEnrichmentsDescription} + /> + + ); + } else if (investigationEnrichmentsCount === 0) { + return ( + <> + + {i18n.NO_INVESTIGATION_ENRICHMENTS_TITLE}} + description={i18n.NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION} + /> + + ); + } else { + return null; + } +}; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx index 0113dde96a4b6c..c25457a5e5e88d 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx @@ -31,15 +31,6 @@ describe('ThreatDetailsView', () => { ); }); - it('renders an empty view if there are no enrichments', () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('[data-test-subj="empty-threat-details-view"]').exists()).toEqual(true); - }); - it('renders anchor links for event.url and event.reference', () => { const enrichments = [ buildEventEnrichmentMock({ diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx index d5e985c5757a62..b6b8a47c1dd8c5 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx @@ -20,7 +20,6 @@ import React, { Fragment } from 'react'; import { StyledEuiInMemoryTable } from '../summary_view'; import { getSummaryColumns, SummaryRow, ThreatDetailsRow } from '../helpers'; -import { EmptyThreatDetailsView } from './empty_threat_details_view'; import { FIRSTSEEN, EVENT_URL, EVENT_REFERENCE } from '../../../../../common/cti/constants'; import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../common/constants'; import { getFirstElement } from '../../../../../common/utils/data_retrieval'; @@ -70,15 +69,13 @@ const ThreatDetailsHeader: React.FC<{ + {isInvestigationTimeEnrichment(type) && ( + + + + )} - {isInvestigationTimeEnrichment(type) && ( - - - - - - )} ); @@ -131,10 +128,6 @@ const buildThreatDetailsItems = (enrichment: CtiEnrichment) => const ThreatDetailsViewComponent: React.FC<{ enrichments: CtiEnrichment[]; }> = ({ enrichments }) => { - if (enrichments.length < 1) { - return ; - } - const sortedEnrichments = enrichments.sort((a, b) => getFirstSeen(b) - getFirstSeen(a)); return ( @@ -146,6 +139,7 @@ const ThreatDetailsViewComponent: React.FC<{ return ( + { ).toEqual('Summary'); }); }); + + describe('threat intel tab', () => { + it('renders a "no enrichments" panel view if there are no enrichments', () => { + alertsWrapper.find('[data-test-subj="threatIntelTab"]').first().simulate('click'); + expect(alertsWrapper.find('[data-test-subj="no-enrichments-panel"]').exists()).toEqual(true); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx index 9afaaef61b17a4..7074212dcdb4c5 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx @@ -9,9 +9,6 @@ import { EuiTabbedContent, EuiTabbedContentTab, EuiSpacer, - EuiButton, - EuiFlexGroup, - EuiFlexItem, EuiLoadingContent, EuiLoadingSpinner, } from '@elastic/eui'; @@ -34,6 +31,7 @@ import { parseExistingEnrichments, timelineDataToEnrichment, } from './cti_details/helpers'; +import { NoEnrichmentsPanel } from './cti_details/no_enrichments_panel'; type EventViewTab = EuiTabbedContentTab; @@ -100,9 +98,6 @@ const EventDetailsComponent: React.FC = ({ (tab: EuiTabbedContentTab) => setSelectedTabId(tab.id as EventViewId), [setSelectedTabId] ); - const viewThreatIntelTab = useCallback(() => setSelectedTabId(EventsViewType.threatIntelView), [ - setSelectedTabId, - ]); const eventFields = useMemo(() => getEnrichmentFields(data), [data]); const existingEnrichments = useMemo( @@ -118,6 +113,9 @@ const EventDetailsComponent: React.FC = ({ loading: enrichmentsLoading, result: enrichmentsResponse, } = useInvestigationTimeEnrichment(eventFields); + const investigationEnrichments = useMemo(() => enrichmentsResponse?.enrichments ?? [], [ + enrichmentsResponse?.enrichments, + ]); const allEnrichments = useMemo(() => { if (enrichmentsLoading || !enrichmentsResponse?.enrichments) { return existingEnrichments; @@ -140,29 +138,20 @@ const EventDetailsComponent: React.FC = ({ eventId: id, browserFields, timelineId, - title: i18n.ALERT_SUMMARY, }} /> + {enrichmentCount > 0 && ( + + )} {enrichmentsLoading && ( <> )} - {enrichmentCount > 0 && ( - <> - - - - - {i18n.VIEW_CTI_DATA} - - - - )} ), } @@ -176,7 +165,6 @@ const EventDetailsComponent: React.FC = ({ enrichmentsLoading, enrichmentCount, allEnrichments, - viewThreatIntelTab, ] ); @@ -192,10 +180,25 @@ const EventDetailsComponent: React.FC = ({ {enrichmentsLoading ? : `(${enrichmentCount})`} ), - content: , + content: ( + <> + + + + ), } : undefined, - [allEnrichments, enrichmentCount, enrichmentsLoading, isAlert] + [ + allEnrichments, + enrichmentCount, + enrichmentsLoading, + existingEnrichments.length, + investigationEnrichments.length, + isAlert, + ] ); const tableTab = useMemo( diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx index 0e846f3f6f6998..961860ed6d8b99 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx @@ -13,12 +13,13 @@ import { SummaryRow } from './helpers'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export const StyledEuiInMemoryTable = styled(EuiInMemoryTable as any)` - .euiTableHeaderCell { - border: none; - } + .euiTableHeaderCell, .euiTableRowCell { border: none; } + .euiTableHeaderCell .euiTableCellContent { + padding: 0; + } `; const StyledEuiTitle = styled(EuiTitle)` diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts index a17ca5e434ace7..c632f5d6332e0e 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts @@ -11,22 +11,10 @@ export const SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.summa defaultMessage: 'Summary', }); -export const ALERT_SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.alertSummary', { - defaultMessage: 'Alert Summary', -}); - export const THREAT_INTEL = i18n.translate('xpack.securitySolution.alertDetails.threatIntel', { defaultMessage: 'Threat Intel', }); -export const THREAT_SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.threatSummary', { - defaultMessage: 'Threat Summary', -}); - -export const VIEW_CTI_DATA = i18n.translate('xpack.securitySolution.alertDetails.threatIntelCta', { - defaultMessage: 'View threat intel data', -}); - export const INVESTIGATION_GUIDE = i18n.translate( 'xpack.securitySolution.alertDetails.summary.investigationGuide', { diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap index 22805d34d2ee1e..410fb7f3ae793e 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap @@ -10,6 +10,7 @@ exports[`GroupsFilterPopover renders correctly against snapshot 1`] = ` iconType="arrowDown" isSelected={false} numActiveFilters={0} + numFilters={3} onClick={[Function]} > Groups diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx index b7425a62f6773b..249dc0dfccdbb6 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx @@ -59,6 +59,7 @@ export const GroupsFilterPopoverComponent = ({ iconType="arrowDown" onClick={() => setIsGroupPopoverOpen(!isGroupPopoverOpen)} isSelected={isGroupPopoverOpen} + numFilters={uniqueGroups.length} hasActiveFilters={selectedGroups.length > 0} numActiveFilters={selectedGroups.length} > diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx index 6342d468f5962c..45b66058a04fb8 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx @@ -118,6 +118,7 @@ export const PreviewQuery = ({ startDate: toTime, filterQuery: queryFilter, indexNames: index, + includeMissingData: false, histogramType: MatrixHistogramType.events, stackByField: 'event.category', threshold: ruleType === 'threshold' ? threshold : undefined, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx index 45ce5bc18361c9..c5262caf6c776c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx @@ -102,9 +102,11 @@ const TagsFilterPopoverComponent = ({ ownFocus button={ setIsTagPopoverOpen(!isTagPopoverOpen)} + numFilters={tags.length} isSelected={isTagPopoverOpen} hasActiveFilters={selectedTags.length > 0} numActiveFilters={selectedTags.length} diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts index d6b24fa3cbdfc2..76de52222bbd39 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts @@ -15,7 +15,6 @@ import { HostPolicyResponse, HostResultList, HostStatus, - MetadataQueryStrategyVersions, } from '../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; import { @@ -54,7 +53,6 @@ export const endpointMetadataHttpMocks = httpHandlerMockFactory => { agentsWithEndpointsTotalError: undefined, endpointsTotal: 0, endpointsTotalError: undefined, - queryStrategyVersion: undefined, policyVersionInfo: undefined, hostStatus: undefined, isolationRequestState: createUninitialisedResourceState(), diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index f233fbdec5415e..922f10cee2f8b4 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -28,7 +28,6 @@ import { nonExistingPolicies, patterns, searchBarQuery, - isTransformEnabled, getIsIsolationRequestPending, getCurrentIsolationRequestState, getActivityLogData, @@ -180,7 +179,7 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory HostResultList = (options = {}) => { const { total = 1, request_page_size: requestPageSize = 10, request_page_index: requestPageIndex = 0, - query_strategy_version: queryStrategyVersion = MetadataQueryStrategyVersions.VERSION_2, } = options; // Skip any that are before the page we're on @@ -58,7 +55,6 @@ export const mockEndpointResultList: (options?: { hosts.push({ metadata: generator.generateHostMetadata(), host_status: HostStatus.UNHEALTHY, - query_strategy_version: queryStrategyVersion, }); } const mock: HostResultList = { @@ -66,7 +62,6 @@ export const mockEndpointResultList: (options?: { total, request_page_size: requestPageSize, request_page_index: requestPageIndex, - query_strategy_version: queryStrategyVersion, }; return mock; }; @@ -78,7 +73,6 @@ export const mockEndpointDetailsApiResult = (): HostInfo => { return { metadata: generator.generateHostMetadata(), host_status: HostStatus.UNHEALTHY, - query_strategy_version: MetadataQueryStrategyVersions.VERSION_2, }; }; @@ -92,7 +86,6 @@ const endpointListApiPathHandlerMocks = ({ endpointPackagePolicies = [], policyResponse = generator.generatePolicyResponse(), agentPolicy = generator.generateAgentPolicy(), - queryStrategyVersion = MetadataQueryStrategyVersions.VERSION_2, totalAgentsUsingEndpoint = 0, }: { /** route handlers will be setup for each individual host in this array */ @@ -101,7 +94,6 @@ const endpointListApiPathHandlerMocks = ({ endpointPackagePolicies?: GetPolicyListResponse['items']; policyResponse?: HostPolicyResponse; agentPolicy?: GetAgentPoliciesResponseItem; - queryStrategyVersion?: MetadataQueryStrategyVersions; totalAgentsUsingEndpoint?: number; } = {}) => { const apiHandlers = { @@ -119,7 +111,6 @@ const endpointListApiPathHandlerMocks = ({ request_page_size: 10, request_page_index: 0, total: endpointsResults?.length || 0, - query_strategy_version: queryStrategyVersion, }; }, @@ -192,16 +183,11 @@ export const setEndpointListApiMockImplementation: ( apiResponses?: Parameters[0] ) => void = ( mockedHttpService, - { - endpointsResults = mockEndpointResultList({ total: 3 }).hosts, - queryStrategyVersion = MetadataQueryStrategyVersions.VERSION_2, - ...pathHandlersOptions - } = {} + { endpointsResults = mockEndpointResultList({ total: 3 }).hosts, ...pathHandlersOptions } = {} ) => { const apiHandlers = endpointListApiPathHandlerMocks({ ...pathHandlersOptions, endpointsResults, - queryStrategyVersion, }); mockedHttpService.post diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts index 1498ce08db8abc..c6bf13a3b5715d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts @@ -89,7 +89,6 @@ export const endpointListReducer: StateReducer = (state = initialEndpointPageSta total, request_page_size: pageSize, request_page_index: pageIndex, - query_strategy_version: queryStrategyVersion, policy_info: policyVersionInfo, } = action.payload; return { @@ -98,7 +97,6 @@ export const endpointListReducer: StateReducer = (state = initialEndpointPageSta total, pageSize, pageIndex, - queryStrategyVersion, policyVersionInfo, loading: false, error: undefined, diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts index 5771fbac957d8b..4287cf9a109ea3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts @@ -15,7 +15,6 @@ import { HostPolicyResponseAppliedAction, HostPolicyResponseConfiguration, HostPolicyResponseActionStatus, - MetadataQueryStrategyVersions, HostStatus, ActivityLog, HostMetadata, @@ -90,17 +89,11 @@ export const agentsWithEndpointsTotalError = (state: Immutable) = state.agentsWithEndpointsTotalError; export const endpointsTotalError = (state: Immutable) => state.endpointsTotalError; -const queryStrategyVersion = (state: Immutable) => state.queryStrategyVersion; export const endpointPackageVersion = createSelector(endpointPackageInfo, (info) => isLoadedResourceState(info) ? info.data.version : undefined ); -export const isTransformEnabled = createSelector( - queryStrategyVersion, - (version) => version !== MetadataQueryStrategyVersions.VERSION_1 -); - /** * Returns the index patterns for the SearchBar to use for autosuggest */ diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts index 144cc7a64d6cbc..875841cb55b738 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts @@ -13,7 +13,6 @@ import { HostPolicyResponse, AppLocation, PolicyData, - MetadataQueryStrategyVersions, HostStatus, HostIsolationResponse, EndpointPendingActions, @@ -96,8 +95,6 @@ export interface EndpointState { endpointsTotal: number; /** api error for total, actual Endpoints */ endpointsTotalError?: ServerApiError; - /** The query strategy version that informs whether the transform for KQL is enabled or not */ - queryStrategyVersion?: MetadataQueryStrategyVersions; /** The policy IDs and revision number of the corresponding agent, and endpoint. May be more recent than what's running */ policyVersionInfo?: HostInfo['policy_info']; /** The status of the host, which is mapped to the Elastic Agent status in Fleet */ diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx index aafac38accd89f..26d0d53e39982a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx @@ -23,7 +23,6 @@ import { HostPolicyResponseActionStatus, HostPolicyResponseAppliedAction, HostStatus, - MetadataQueryStrategyVersions, } from '../../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { POLICY_STATUS_TO_TEXT } from './host_constants'; @@ -167,31 +166,6 @@ describe('when on the endpoint list page', () => { }); }); - describe('when loading data with the query_strategy_version is `v1`', () => { - beforeEach(() => { - reactTestingLibrary.act(() => { - const mockedEndpointListData = mockEndpointResultList({ - total: 4, - query_strategy_version: MetadataQueryStrategyVersions.VERSION_1, - }); - setEndpointListApiMockImplementation(coreStart.http, { - endpointsResults: mockedEndpointListData.hosts, - queryStrategyVersion: mockedEndpointListData.query_strategy_version, - }); - }); - }); - afterEach(() => { - jest.clearAllMocks(); - }); - it('should not display the KQL bar', async () => { - const renderResult = render(); - await reactTestingLibrary.act(async () => { - await middlewareSpy.waitForAction('serverReturnedEndpointList'); - }); - expect(renderResult.queryByTestId('adminSearchBar')).toBeNull(); - }); - }); - describe('when determining when to show the enrolling message', () => { afterEach(() => { jest.clearAllMocks(); @@ -268,7 +242,6 @@ describe('when on the endpoint list page', () => { reactTestingLibrary.act(() => { const mockedEndpointData = mockEndpointResultList({ total: 5 }); const hostListData = mockedEndpointData.hosts; - const queryStrategyVersion = mockedEndpointData.query_strategy_version; firstPolicyID = hostListData[0].metadata.Endpoint.policy.applied.id; firstPolicyRev = hostListData[0].metadata.Endpoint.policy.applied.endpoint_policy_version; @@ -329,7 +302,6 @@ describe('when on the endpoint list page', () => { hostListData[index].metadata.Endpoint.policy.applied, setup.policy ), - query_strategy_version: queryStrategyVersion, }; }); hostListData.forEach((item, index) => { @@ -535,8 +507,6 @@ describe('when on the endpoint list page', () => { // eslint-disable-next-line @typescript-eslint/naming-convention host_status, metadata: { agent, Endpoint, ...details }, - // eslint-disable-next-line @typescript-eslint/naming-convention - query_strategy_version, } = mockEndpointDetailsApiResult(); hostDetails = { @@ -555,7 +525,6 @@ describe('when on the endpoint list page', () => { id: '1', }, }, - query_strategy_version, }; const policy = docGenerator.generatePolicyPackagePolicy(); @@ -1198,7 +1167,7 @@ describe('when on the endpoint list page', () => { let renderResult: ReturnType; const mockEndpointListApi = () => { - const { hosts, query_strategy_version: queryStrategyVersion } = mockEndpointResultList(); + const { hosts } = mockEndpointResultList(); hostInfo = { host_status: hosts[0].host_status, metadata: { @@ -1222,7 +1191,6 @@ describe('when on the endpoint list page', () => { version: '7.14.0', }, }, - query_strategy_version: queryStrategyVersion, }; const packagePolicy = docGenerator.generatePolicyPackagePolicy(); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx index 0ee345431055bb..c78d4ca6af634b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx @@ -120,7 +120,6 @@ export const EndpointList = () => { areEndpointsEnrolling, agentsWithEndpointsTotalError, endpointsTotalError, - isTransformEnabled, } = useEndpointSelector(selector); const { search } = useFormatUrl(SecurityPageName.administration); const { getAppUrl } = useAppUrl(); @@ -476,8 +475,8 @@ export const EndpointList = () => { const hasListData = listData && listData.length > 0; const refreshStyle = useMemo(() => { - return { display: endpointsExist && isTransformEnabled ? 'flex' : 'none', maxWidth: 200 }; - }, [endpointsExist, isTransformEnabled]); + return { display: endpointsExist ? 'flex' : 'none', maxWidth: 200 }; + }, [endpointsExist]); const refreshIsPaused = useMemo(() => { return !endpointsExist ? false : hasSelectedEndpoint ? true : !isAutoRefreshEnabled; @@ -492,8 +491,8 @@ export const EndpointList = () => { }, [endpointsTotalError, agentsWithEndpointsTotalError]); const shouldShowKQLBar = useMemo(() => { - return endpointsExist && !patternsError && isTransformEnabled; - }, [endpointsExist, patternsError, isTransformEnabled]); + return endpointsExist && !patternsError; + }, [endpointsExist, patternsError]); return ( { title={i18n.DANGER_TITLE} body={i18n.DANGER_BODY} button={ - + {i18n.DANGER_BUTTON} } diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx index 4565c16bc2bf65..b34f6e657d39a9 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx @@ -22,7 +22,6 @@ import { InspectButtonContainer } from '../../../common/components/inspect'; import { HeaderSection } from '../../../common/components/header_section'; import { ID as CTIEventCountQueryId } from '../../containers/overview_cti_links/use_cti_event_counts'; import { CtiListItem } from '../../containers/overview_cti_links/helpers'; -import { LinkButton } from '../../../common/components/links'; import { useKibana } from '../../../common/lib/kibana'; import { CtiInnerPanel } from './cti_inner_panel'; import * as i18n from './translations'; @@ -36,7 +35,7 @@ const DashboardLinkItems = styled(EuiFlexGroup)` `; const Title = styled(EuiFlexItem)` - min-width: 140px; + min-width: 110px; `; const List = styled.ul` @@ -45,12 +44,11 @@ const List = styled.ul` const DashboardRightSideElement = styled(EuiFlexItem)` align-items: flex-end; - max-width: 160px; `; const RightSideLink = styled(EuiLink)` text-align: right; - min-width: 140px; + min-width: 180px; `; interface ThreatIntelPanelViewProps { @@ -96,12 +94,12 @@ export const ThreatIntelPanelView: React.FC = ({ const button = useMemo( () => ( - + - + ), [buttonHref] ); @@ -117,7 +115,11 @@ export const ThreatIntelPanelView: React.FC = ({ color={'primary'} title={i18n.INFO_TITLE} body={i18n.INFO_BODY} - button={{i18n.INFO_BUTTON}} + button={ + + {i18n.INFO_BUTTON} + + } /> ) : null, [isDashboardPluginDisabled, threatIntelDashboardDocLink] @@ -149,9 +151,7 @@ export const ThreatIntelPanelView: React.FC = ({ gutterSize="l" justifyContent="spaceBetween" > - - {title} - + {title} = ({ alignItems="center" justifyContent="flexEnd" > - + {count} - + {path ? ( - {linkCopy} + + {linkCopy} + ) : ( {linkCopy} diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts index 663ec3a75c9025..91abd48eb2b7e8 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts @@ -51,9 +51,10 @@ export const DANGER_TITLE = i18n.translate( ); export const DANGER_BODY = i18n.translate( - 'xpack.securitySolution.overview.ctiDashboardDangerPanelBody', + 'xpack.securitySolution.overview.ctiDashboardEnableThreatIntel', { - defaultMessage: 'You need to enable module in order to view data from different sources.', + defaultMessage: + 'You need to enable the filebeat threatintel module in order to view data from different sources.', } ); diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index d8e7a813c37c3d..3ab0e6179f8425 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -20,7 +20,6 @@ import { SecurityPluginStart } from '../../../security/server'; import { AgentService, FleetStartContract, - PackageService, AgentPolicyServiceInterface, PackagePolicyServiceInterface, } from '../../../fleet/server'; @@ -30,14 +29,6 @@ import { getPackagePolicyUpdateCallback, } from '../fleet_integration/fleet_integration'; import { ManifestManager } from './services/artifacts'; -import { MetadataQueryStrategy } from './types'; -import { MetadataQueryStrategyVersions } from '../../common/endpoint/types'; -import { - metadataQueryStrategyV1, - metadataQueryStrategyV2, -} from './routes/metadata/support/query_strategies'; -import { ElasticsearchAssetType } from '../../../fleet/common/types/models'; -import { metadataTransformPrefix } from '../../common/endpoint/constants'; import { AppClientFactory } from '../client'; import { ConfigType } from '../config'; import { LicenseService } from '../../common/license'; @@ -46,45 +37,6 @@ import { parseExperimentalConfigValue, } from '../../common/experimental_features'; -export interface MetadataService { - queryStrategy( - savedObjectsClient: SavedObjectsClientContract, - version?: MetadataQueryStrategyVersions - ): Promise; -} - -export const createMetadataService = (packageService: PackageService): MetadataService => { - return { - async queryStrategy( - savedObjectsClient: SavedObjectsClientContract, - version?: MetadataQueryStrategyVersions - ): Promise { - if (version === MetadataQueryStrategyVersions.VERSION_1) { - return metadataQueryStrategyV1(); - } - if (!packageService) { - throw new Error('package service is uninitialized'); - } - - if (version === MetadataQueryStrategyVersions.VERSION_2 || !version) { - const assets = - (await packageService.getInstallation({ savedObjectsClient, pkgName: 'endpoint' })) - ?.installed_es ?? []; - const expectedTransformAssets = assets.filter( - (ref) => - ref.type === ElasticsearchAssetType.transform && - ref.id.startsWith(metadataTransformPrefix) - ); - if (expectedTransformAssets && expectedTransformAssets.length === 1) { - return metadataQueryStrategyV2(); - } - return metadataQueryStrategyV1(); - } - return metadataQueryStrategyV1(); - }, - }; -}; - export type EndpointAppContextServiceStartContract = Partial< Pick< FleetStartContract, @@ -114,7 +66,6 @@ export class EndpointAppContextService { private packagePolicyService: PackagePolicyServiceInterface | undefined; private agentPolicyService: AgentPolicyServiceInterface | undefined; private savedObjectsStart: SavedObjectsServiceStart | undefined; - private metadataService: MetadataService | undefined; private config: ConfigType | undefined; private license: LicenseService | undefined; public security: SecurityPluginStart | undefined; @@ -128,7 +79,6 @@ export class EndpointAppContextService { this.agentPolicyService = dependencies.agentPolicyService; this.manifestManager = dependencies.manifestManager; this.savedObjectsStart = dependencies.savedObjectsStart; - this.metadataService = createMetadataService(dependencies.packageService!); this.config = dependencies.config; this.license = dependencies.licenseService; this.security = dependencies.security; @@ -176,10 +126,6 @@ export class EndpointAppContextService { return this.agentPolicyService; } - public getMetadataService(): MetadataService | undefined { - return this.metadataService; - } - public getManifestManager(): ManifestManager | undefined { return this.manifestManager; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts index 45063ca92e2b0a..fceb45b17c2587 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts @@ -83,7 +83,7 @@ export const isolationRequestHandler = function ( // fetch the Agent IDs to send the commands to const endpointIDs = [...new Set(req.body.endpoint_ids)]; // dedupe - const endpointData = await getMetadataForEndpoints(endpointIDs, context, endpointContext); + const endpointData = await getMetadataForEndpoints(endpointIDs, context); const casesClient = await endpointContext.service.getCasesClient(req); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts index 960f3abda81956..39aa0bf2d8cf77 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { HostStatus, MetadataQueryStrategyVersions } from '../../../../common/endpoint/types'; +import { HostStatus } from '../../../../common/endpoint/types'; import { createMockMetadataRequestContext } from '../../mocks'; import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; import { enrichHostMetadata, MetadataRequestContext } from './handlers'; @@ -18,30 +18,6 @@ describe('test document enrichment', () => { metaReqCtx = createMockMetadataRequestContext(); }); - // verify query version passed through - describe('metadata query strategy enrichment', () => { - it('should match v1 strategy when directed', async () => { - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_1 - ); - expect(enrichedHostList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_1 - ); - }); - it('should match v2 strategy when directed', async () => { - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); - expect(enrichedHostList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_2 - ); - }); - }); - describe('host status enrichment', () => { let statusFn: jest.Mock; @@ -57,77 +33,49 @@ describe('test document enrichment', () => { it('should return host healthy for online agent', async () => { statusFn.mockImplementation(() => 'online'); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.host_status).toEqual(HostStatus.HEALTHY); }); it('should return host offline for offline agent', async () => { statusFn.mockImplementation(() => 'offline'); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.host_status).toEqual(HostStatus.OFFLINE); }); it('should return host updating for unenrolling agent', async () => { statusFn.mockImplementation(() => 'unenrolling'); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.host_status).toEqual(HostStatus.UPDATING); }); it('should return host unhealthy for degraded agent', async () => { statusFn.mockImplementation(() => 'degraded'); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); it('should return host unhealthy for erroring agent', async () => { statusFn.mockImplementation(() => 'error'); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); it('should return host unhealthy for warning agent', async () => { statusFn.mockImplementation(() => 'warning'); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); it('should return host unhealthy for invalid agent', async () => { statusFn.mockImplementation(() => 'asliduasofb'); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY); }); }); @@ -164,11 +112,7 @@ describe('test document enrichment', () => { }; }); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.policy_info).toBeDefined(); expect(enrichedHostList.policy_info!.agent.applied.id).toEqual(policyID); expect(enrichedHostList.policy_info!.agent.applied.revision).toEqual(policyRev); @@ -184,11 +128,7 @@ describe('test document enrichment', () => { }; }); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.policy_info).toBeDefined(); expect(enrichedHostList.policy_info!.agent.configured.id).toEqual(policyID); expect(enrichedHostList.policy_info!.agent.configured.revision).toEqual(policyRev); @@ -209,11 +149,7 @@ describe('test document enrichment', () => { }; }); - const enrichedHostList = await enrichHostMetadata( - docGen.generateHostMetadata(), - metaReqCtx, - MetadataQueryStrategyVersions.VERSION_2 - ); + const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx); expect(enrichedHostList.policy_info).toBeDefined(); expect(enrichedHostList.policy_info!.endpoint.id).toEqual(policyID); expect(enrichedHostList.policy_info!.endpoint.revision).toEqual(policyRev); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts index 815f30e6e7426f..2ceca170881e32 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts @@ -17,10 +17,8 @@ import { import { HostInfo, HostMetadata, - HostMetadataInfo, HostResultList, HostStatus, - MetadataQueryStrategyVersions, } from '../../../../common/endpoint/types'; import type { SecuritySolutionRequestHandlerContext } from '../../../types'; @@ -33,6 +31,10 @@ import { findAllUnenrolledAgentIds } from './support/unenroll'; import { findAgentIDsByStatus } from './support/agent_status'; import { EndpointAppContextService } from '../../endpoint_app_context_services'; import { fleetAgentStatusToEndpointHostStatus } from '../../utils'; +import { + queryResponseToHostListResult, + queryResponseToHostResult, +} from './support/query_strategies'; export interface MetadataRequestContext { esClient?: IScopedClusterClient; @@ -58,8 +60,7 @@ export const getLogger = (endpointAppContext: EndpointAppContext): Logger => { export const getMetadataListRequestHandler = function ( endpointAppContext: EndpointAppContext, - logger: Logger, - queryStrategyVersion?: MetadataQueryStrategyVersions + logger: Logger ): RequestHandler< unknown, unknown, @@ -96,24 +97,15 @@ export const getMetadataListRequestHandler = function ( ) : undefined; - const queryStrategy = await endpointAppContext.service - ?.getMetadataService() - ?.queryStrategy(context.core.savedObjects.client, queryStrategyVersion); - - const queryParams = await kibanaRequestToMetadataListESQuery( - request, - endpointAppContext, - queryStrategy!, - { - unenrolledAgentIds: unenrolledAgentIds.concat(IGNORED_ELASTIC_AGENT_IDS), - statusAgentIDs: statusIDs, - } - ); + const queryParams = await kibanaRequestToMetadataListESQuery(request, endpointAppContext, { + unenrolledAgentIds: unenrolledAgentIds.concat(IGNORED_ELASTIC_AGENT_IDS), + statusAgentIDs: statusIDs, + }); const result = await context.core.elasticsearch.client.asCurrentUser.search( queryParams ); - const hostListQueryResult = queryStrategy!.queryResponseToHostListResult(result.body); + const hostListQueryResult = queryResponseToHostListResult(result.body); return response.ok({ body: await mapToHostResultList(queryParams, hostListQueryResult, metadataRequestContext), }); @@ -122,8 +114,7 @@ export const getMetadataListRequestHandler = function ( export const getMetadataRequestHandler = function ( endpointAppContext: EndpointAppContext, - logger: Logger, - queryStrategyVersion?: MetadataQueryStrategyVersions + logger: Logger ): RequestHandler< TypeOf, unknown, @@ -145,11 +136,7 @@ export const getMetadataRequestHandler = function ( }; try { - const doc = await getHostData( - metadataRequestContext, - request?.params?.id, - queryStrategyVersion - ); + const doc = await getHostData(metadataRequestContext, request?.params?.id); if (doc) { return response.ok({ body: doc }); } @@ -169,9 +156,8 @@ export const getMetadataRequestHandler = function ( export async function getHostMetaData( metadataRequestContext: MetadataRequestContext, - id: string, - queryStrategyVersion?: MetadataQueryStrategyVersions -): Promise { + id: string +): Promise { if ( !metadataRequestContext.esClient && !metadataRequestContext.requestHandlerContext?.core.elasticsearch.client @@ -190,32 +176,23 @@ export async function getHostMetaData( metadataRequestContext.requestHandlerContext?.core.elasticsearch .client) as IScopedClusterClient; - const esSavedObjectClient = - metadataRequestContext?.savedObjectsClient ?? - (metadataRequestContext.requestHandlerContext?.core.savedObjects - .client as SavedObjectsClientContract); - - const queryStrategy = await metadataRequestContext.endpointAppContextService - ?.getMetadataService() - ?.queryStrategy(esSavedObjectClient, queryStrategyVersion); - const query = getESQueryHostMetadataByID(id, queryStrategy!); + const query = getESQueryHostMetadataByID(id); const response = await esClient.asCurrentUser.search(query); - const hostResult = queryStrategy!.queryResponseToHostResult(response.body); + const hostResult = queryResponseToHostResult(response.body); const hostMetadata = hostResult.result; if (!hostMetadata) { return undefined; } - return { metadata: hostMetadata, query_strategy_version: hostResult.queryStrategyVersion }; + return hostMetadata; } export async function getHostData( metadataRequestContext: MetadataRequestContext, - id: string, - queryStrategyVersion?: MetadataQueryStrategyVersions + id: string ): Promise { if (!metadataRequestContext.savedObjectsClient) { throw Boom.badRequest('savedObjectsClient not found'); @@ -228,25 +205,21 @@ export async function getHostData( throw Boom.badRequest('esClient not found'); } - const hostResult = await getHostMetaData(metadataRequestContext, id, queryStrategyVersion); + const hostMetadata = await getHostMetaData(metadataRequestContext, id); - if (!hostResult) { + if (!hostMetadata) { return undefined; } - const agent = await findAgent(metadataRequestContext, hostResult.metadata); + const agent = await findAgent(metadataRequestContext, hostMetadata); if (agent && !agent.active) { throw Boom.badRequest('the requested endpoint is unenrolled'); } - const metadata = await enrichHostMetadata( - hostResult.metadata, - metadataRequestContext, - hostResult.query_strategy_version - ); + const metadata = await enrichHostMetadata(hostMetadata, metadataRequestContext); - return { ...metadata, query_strategy_version: hostResult.query_strategy_version }; + return metadata; } async function findAgent( @@ -293,15 +266,10 @@ export async function mapToHostResultList( request_page_index: queryParams.from, hosts: await Promise.all( hostListQueryResult.resultList.map(async (entry) => - enrichHostMetadata( - entry, - metadataRequestContext, - hostListQueryResult.queryStrategyVersion - ) + enrichHostMetadata(entry, metadataRequestContext) ) ), total: totalNumberOfHosts, - query_strategy_version: hostListQueryResult.queryStrategyVersion, }; } else { return { @@ -309,15 +277,13 @@ export async function mapToHostResultList( request_page_index: queryParams.from, total: totalNumberOfHosts, hosts: [], - query_strategy_version: hostListQueryResult.queryStrategyVersion, }; } } export async function enrichHostMetadata( hostMetadata: HostMetadata, - metadataRequestContext: MetadataRequestContext, - metadataQueryStrategyVersion: MetadataQueryStrategyVersions + metadataRequestContext: MetadataRequestContext ): Promise { let hostStatus = HostStatus.UNHEALTHY; let elasticAgentId = hostMetadata?.elastic?.agent?.id; @@ -413,6 +379,5 @@ export async function enrichHostMetadata( metadata: hostMetadata, host_status: hostStatus, policy_info: policyInfo, - query_strategy_version: metadataQueryStrategyVersion, }; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts index b4784c1ff5ed40..d9c3e6c195307d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts @@ -7,19 +7,15 @@ import { schema } from '@kbn/config-schema'; -import { HostStatus, MetadataQueryStrategyVersions } from '../../../../common/endpoint/types'; +import { HostStatus } from '../../../../common/endpoint/types'; import { EndpointAppContext } from '../../types'; import { getLogger, getMetadataListRequestHandler, getMetadataRequestHandler } from './handlers'; import type { SecuritySolutionPluginRouter } from '../../../types'; import { - BASE_ENDPOINT_ROUTE, HOST_METADATA_GET_ROUTE, HOST_METADATA_LIST_ROUTE, } from '../../../../common/endpoint/constants'; -export const METADATA_REQUEST_V1_ROUTE = `${BASE_ENDPOINT_ROUTE}/v1/metadata`; -export const GET_METADATA_REQUEST_V1_ROUTE = `${METADATA_REQUEST_V1_ROUTE}/{id}`; - /* Filters that can be applied to the endpoint fetch route */ export const endpointFilters = schema.object({ kql: schema.nullable(schema.string()), @@ -69,18 +65,6 @@ export function registerEndpointRoutes( endpointAppContext: EndpointAppContext ) { const logger = getLogger(endpointAppContext); - router.post( - { - path: `${METADATA_REQUEST_V1_ROUTE}`, - validate: GetMetadataListRequestSchema, - options: { authRequired: true, tags: ['access:securitySolution'] }, - }, - getMetadataListRequestHandler( - endpointAppContext, - logger, - MetadataQueryStrategyVersions.VERSION_1 - ) - ); router.post( { @@ -91,15 +75,6 @@ export function registerEndpointRoutes( getMetadataListRequestHandler(endpointAppContext, logger) ); - router.get( - { - path: `${GET_METADATA_REQUEST_V1_ROUTE}`, - validate: GetMetadataRequestSchema, - options: { authRequired: true, tags: ['access:securitySolution'] }, - }, - getMetadataRequestHandler(endpointAppContext, logger, MetadataQueryStrategyVersions.VERSION_1) - ); - router.get( { path: `${HOST_METADATA_GET_ROUTE}`, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts index 5250f7c49d6ade..1e56f79aa0b324 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts @@ -19,12 +19,7 @@ import { loggingSystemMock, savedObjectsClientMock, } from '../../../../../../../src/core/server/mocks'; -import { - HostInfo, - HostResultList, - HostStatus, - MetadataQueryStrategyVersions, -} from '../../../../common/endpoint/types'; +import { HostInfo, HostResultList, HostStatus } from '../../../../common/endpoint/types'; import { parseExperimentalConfigValue } from '../../../../common/experimental_features'; import { registerEndpointRoutes } from './index'; import { @@ -39,7 +34,7 @@ import { import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__'; import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; import { Agent, ElasticsearchAssetType } from '../../../../../fleet/common/types/models'; -import { createV1SearchResponse, createV2SearchResponse } from './support/test_support'; +import { createV2SearchResponse } from './support/test_support'; import { PackageService } from '../../../../../fleet/server/services'; import { HOST_METADATA_LIST_ROUTE, @@ -98,94 +93,6 @@ describe('test endpoint route', () => { ); }); - describe('with no transform package', () => { - beforeEach(() => { - endpointAppContextService = new EndpointAppContextService(); - mockPackageService = createMockPackageService(); - mockPackageService.getInstallation.mockReturnValue(Promise.resolve(undefined)); - endpointAppContextService.start({ ...startContract, packageService: mockPackageService }); - mockAgentService = startContract.agentService!; - - registerEndpointRoutes(routerMock, { - logFactory: loggingSystemMock.create(), - service: endpointAppContextService, - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }); - }); - - afterEach(() => endpointAppContextService.stop()); - - it('test find the latest of all endpoints', async () => { - const mockRequest = httpServerMock.createKibanaRequest({}); - const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: response }) - ); - [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => - path.startsWith(`${HOST_METADATA_LIST_ROUTE}`) - )!; - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); - mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent); - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(routeConfig.options).toEqual({ - authRequired: true, - tags: ['access:securitySolution'], - }); - expect(mockResponse.ok).toBeCalled(); - const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList; - expect(endpointResultList.hosts.length).toEqual(1); - expect(endpointResultList.total).toEqual(1); - expect(endpointResultList.request_page_index).toEqual(0); - expect(endpointResultList.request_page_size).toEqual(10); - expect(endpointResultList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_1 - ); - }); - - it('should return a single endpoint with status healthy', async () => { - const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); - const mockRequest = httpServerMock.createKibanaRequest({ - params: { id: response.hits.hits[0]._id }, - }); - - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('online'); - mockAgentService.getAgent = jest.fn().mockReturnValue(({ - active: true, - } as unknown) as Agent); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: response }) - ); - - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => - path.startsWith(`${HOST_METADATA_LIST_ROUTE}`) - )!; - - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(routeConfig.options).toEqual({ - authRequired: true, - tags: ['access:securitySolution'], - }); - expect(mockResponse.ok).toBeCalled(); - const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result).toHaveProperty('metadata.Endpoint'); - expect(result.host_status).toEqual(HostStatus.HEALTHY); - expect(result.query_strategy_version).toEqual(MetadataQueryStrategyVersions.VERSION_1); - }); - }); - describe('with new transform package', () => { beforeEach(() => { endpointAppContextService = new EndpointAppContextService(); @@ -254,9 +161,6 @@ describe('test endpoint route', () => { expect(endpointResultList.total).toEqual(1); expect(endpointResultList.request_page_index).toEqual(0); expect(endpointResultList.request_page_size).toEqual(10); - expect(endpointResultList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_2 - ); }); it('test find the latest of all endpoints with paging properties', async () => { @@ -311,9 +215,6 @@ describe('test endpoint route', () => { expect(endpointResultList.total).toEqual(1); expect(endpointResultList.request_page_index).toEqual(10); expect(endpointResultList.request_page_size).toEqual(10); - expect(endpointResultList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_2 - ); }); it('test find the latest of all endpoints with paging and filters properties', async () => { @@ -405,9 +306,6 @@ describe('test endpoint route', () => { expect(endpointResultList.total).toEqual(1); expect(endpointResultList.request_page_index).toEqual(10); expect(endpointResultList.request_page_size).toEqual(10); - expect(endpointResultList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_2 - ); }); describe('Endpoint Details route', () => { @@ -475,7 +373,6 @@ describe('test endpoint route', () => { const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; expect(result).toHaveProperty('metadata.Endpoint'); expect(result.host_status).toEqual(HostStatus.HEALTHY); - expect(result.query_strategy_version).toEqual(MetadataQueryStrategyVersions.VERSION_2); }); it('should return a single endpoint with status unhealthy when AgentService throw 404', async () => { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts deleted file mode 100644 index 29b2c231cc4a57..00000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts +++ /dev/null @@ -1,456 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - KibanaResponseFactory, - RequestHandler, - RouteConfig, - SavedObjectsClientContract, - SavedObjectsErrorHelpers, -} from '../../../../../../../src/core/server'; -import { - ClusterClientMock, - ScopedClusterClientMock, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../src/core/server/elasticsearch/client/mocks'; -import { - elasticsearchServiceMock, - httpServerMock, - httpServiceMock, - loggingSystemMock, - savedObjectsClientMock, -} from '../../../../../../../src/core/server/mocks'; -import { - HostInfo, - HostResultList, - HostStatus, - MetadataQueryStrategyVersions, -} from '../../../../common/endpoint/types'; -import { registerEndpointRoutes, METADATA_REQUEST_V1_ROUTE } from './index'; -import { - createMockEndpointAppContextServiceStartContract, - createMockPackageService, - createRouteHandlerContext, -} from '../../mocks'; -import { - EndpointAppContextService, - EndpointAppContextServiceStartContract, -} from '../../endpoint_app_context_services'; -import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__'; -import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; -import { parseExperimentalConfigValue } from '../../../../common/experimental_features'; -import { Agent } from '../../../../../fleet/common/types/models'; -import { createV1SearchResponse } from './support/test_support'; -import { PackageService } from '../../../../../fleet/server/services'; -import type { SecuritySolutionPluginRouter } from '../../../types'; -import { PackagePolicyServiceInterface } from '../../../../../fleet/server'; - -describe('test endpoint route v1', () => { - let routerMock: jest.Mocked; - let mockResponse: jest.Mocked; - let mockClusterClient: ClusterClientMock; - let mockScopedClient: ScopedClusterClientMock; - let mockSavedObjectClient: jest.Mocked; - let mockPackageService: jest.Mocked; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let routeHandler: RequestHandler; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let routeConfig: RouteConfig; - // tests assume that fleet is enabled, and thus agentService is available - let mockAgentService: Required< - ReturnType - >['agentService']; - let endpointAppContextService: EndpointAppContextService; - let startContract: EndpointAppContextServiceStartContract; - const noUnenrolledAgent = { - agents: [], - total: 0, - page: 1, - perPage: 1, - }; - - beforeEach(() => { - mockClusterClient = elasticsearchServiceMock.createClusterClient(); - mockScopedClient = elasticsearchServiceMock.createScopedClusterClient(); - mockSavedObjectClient = savedObjectsClientMock.create(); - mockClusterClient.asScoped.mockReturnValue(mockScopedClient); - routerMock = httpServiceMock.createRouter(); - mockResponse = httpServerMock.createResponseFactory(); - endpointAppContextService = new EndpointAppContextService(); - mockPackageService = createMockPackageService(); - mockPackageService.getInstallation.mockReturnValue(Promise.resolve(undefined)); - startContract = createMockEndpointAppContextServiceStartContract(); - endpointAppContextService.start({ ...startContract, packageService: mockPackageService }); - mockAgentService = startContract.agentService!; - - (startContract.packagePolicyService as jest.Mocked).list.mockImplementation( - () => { - return Promise.resolve({ - items: [], - total: 0, - page: 1, - perPage: 1000, - }); - } - ); - - registerEndpointRoutes(routerMock, { - logFactory: loggingSystemMock.create(), - service: endpointAppContextService, - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }); - }); - - afterEach(() => endpointAppContextService.stop()); - - it('test find the latest of all endpoints', async () => { - const mockRequest = httpServerMock.createKibanaRequest({}); - const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: response }) - ); - [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); - mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent); - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(routeConfig.options).toEqual({ authRequired: true, tags: ['access:securitySolution'] }); - expect(mockResponse.ok).toBeCalled(); - const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList; - expect(endpointResultList.hosts.length).toEqual(1); - expect(endpointResultList.total).toEqual(1); - expect(endpointResultList.request_page_index).toEqual(0); - expect(endpointResultList.request_page_size).toEqual(10); - expect(endpointResultList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_1 - ); - }); - - it('test find the latest of all endpoints with paging properties', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - body: { - paging_properties: [ - { - page_size: 10, - }, - { - page_index: 1, - }, - ], - }, - }); - - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); - mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ - body: createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()), - }) - ); - [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect( - (mockScopedClient.asCurrentUser.search as jest.Mock).mock.calls[0][0]?.body?.query.bool - .must_not - ).toContainEqual({ - terms: { - 'elastic.agent.id': [ - '00000000-0000-0000-0000-000000000000', - '11111111-1111-1111-1111-111111111111', - ], - }, - }); - expect(routeConfig.options).toEqual({ authRequired: true, tags: ['access:securitySolution'] }); - expect(mockResponse.ok).toBeCalled(); - const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList; - expect(endpointResultList.hosts.length).toEqual(1); - expect(endpointResultList.total).toEqual(1); - expect(endpointResultList.request_page_index).toEqual(10); - expect(endpointResultList.request_page_size).toEqual(10); - expect(endpointResultList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_1 - ); - }); - - it('test find the latest of all endpoints with paging and filters properties', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - body: { - paging_properties: [ - { - page_size: 10, - }, - { - page_index: 1, - }, - ], - - filters: { kql: 'not host.ip:10.140.73.246' }, - }, - }); - - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); - mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ - body: createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()), - }) - ); - [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toBeCalled(); - // needs to have the KQL filter passed through - expect( - (mockScopedClient.asCurrentUser.search as jest.Mock).mock.calls[0][0]?.body?.query.bool.must - ).toContainEqual({ - bool: { - must_not: { - bool: { - should: [ - { - match: { - 'host.ip': '10.140.73.246', - }, - }, - ], - minimum_should_match: 1, - }, - }, - }, - }); - // and unenrolled should be filtered out. - expect( - (mockScopedClient.asCurrentUser.search as jest.Mock).mock.calls[0][0]?.body?.query.bool.must - ).toContainEqual({ - bool: { - must_not: [ - { - terms: { - 'elastic.agent.id': [ - '00000000-0000-0000-0000-000000000000', - '11111111-1111-1111-1111-111111111111', - ], - }, - }, - { - terms: { - // we actually don't care about HostDetails in v1 queries, but - // harder to set up the expectation to ignore its inclusion succinctly - 'HostDetails.elastic.agent.id': [ - '00000000-0000-0000-0000-000000000000', - '11111111-1111-1111-1111-111111111111', - ], - }, - }, - ], - }, - }); - expect(routeConfig.options).toEqual({ authRequired: true, tags: ['access:securitySolution'] }); - expect(mockResponse.ok).toBeCalled(); - const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList; - expect(endpointResultList.hosts.length).toEqual(1); - expect(endpointResultList.total).toEqual(1); - expect(endpointResultList.request_page_index).toEqual(10); - expect(endpointResultList.request_page_size).toEqual(10); - expect(endpointResultList.query_strategy_version).toEqual( - MetadataQueryStrategyVersions.VERSION_1 - ); - }); - - describe('Endpoint Details route', () => { - it('should return 404 on no results', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ params: { id: 'BADID' } }); - - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: createV1SearchResponse() }) - ); - - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error'); - mockAgentService.getAgent = jest.fn().mockReturnValue(({ - active: true, - } as unknown) as Agent); - - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(routeConfig.options).toEqual({ - authRequired: true, - tags: ['access:securitySolution'], - }); - expect(mockResponse.notFound).toBeCalled(); - const message = mockResponse.notFound.mock.calls[0][0]?.body; - expect(message).toEqual('Endpoint Not Found'); - }); - - it('should return a single endpoint with status healthy', async () => { - const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); - const mockRequest = httpServerMock.createKibanaRequest({ - params: { id: response.hits.hits[0]._id }, - }); - - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('online'); - mockAgentService.getAgent = jest.fn().mockReturnValue(({ - active: true, - } as unknown) as Agent); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: response }) - ); - - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(routeConfig.options).toEqual({ - authRequired: true, - tags: ['access:securitySolution'], - }); - expect(mockResponse.ok).toBeCalled(); - const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result).toHaveProperty('metadata.Endpoint'); - expect(result.host_status).toEqual(HostStatus.HEALTHY); - }); - - it('should return a single endpoint with status unhealthy when AgentService throw 404', async () => { - const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); - - const mockRequest = httpServerMock.createKibanaRequest({ - params: { id: response.hits.hits[0]._id }, - }); - - mockAgentService.getAgentStatusById = jest.fn().mockImplementation(() => { - SavedObjectsErrorHelpers.createGenericNotFoundError(); - }); - - mockAgentService.getAgent = jest.fn().mockImplementation(() => { - SavedObjectsErrorHelpers.createGenericNotFoundError(); - }); - - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: response }) - ); - - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(routeConfig.options).toEqual({ - authRequired: true, - tags: ['access:securitySolution'], - }); - expect(mockResponse.ok).toBeCalled(); - const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result.host_status).toEqual(HostStatus.UNHEALTHY); - }); - - it('should return a single endpoint with status unhealthy when status is not offline, online or enrolling', async () => { - const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); - - const mockRequest = httpServerMock.createKibanaRequest({ - params: { id: response.hits.hits[0]._id }, - }); - - mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('warning'); - mockAgentService.getAgent = jest.fn().mockReturnValue(({ - active: true, - } as unknown) as Agent); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: response }) - ); - - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(routeConfig.options).toEqual({ - authRequired: true, - tags: ['access:securitySolution'], - }); - expect(mockResponse.ok).toBeCalled(); - const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo; - expect(result.host_status).toEqual(HostStatus.UNHEALTHY); - }); - - it('should throw error when endpoint agent is not active', async () => { - const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()); - - const mockRequest = httpServerMock.createKibanaRequest({ - params: { id: response.hits.hits[0]._id }, - }); - (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ body: response }) - ); - mockAgentService.getAgent = jest.fn().mockReturnValue(({ - active: false, - } as unknown) as Agent); - - [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) => - path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`) - )!; - - await routeHandler( - createRouteHandlerContext(mockScopedClient, mockSavedObjectClient), - mockRequest, - mockResponse - ); - - expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1); - expect(mockResponse.customError).toBeCalled(); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts index e790c1de1a5b8e..87de5a540ea991 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts @@ -11,38 +11,29 @@ import { EndpointAppContextService } from '../../endpoint_app_context_services'; import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__'; import { metadataCurrentIndexPattern } from '../../../../common/endpoint/constants'; import { parseExperimentalConfigValue } from '../../../../common/experimental_features'; -import { metadataQueryStrategyV2 } from './support/query_strategies'; import { get } from 'lodash'; describe('query builder', () => { describe('MetadataListESQuery', () => { it('queries the correct index', async () => { const mockRequest = httpServerMock.createKibanaRequest({ body: {} }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }, - metadataQueryStrategyV2() - ); + const query = await kibanaRequestToMetadataListESQuery(mockRequest, { + logFactory: loggingSystemMock.create(), + service: new EndpointAppContextService(), + config: () => Promise.resolve(createMockConfig()), + experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), + }); expect(query.index).toEqual(metadataCurrentIndexPattern); }); it('sorts using *event.created', async () => { const mockRequest = httpServerMock.createKibanaRequest({ body: {} }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }, - metadataQueryStrategyV2() - ); + const query = await kibanaRequestToMetadataListESQuery(mockRequest, { + logFactory: loggingSystemMock.create(), + service: new EndpointAppContextService(), + config: () => Promise.resolve(createMockConfig()), + experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), + }); expect(query.body.sort).toContainEqual({ 'event.created': { order: 'desc', @@ -61,16 +52,12 @@ describe('query builder', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: {}, }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }, - metadataQueryStrategyV2() - ); + const query = await kibanaRequestToMetadataListESQuery(mockRequest, { + logFactory: loggingSystemMock.create(), + service: new EndpointAppContextService(), + config: () => Promise.resolve(createMockConfig()), + experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), + }); expect(query.body.query).toHaveProperty('match_all'); }); @@ -87,7 +74,6 @@ describe('query builder', () => { config: () => Promise.resolve(createMockConfig()), experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), }, - metadataQueryStrategyV2(), { unenrolledAgentIds: [unenrolledElasticAgentId], } @@ -111,16 +97,12 @@ describe('query builder', () => { filters: { kql: 'not host.ip:10.140.73.246' }, }, }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }, - metadataQueryStrategyV2() - ); + const query = await kibanaRequestToMetadataListESQuery(mockRequest, { + logFactory: loggingSystemMock.create(), + service: new EndpointAppContextService(), + config: () => Promise.resolve(createMockConfig()), + experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), + }); expect(query.body.query.bool.must).toContainEqual({ bool: { @@ -160,7 +142,6 @@ describe('query builder', () => { createMockConfig().enableExperimental ), }, - metadataQueryStrategyV2(), { unenrolledAgentIds: [unenrolledElasticAgentId], } @@ -197,13 +178,13 @@ describe('query builder', () => { describe('MetadataGetQuery', () => { it('searches the correct index', () => { - const query = getESQueryHostMetadataByID('nonsense-id', metadataQueryStrategyV2()); + const query = getESQueryHostMetadataByID('nonsense-id'); expect(query.index).toEqual(metadataCurrentIndexPattern); }); it('searches for the correct ID', () => { const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899'; - const query = getESQueryHostMetadataByID(mockID, metadataQueryStrategyV2()); + const query = getESQueryHostMetadataByID(mockID); expect(get(query, 'body.query.bool.filter.0.bool.should')).toContainEqual({ term: { 'agent.id': mockID }, @@ -212,7 +193,7 @@ describe('query builder', () => { it('supports HostDetails in schema for backwards compat', () => { const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899'; - const query = getESQueryHostMetadataByID(mockID, metadataQueryStrategyV2()); + const query = getESQueryHostMetadataByID(mockID); expect(get(query, 'body.query.bool.filter.0.bool.should')).toContainEqual({ term: { 'HostDetails.agent.id': mockID }, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts index f0950e5fb79ba7..99ec1d10227472 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts @@ -6,9 +6,10 @@ */ import type { estypes } from '@elastic/elasticsearch'; +import { metadataCurrentIndexPattern } from '../../../../common/endpoint/constants'; import { KibanaRequest } from '../../../../../../../src/core/server'; import { esKuery } from '../../../../../../../src/plugins/data/server'; -import { EndpointAppContext, MetadataQueryStrategy } from '../../types'; +import { EndpointAppContext } from '../../types'; export interface QueryBuilderOptions { unenrolledAgentIds?: string[]; @@ -39,7 +40,6 @@ export async function kibanaRequestToMetadataListESQuery( // eslint-disable-next-line @typescript-eslint/no-explicit-any request: KibanaRequest, endpointAppContext: EndpointAppContext, - metadataQueryStrategy: MetadataQueryStrategy, queryBuilderOptions?: QueryBuilderOptions // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Promise> { @@ -49,16 +49,15 @@ export async function kibanaRequestToMetadataListESQuery( body: { query: buildQueryBody( request, - metadataQueryStrategy, queryBuilderOptions?.unenrolledAgentIds!, queryBuilderOptions?.statusAgentIDs! ), - ...metadataQueryStrategy.extraBodyProperties, + track_total_hits: true, sort: MetadataSortMethod, }, from: pagingProperties.pageIndex * pagingProperties.pageSize, size: pagingProperties.pageSize, - index: metadataQueryStrategy.index, + index: metadataCurrentIndexPattern, }; } @@ -86,7 +85,6 @@ async function getPagingProperties( function buildQueryBody( // eslint-disable-next-line @typescript-eslint/no-explicit-any request: KibanaRequest, - metadataQueryStrategy: MetadataQueryStrategy, unerolledAgentIds: string[] | undefined, statusAgentIDs: string[] | undefined // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -144,10 +142,7 @@ function buildQueryBody( }; } -export function getESQueryHostMetadataByID( - agentID: string, - metadataQueryStrategy: MetadataQueryStrategy -): estypes.SearchRequest { +export function getESQueryHostMetadataByID(agentID: string): estypes.SearchRequest { return { body: { query: { @@ -167,14 +162,11 @@ export function getESQueryHostMetadataByID( sort: MetadataSortMethod, size: 1, }, - index: metadataQueryStrategy.index, + index: metadataCurrentIndexPattern, }; } -export function getESQueryHostMetadataByIDs( - agentIDs: string[], - metadataQueryStrategy: MetadataQueryStrategy -) { +export function getESQueryHostMetadataByIDs(agentIDs: string[]) { return { body: { query: { @@ -193,6 +185,6 @@ export function getESQueryHostMetadataByIDs( }, sort: MetadataSortMethod, }, - index: metadataQueryStrategy.index, + index: metadataCurrentIndexPattern, }; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders_v1.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders_v1.test.ts deleted file mode 100644 index c18c585cd3d34b..00000000000000 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders_v1.test.ts +++ /dev/null @@ -1,188 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { httpServerMock, loggingSystemMock } from '../../../../../../../src/core/server/mocks'; -import { kibanaRequestToMetadataListESQuery, getESQueryHostMetadataByID } from './query_builders'; -import { EndpointAppContextService } from '../../endpoint_app_context_services'; -import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__'; -import { metadataIndexPattern } from '../../../../common/endpoint/constants'; -import { parseExperimentalConfigValue } from '../../../../common/experimental_features'; -import { metadataQueryStrategyV1 } from './support/query_strategies'; -import { get } from 'lodash'; - -describe('query builder v1', () => { - describe('MetadataListESQuery', () => { - it('test default query params for all endpoints metadata when no params or body is provided', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - body: {}, - }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }, - metadataQueryStrategyV1() - ); - - expect(query.body.query).toHaveProperty('match_all'); // no filtering - expect(query.body.collapse).toEqual({ - field: 'agent.id', - inner_hits: { - name: 'most_recent', - size: 1, - sort: [{ 'event.created': 'desc' }], - }, - }); - expect(query.body.aggs).toEqual({ - total: { - cardinality: { - field: 'agent.id', - }, - }, - }); - expect(query.index).toEqual(metadataIndexPattern); - }); - - it( - 'test default query params for all endpoints metadata when no params or body is provided ' + - 'with unenrolled host ids excluded', - async () => { - const unenrolledElasticAgentId = '1fdca33f-799f-49f4-939c-ea4383c77672'; - const mockRequest = httpServerMock.createKibanaRequest({ - body: {}, - }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue( - createMockConfig().enableExperimental - ), - }, - metadataQueryStrategyV1(), - { - unenrolledAgentIds: [unenrolledElasticAgentId], - } - ); - expect(Object.keys(query.body.query.bool)).toEqual(['must_not']); // only filtering out unenrolled - expect(query.body.query.bool.must_not).toContainEqual({ - terms: { 'elastic.agent.id': [unenrolledElasticAgentId] }, - }); - } - ); - }); - - describe('test query builder with kql filter', () => { - it('test default query params for all endpoints metadata when body filter is provided', async () => { - const mockRequest = httpServerMock.createKibanaRequest({ - body: { - filters: { kql: 'not host.ip:10.140.73.246' }, - }, - }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental), - }, - metadataQueryStrategyV1() - ); - expect(query.body.query.bool.must).toHaveLength(1); // should not be any other filtering happening - expect(query.body.query.bool.must).toContainEqual({ - bool: { - must_not: { - bool: { - should: [ - { - match: { - 'host.ip': '10.140.73.246', - }, - }, - ], - minimum_should_match: 1, - }, - }, - }, - }); - }); - - it( - 'test default query params for all endpoints endpoint metadata excluding unerolled endpoint ' + - 'and when body filter is provided', - async () => { - const unenrolledElasticAgentId = '1fdca33f-799f-49f4-939c-ea4383c77672'; - const mockRequest = httpServerMock.createKibanaRequest({ - body: { - filters: { kql: 'not host.ip:10.140.73.246' }, - }, - }); - const query = await kibanaRequestToMetadataListESQuery( - mockRequest, - { - logFactory: loggingSystemMock.create(), - service: new EndpointAppContextService(), - config: () => Promise.resolve(createMockConfig()), - experimentalFeatures: parseExperimentalConfigValue( - createMockConfig().enableExperimental - ), - }, - metadataQueryStrategyV1(), - { - unenrolledAgentIds: [unenrolledElasticAgentId], - } - ); - - expect(query.body.query.bool.must.length).toBeGreaterThan(1); - // unenrollment filter should be there - expect(query.body.query.bool.must).toContainEqual({ - bool: { - must_not: [ - { terms: { 'elastic.agent.id': [unenrolledElasticAgentId] } }, - // below is not actually necessary behavior for v1, but hard to structure the test to ignore it - { terms: { 'HostDetails.elastic.agent.id': [unenrolledElasticAgentId] } }, - ], - }, - }); - // and KQL should also be there - expect(query.body.query.bool.must).toContainEqual({ - bool: { - must_not: { - bool: { - should: [ - { - match: { - 'host.ip': '10.140.73.246', - }, - }, - ], - minimum_should_match: 1, - }, - }, - }, - }); - } - ); - }); - - describe('MetadataGetQuery', () => { - it('searches for the correct ID', () => { - const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899'; - const query = getESQueryHostMetadataByID(mockID, metadataQueryStrategyV1()); - - expect(get(query, 'body.query.bool.filter.0.bool.should')).toContainEqual({ - term: { 'agent.id': mockID }, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts index 506c02fc2f1ec1..2d7bff4a53f3f0 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts @@ -6,102 +6,39 @@ */ import { SearchResponse } from '@elastic/elasticsearch/api/types'; -import { - metadataCurrentIndexPattern, - metadataIndexPattern, -} from '../../../../../common/endpoint/constants'; -import { HostMetadata, MetadataQueryStrategyVersions } from '../../../../../common/endpoint/types'; -import { HostListQueryResult, HostQueryResult, MetadataQueryStrategy } from '../../../types'; +import { HostMetadata } from '../../../../../common/endpoint/types'; +import { HostListQueryResult, HostQueryResult } from '../../../types'; -export function metadataQueryStrategyV1(): MetadataQueryStrategy { - return { - index: metadataIndexPattern, - extraBodyProperties: { - collapse: { - field: 'agent.id', - inner_hits: { - name: 'most_recent', - size: 1, - sort: [{ 'event.created': 'desc' }], - }, - }, - aggs: { - total: { - cardinality: { - field: 'agent.id', - }, - }, - }, - }, - queryResponseToHostListResult: ( - searchResponse: SearchResponse - ): HostListQueryResult => { - const response = searchResponse as SearchResponse; - return { - resultLength: - ((response?.aggregations?.total as unknown) as { value?: number; relation: string }) - ?.value || 0, - resultList: response.hits.hits - .map((hit) => hit.inner_hits?.most_recent.hits.hits) - .flatMap((data) => data) - .map((entry) => (entry?._source ?? {}) as HostMetadata), - queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_1, - }; - }, - queryResponseToHostResult: (searchResponse: SearchResponse): HostQueryResult => { - const response = searchResponse as SearchResponse; - return { - resultLength: response.hits.hits.length, - result: response.hits.hits.length > 0 ? response.hits.hits[0]._source : undefined, - queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_1, - }; - }, - }; +// remove the top-level 'HostDetails' property if found, from previous schemas +function stripHostDetails(host: HostMetadata | { HostDetails: HostMetadata }): HostMetadata { + return 'HostDetails' in host ? host.HostDetails : host; } -export function metadataQueryStrategyV2(): MetadataQueryStrategy { +export const queryResponseToHostResult = ( + searchResponse: SearchResponse +): HostQueryResult => { + const response = searchResponse as SearchResponse; return { - index: metadataCurrentIndexPattern, - extraBodyProperties: { - track_total_hits: true, - }, - queryResponseToHostListResult: ( - searchResponse: SearchResponse - ): HostListQueryResult => { - const response = searchResponse as SearchResponse< - HostMetadata | { HostDetails: HostMetadata } - >; - const list = - response.hits.hits.length > 0 - ? response.hits.hits.map((entry) => stripHostDetails(entry?._source as HostMetadata)) - : []; - - return { - resultLength: - ((response.hits?.total as unknown) as { value: number; relation: string }).value || 0, - resultList: list, - queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_2, - }; - }, - queryResponseToHostResult: ( - searchResponse: SearchResponse - ): HostQueryResult => { - const response = searchResponse as SearchResponse< - HostMetadata | { HostDetails: HostMetadata } - >; - return { - resultLength: response.hits.hits.length, - result: - response.hits.hits.length > 0 - ? stripHostDetails(response.hits.hits[0]._source as HostMetadata) - : undefined, - queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_2, - }; - }, + resultLength: response.hits.hits.length, + result: + response.hits.hits.length > 0 + ? stripHostDetails(response.hits.hits[0]._source as HostMetadata) + : undefined, }; -} +}; -// remove the top-level 'HostDetails' property if found, from previous schemas -function stripHostDetails(host: HostMetadata | { HostDetails: HostMetadata }): HostMetadata { - return 'HostDetails' in host ? host.HostDetails : host; -} +export const queryResponseToHostListResult = ( + searchResponse: SearchResponse +): HostListQueryResult => { + const response = searchResponse as SearchResponse; + const list = + response.hits.hits.length > 0 + ? response.hits.hits.map((entry) => stripHostDetails(entry?._source as HostMetadata)) + : []; + + return { + resultLength: + ((response.hits?.total as unknown) as { value: number; relation: string }).value || 0, + resultList: list, + }; +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts index bc23c253c43478..a0530590f5f9fe 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts @@ -8,62 +8,6 @@ import { SearchResponse } from 'elasticsearch'; import { HostMetadata } from '../../../../../common/endpoint/types'; -export function createV1SearchResponse(hostMetadata?: HostMetadata): SearchResponse { - return ({ - took: 15, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: { - value: 5, - relation: 'eq', - }, - max_score: null, - hits: hostMetadata - ? [ - { - _index: 'metrics-endpoint.metadata-default', - _id: '8FhM0HEBYyRTvb6lOQnw', - _score: null, - _source: hostMetadata, - sort: [1588337587997], - inner_hits: { - most_recent: { - hits: { - total: { - value: 2, - relation: 'eq', - }, - max_score: null, - hits: [ - { - _index: 'metrics-endpoint.metadata-default', - _id: 'W6Vo1G8BYQH1gtPUgYkC', - _score: null, - _source: hostMetadata, - sort: [1579816615336], - }, - ], - }, - }, - }, - }, - ] - : [], - }, - aggregations: { - total: { - value: 1, - }, - }, - } as unknown) as SearchResponse; -} - export function createV2SearchResponse(hostMetadata?: HostMetadata): SearchResponse { return ({ took: 15, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts b/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts index 0ca1983aa68d51..1a5515d8122f18 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts @@ -10,20 +10,15 @@ import { SearchResponse } from 'elasticsearch'; import { HostMetadata } from '../../../common/endpoint/types'; import { SecuritySolutionRequestHandlerContext } from '../../types'; import { getESQueryHostMetadataByIDs } from '../routes/metadata/query_builders'; -import { EndpointAppContext } from '../types'; +import { queryResponseToHostListResult } from '../routes/metadata/support/query_strategies'; export async function getMetadataForEndpoints( endpointIDs: string[], - requestHandlerContext: SecuritySolutionRequestHandlerContext, - endpointAppContext: EndpointAppContext + requestHandlerContext: SecuritySolutionRequestHandlerContext ): Promise { - const queryStrategy = await endpointAppContext.service - ?.getMetadataService() - ?.queryStrategy(requestHandlerContext.core.savedObjects.client); - - const query = getESQueryHostMetadataByIDs(endpointIDs, queryStrategy!); + const query = getESQueryHostMetadataByIDs(endpointIDs); const esClient = requestHandlerContext.core.elasticsearch.client.asCurrentUser; const { body } = await esClient.search(query as SearchRequest); - const hosts = queryStrategy!.queryResponseToHostListResult(body as SearchResponse); + const hosts = queryResponseToHostListResult(body as SearchResponse); return hosts.resultList; } diff --git a/x-pack/plugins/security_solution/server/endpoint/types.ts b/x-pack/plugins/security_solution/server/endpoint/types.ts index 6076aa9af635bf..bc52b759b9f0ab 100644 --- a/x-pack/plugins/security_solution/server/endpoint/types.ts +++ b/x-pack/plugins/security_solution/server/endpoint/types.ts @@ -7,11 +7,9 @@ import { LoggerFactory } from 'kibana/server'; -import { SearchResponse } from '@elastic/elasticsearch/api/types'; -import { JsonObject } from '@kbn/common-utils'; import { ConfigType } from '../config'; import { EndpointAppContextService } from './endpoint_app_context_services'; -import { HostMetadata, MetadataQueryStrategyVersions } from '../../common/endpoint/types'; +import { HostMetadata } from '../../common/endpoint/types'; import { ExperimentalFeatures } from '../../common/experimental_features'; /** @@ -31,20 +29,9 @@ export interface EndpointAppContext { export interface HostListQueryResult { resultLength: number; resultList: HostMetadata[]; - queryStrategyVersion: MetadataQueryStrategyVersions; } export interface HostQueryResult { resultLength: number; result: HostMetadata | undefined; - queryStrategyVersion: MetadataQueryStrategyVersions; -} - -export interface MetadataQueryStrategy { - index: string; - extraBodyProperties?: JsonObject; - queryResponseToHostListResult: ( - searchResponse: SearchResponse - ) => HostListQueryResult; - queryResponseToHostResult: (searchResponse: SearchResponse) => HostQueryResult; } diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index f4d942f733c1db..9b9f49a167397f 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -199,10 +199,10 @@ export const getHostEndpoint = async ( }; const endpointData = id != null && metadataRequestContext.endpointAppContextService.getAgentService() != null - ? await getHostMetaData(metadataRequestContext, id, undefined) + ? await getHostMetaData(metadataRequestContext, id) : null; - const fleetAgentId = endpointData?.metadata.elastic.agent.id; + const fleetAgentId = endpointData?.elastic.agent.id; const [fleetAgentStatus, pendingActions] = !fleetAgentId ? [undefined, {}] : await Promise.all([ @@ -214,13 +214,13 @@ export const getHostEndpoint = async ( }), ]); - return endpointData != null && endpointData.metadata + return endpointData != null && endpointData ? { - endpointPolicy: endpointData.metadata.Endpoint.policy.applied.name, - policyStatus: endpointData.metadata.Endpoint.policy.applied.status, - sensorVersion: endpointData.metadata.agent.version, + endpointPolicy: endpointData.Endpoint.policy.applied.name, + policyStatus: endpointData.Endpoint.policy.applied.status, + sensorVersion: endpointData.agent.version, elasticAgentStatus: fleetAgentStatusToEndpointHostStatus(fleetAgentStatus!), - isolation: endpointData.metadata.Endpoint.state?.isolation ?? false, + isolation: endpointData.Endpoint.state?.isolation ?? false, pendingActions, } : null; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts index 1e26ea09618d5a..37e0a293b03a00 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts @@ -151,7 +151,14 @@ export async function executeEsQueryFactory( }, }, ], - docvalue_fields: [entity, dateField, geoField], + docvalue_fields: [ + entity, + { + field: dateField, + format: 'strict_date_optional_time', + }, + geoField, + ], _source: false, }, }, diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts index 754af920b009e5..21a536dd474bad 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts @@ -103,7 +103,7 @@ export function getActiveEntriesAndGenerateAlerts( locationsArr.forEach(({ location, shapeLocationId, dateInShape, docId }) => { const context = { entityId: entityName, - entityDateTime: dateInShape ? new Date(dateInShape).toISOString() : null, + entityDateTime: dateInShape || null, entityDocumentId: docId, detectionDateTime: new Date(currIntervalEndTime).toISOString(), entityLocation: `POINT (${location[0]} ${location[1]})`, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 107f5d6121e506..2a4fba9ceb5d71 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8104,7 +8104,6 @@ "xpack.enterpriseSearch.workplaceSearch.groups.groupSourcesUpdated": "共有コンテンツソースが正常に更新されました。", "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.groupTableHeader": "グループ", "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.sourcesTableHeader": "コンテンツソース", - "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.usersTableHeader": "ユーザー", "xpack.enterpriseSearch.workplaceSearch.groups.groupUpdatedText": "前回更新日時{updatedAt}。", "xpack.enterpriseSearch.workplaceSearch.groups.heading": "グループを管理", "xpack.enterpriseSearch.workplaceSearch.groups.inviteUsers.action": "ユーザーを招待", @@ -8117,7 +8116,6 @@ "xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveDescription": "グループはWorkplace Searchから削除されます。{name}を削除してよろしいですか?", "xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmTitleText": "確認", "xpack.enterpriseSearch.workplaceSearch.groups.overview.emptySourcesDescription": "コンテンツソースはこのグループと共有されていません。", - "xpack.enterpriseSearch.workplaceSearch.groups.overview.emptyUsersDescription": "このグループにはユーザーがありません。", "xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesDescription": "「{name}」グループのすべてのユーザーによって検索可能です。", "xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesTitle": "グループコンテンツソース", "xpack.enterpriseSearch.workplaceSearch.groups.overview.groupUsersDescription": "メンバーはグループのソースを検索できます。", @@ -13640,7 +13638,6 @@ "xpack.ml.annotationsTable.byColumnSMVName": "グループ基準", "xpack.ml.annotationsTable.detectorColumnName": "検知器", "xpack.ml.annotationsTable.editAnnotationsTooltip": "注釈を編集します", - "xpack.ml.annotationsTable.editAnnotationsTooltipAriaLabel": "注釈を編集します", "xpack.ml.annotationsTable.eventColumnName": "イベント", "xpack.ml.annotationsTable.fromColumnName": "開始:", "xpack.ml.annotationsTable.howToCreateAnnotationDescription": "注釈を作成するには、{linkToSingleMetricView} を開きます", @@ -18564,16 +18561,13 @@ "xpack.securitySolution.administration.os.linux": "Linux", "xpack.securitySolution.administration.os.macos": "Mac", "xpack.securitySolution.administration.os.windows": "Windows", - "xpack.securitySolution.alertDetails.alertSummary": "アラート概要", "xpack.securitySolution.alertDetails.checkDocs": "マニュアルをご確認ください。", "xpack.securitySolution.alertDetails.ifCtiNotEnabled": "脅威インテリジェンスソースを有効にしていない場合で、この機能について関心がある場合は、", - "xpack.securitySolution.alertDetails.noEnrichmentFound": "Threat Intel Enrichmentが見つかりません", "xpack.securitySolution.alertDetails.summary": "まとめ", "xpack.securitySolution.alertDetails.summary.investigationGuide": "調査ガイド", "xpack.securitySolution.alertDetails.summary.readLess": "表示を減らす", "xpack.securitySolution.alertDetails.summary.readMore": "続きを読む", "xpack.securitySolution.alertDetails.threatIntel": "Threat Intel", - "xpack.securitySolution.alertDetails.threatSummary": "脅威概要", "xpack.securitySolution.alerts.riskScoreMapping.defaultDescriptionLabel": "このルールで生成されたすべてのアラートのリスクスコアを選択します。", "xpack.securitySolution.alerts.riskScoreMapping.defaultRiskScoreTitle": "デフォルトリスクスコア", "xpack.securitySolution.alerts.riskScoreMapping.mappingDescriptionLabel": "ソースイベント値を使用して、デフォルトリスクスコアを上書きします。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d8e5ae57d22156..b919a0e36a2ad3 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8172,7 +8172,6 @@ "xpack.enterpriseSearch.workplaceSearch.groups.groupSourcesUpdated": "已成功更新共享内容源。", "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.groupTableHeader": "组", "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.sourcesTableHeader": "内容源", - "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.usersTableHeader": "用户", "xpack.enterpriseSearch.workplaceSearch.groups.groupUpdatedText": "上次更新于 {updatedAt}。", "xpack.enterpriseSearch.workplaceSearch.groups.heading": "管理组", "xpack.enterpriseSearch.workplaceSearch.groups.inviteUsers.action": "邀请用户", @@ -8185,7 +8184,6 @@ "xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveDescription": "您的组将从 Workplace Search 中删除。确定要移除 {name}?", "xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmTitleText": "确认", "xpack.enterpriseSearch.workplaceSearch.groups.overview.emptySourcesDescription": "未与此组共享任何内容源。", - "xpack.enterpriseSearch.workplaceSearch.groups.overview.emptyUsersDescription": "此组中没有用户。", "xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesDescription": "可按“{name}”组中的所有用户搜索。", "xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesTitle": "组内容源", "xpack.enterpriseSearch.workplaceSearch.groups.overview.groupUsersDescription": "成员将可以对该组的源进行搜索。", @@ -13819,7 +13817,6 @@ "xpack.ml.annotationsTable.byColumnSMVName": "依据", "xpack.ml.annotationsTable.detectorColumnName": "检测工具", "xpack.ml.annotationsTable.editAnnotationsTooltip": "编辑注释", - "xpack.ml.annotationsTable.editAnnotationsTooltipAriaLabel": "编辑注释", "xpack.ml.annotationsTable.eventColumnName": "事件", "xpack.ml.annotationsTable.fromColumnName": "自", "xpack.ml.annotationsTable.howToCreateAnnotationDescription": "要创建注释,请打开 {linkToSingleMetricView}", @@ -18828,16 +18825,13 @@ "xpack.securitySolution.administration.os.linux": "Linux", "xpack.securitySolution.administration.os.macos": "Mac", "xpack.securitySolution.administration.os.windows": "Windows", - "xpack.securitySolution.alertDetails.alertSummary": "告警摘要", "xpack.securitySolution.alertDetails.checkDocs": "请查看我们的文档。", "xpack.securitySolution.alertDetails.ifCtiNotEnabled": "如果尚未启用任何威胁情报来源,并希望更多了解此功能,", - "xpack.securitySolution.alertDetails.noEnrichmentFound": "未找到威胁情报扩充", "xpack.securitySolution.alertDetails.summary": "摘要", "xpack.securitySolution.alertDetails.summary.investigationGuide": "调查指南", "xpack.securitySolution.alertDetails.summary.readLess": "阅读更少内容", "xpack.securitySolution.alertDetails.summary.readMore": "阅读更多内容", "xpack.securitySolution.alertDetails.threatIntel": "威胁情报", - "xpack.securitySolution.alertDetails.threatSummary": "威胁摘要", "xpack.securitySolution.alerts.riskScoreMapping.defaultDescriptionLabel": "选择此规则生成的所有告警的风险分数。", "xpack.securitySolution.alerts.riskScoreMapping.defaultRiskScoreTitle": "默认风险分数", "xpack.securitySolution.alerts.riskScoreMapping.mappingDescriptionLabel": "使用源事件值覆盖默认风险分数。", diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts index 1a52bd18f80af4..e1763b6ad44042 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts @@ -29,7 +29,6 @@ export default function endpointAPIIntegrationTests(providerContext: FtrProvider }); loadTestFile(require.resolve('./resolver/index')); loadTestFile(require.resolve('./metadata')); - loadTestFile(require.resolve('./metadata_v1')); loadTestFile(require.resolve('./policy')); loadTestFile(require.resolve('./package')); }); diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts index b5d98c115d1940..1f57cd1b6db347 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts @@ -12,7 +12,6 @@ import { deleteAllDocsFromMetadataIndex, deleteMetadataStream, } from './data_stream_helper'; -import { MetadataQueryStrategyVersions } from '../../../plugins/security_solution/common/endpoint/types'; import { HOST_METADATA_LIST_ROUTE } from '../../../plugins/security_solution/common/endpoint/constants'; /** @@ -88,7 +87,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(1); expect(body.request_page_size).to.eql(1); expect(body.request_page_index).to.eql(1); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); /* test that when paging properties produces no result, the total should reflect the actual number of metadata @@ -113,7 +111,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(0); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(30); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); it('metadata api should return 400 when pagingProperties is below boundaries.', async () => { @@ -148,7 +145,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(2); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); it('metadata api should return page based on filters and paging passed.', async () => { @@ -186,7 +182,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(2); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); it('metadata api should return page based on host.os.Ext.variant filter.', async () => { @@ -208,7 +203,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(2); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); it('metadata api should return the latest event for all the events for an endpoint', async () => { @@ -231,7 +225,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(1); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); it('metadata api should return the latest event for all the events where policy status is not success', async () => { @@ -275,7 +268,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(1); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); it('metadata api should return all hosts when filter is empty string', async () => { @@ -292,7 +284,6 @@ export default function ({ getService }: FtrProviderContext) { expect(body.hosts.length).to.eql(numberOfHostsInFixture); expect(body.request_page_size).to.eql(10); expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2); }); }); }); diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts deleted file mode 100644 index d8cf1a11fac0a5..00000000000000 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts +++ /dev/null @@ -1,290 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; -import { deleteMetadataStream } from './data_stream_helper'; -import { METADATA_REQUEST_V1_ROUTE } from '../../../plugins/security_solution/server/endpoint/routes/metadata'; -import { MetadataQueryStrategyVersions } from '../../../plugins/security_solution/common/endpoint/types'; - -/** - * The number of host documents in the es archive. - */ -const numberOfHostsInFixture = 3; - -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - describe('test metadata api v1', () => { - describe(`POST ${METADATA_REQUEST_V1_ROUTE} when index is empty`, () => { - it('metadata api should return empty result when index is empty', async () => { - // the endpoint uses data streams and es archiver does not support deleting them at the moment so we need - // to do it manually - await deleteMetadataStream(getService); - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send() - .expect(200); - expect(body.total).to.eql(0); - expect(body.hosts.length).to.eql(0); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - }); - - describe(`POST ${METADATA_REQUEST_V1_ROUTE} when index is not empty`, () => { - before( - async () => - await esArchiver.load( - 'x-pack/test/functional/es_archives/endpoint/metadata/api_feature', - { useCreate: true } - ) - ); - // the endpoint uses data streams and es archiver does not support deleting them at the moment so we need - // to do it manually - after(async () => await deleteMetadataStream(getService)); - it('metadata api should return one entry for each host with default paging', async () => { - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send() - .expect(200); - expect(body.total).to.eql(numberOfHostsInFixture); - expect(body.hosts.length).to.eql(numberOfHostsInFixture); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - it('metadata api should return page based on paging properties passed.', async () => { - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - paging_properties: [ - { - page_size: 1, - }, - { - page_index: 1, - }, - ], - }) - .expect(200); - expect(body.total).to.eql(numberOfHostsInFixture); - expect(body.hosts.length).to.eql(1); - expect(body.request_page_size).to.eql(1); - expect(body.request_page_index).to.eql(1); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - /* test that when paging properties produces no result, the total should reflect the actual number of metadata - in the index. - */ - it('metadata api should return accurate total metadata if page index produces no result', async () => { - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - paging_properties: [ - { - page_size: 10, - }, - { - page_index: 3, - }, - ], - }) - .expect(200); - expect(body.total).to.eql(numberOfHostsInFixture); - expect(body.hosts.length).to.eql(0); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(30); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - it('metadata api should return 400 when pagingProperties is below boundaries.', async () => { - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - paging_properties: [ - { - page_size: 0, - }, - { - page_index: 1, - }, - ], - }) - .expect(400); - expect(body.message).to.contain('Value must be equal to or greater than [1]'); - }); - - it('metadata api should return page based on filters passed.', async () => { - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - filters: { - kql: 'not host.ip:10.46.229.234', - }, - }) - .expect(200); - expect(body.total).to.eql(2); - expect(body.hosts.length).to.eql(2); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - it('metadata api should return page based on filters and paging passed.', async () => { - const notIncludedIp = '10.46.229.234'; - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - paging_properties: [ - { - page_size: 10, - }, - { - page_index: 0, - }, - ], - filters: { - kql: `not host.ip:${notIncludedIp}`, - }, - }) - .expect(200); - expect(body.total).to.eql(2); - const resultIps: string[] = [].concat( - ...body.hosts.map((hostInfo: Record) => hostInfo.metadata.host.ip) - ); - expect(resultIps).to.eql([ - '10.192.213.130', - '10.70.28.129', - '10.101.149.26', - '2606:a000:ffc0:39:11ef:37b9:3371:578c', - ]); - expect(resultIps).not.include.eql(notIncludedIp); - expect(body.hosts.length).to.eql(2); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - it('metadata api should return page based on host.os.Ext.variant filter.', async () => { - const variantValue = 'Windows Pro'; - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - filters: { - kql: `host.os.Ext.variant:${variantValue}`, - }, - }) - .expect(200); - expect(body.total).to.eql(2); - const resultOsVariantValue: Set = new Set( - body.hosts.map((hostInfo: Record) => hostInfo.metadata.host.os.Ext.variant) - ); - expect(Array.from(resultOsVariantValue)).to.eql([variantValue]); - expect(body.hosts.length).to.eql(2); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - it('metadata api should return the latest event for all the events for an endpoint', async () => { - const targetEndpointIp = '10.46.229.234'; - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - filters: { - kql: `host.ip:${targetEndpointIp}`, - }, - }) - .expect(200); - expect(body.total).to.eql(1); - const resultIp: string = body.hosts[0].metadata.host.ip.filter( - (ip: string) => ip === targetEndpointIp - ); - expect(resultIp).to.eql([targetEndpointIp]); - expect(body.hosts[0].metadata.event.created).to.eql(1618841405309); - expect(body.hosts.length).to.eql(1); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - it('metadata api should return the latest event for all the events where policy status is not success', async () => { - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - filters: { - kql: `not Endpoint.policy.applied.status:success`, - }, - }) - .expect(200); - const statuses: Set = new Set( - body.hosts.map( - (hostInfo: Record) => hostInfo.metadata.Endpoint.policy.applied.status - ) - ); - expect(statuses.size).to.eql(1); - expect(Array.from(statuses)).to.eql(['failure']); - }); - - it('metadata api should return the endpoint based on the elastic agent id, and status should be unhealthy', async () => { - const targetEndpointId = 'fc0ff548-feba-41b6-8367-65e8790d0eaf'; - const targetElasticAgentId = '023fa40c-411d-4188-a941-4147bfadd095'; - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - filters: { - kql: `elastic.agent.id:${targetElasticAgentId}`, - }, - }) - .expect(200); - expect(body.total).to.eql(1); - const resultHostId: string = body.hosts[0].metadata.host.id; - const resultElasticAgentId: string = body.hosts[0].metadata.elastic.agent.id; - expect(resultHostId).to.eql(targetEndpointId); - expect(resultElasticAgentId).to.eql(targetElasticAgentId); - expect(body.hosts[0].metadata.event.created).to.eql(1618841405309); - expect(body.hosts[0].host_status).to.eql('unhealthy'); - expect(body.hosts.length).to.eql(1); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - - it('metadata api should return all hosts when filter is empty string', async () => { - const { body } = await supertest - .post(`${METADATA_REQUEST_V1_ROUTE}`) - .set('kbn-xsrf', 'xxx') - .send({ - filters: { - kql: '', - }, - }) - .expect(200); - expect(body.total).to.eql(numberOfHostsInFixture); - expect(body.hosts.length).to.eql(numberOfHostsInFixture); - expect(body.request_page_size).to.eql(10); - expect(body.request_page_index).to.eql(0); - expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1); - }); - }); - }); -} diff --git a/yarn.lock b/yarn.lock index 227301eed8dd6c..dccbd8f91a4299 100644 --- a/yarn.lock +++ b/yarn.lock @@ -209,6 +209,13 @@ dependencies: "@babel/types" "^7.12.5" +"@babel/helper-module-imports@^7.7.0": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" + integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== + dependencies: + "@babel/types" "^7.13.12" + "@babel/helper-module-transforms@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" @@ -548,6 +555,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-syntax-jsx@^7.2.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz#044fb81ebad6698fe62c478875575bcbb9b70f15" + integrity sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -1154,6 +1168,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.13.10": + version "7.13.17" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.17.tgz#8966d1fc9593bf848602f0662d6b4d0069e3a7ec" + integrity sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.12.13", "@babel/template@^7.12.7", "@babel/template@^7.3.3", "@babel/template@^7.4.4": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" @@ -1187,6 +1208,15 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" +"@babel/types@^7.13.12": + version "7.13.14" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d" + integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@base2/pretty-print-object@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.0.tgz#860ce718b0b73f4009e153541faff2cb6b85d047" @@ -1592,6 +1622,41 @@ resolved "https://registry.yarnpkg.com/@elastic/ui-ace/-/ui-ace-0.2.3.tgz#5281aed47a79b7216c55542b0675e435692f20cd" integrity sha512-Nti5s2dplBPhSKRwJxG9JXTMOev4jVOWcnTJD1TOkJr1MUBYKVZcNcJtIVMSvahWGmP0B/UfO9q9lyRqdivkvQ== +"@emotion/babel-plugin-jsx-pragmatic@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin-jsx-pragmatic/-/babel-plugin-jsx-pragmatic-0.1.5.tgz#27debfe9c27c4d83574d509787ae553bf8a34d7e" + integrity sha512-y+3AJ0SItMDaAgGPVkQBC/S/BaqaPACkQ6MyCI2CUlrjTxKttTVfD3TMtcs7vLEcLxqzZ1xiG0vzwCXjhopawQ== + dependencies: + "@babel/plugin-syntax-jsx" "^7.2.0" + +"@emotion/babel-plugin@^11.2.0": + version "11.2.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.2.0.tgz#f25c6df8ec045dad5ae6ca63df0791673b98c920" + integrity sha512-lsnQBnl3l4wu/FJoyHnYRpHJeIPNkOBMbtDUIXcO8luulwRKZXPvA10zd2eXVN6dABIWNX4E34en/jkejIg/yA== + dependencies: + "@babel/helper-module-imports" "^7.7.0" + "@babel/plugin-syntax-jsx" "^7.12.1" + "@babel/runtime" "^7.7.2" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.0" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "^4.0.3" + +"@emotion/babel-preset-css-prop@^11.2.0": + version "11.2.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-preset-css-prop/-/babel-preset-css-prop-11.2.0.tgz#c7e945f56b2610b438f0dc8ae5253fc55488de0e" + integrity sha512-9XLQm2eLPYTho+Cx1LQTDA1rATjoAaB4O+ds55XDvoAa+Z16Hhg8y5Vihj3C8E6+ilDM8SV5A9Z6z+yj0YIRBg== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.12.1" + "@babel/runtime" "^7.7.2" + "@emotion/babel-plugin" "^11.2.0" + "@emotion/babel-plugin-jsx-pragmatic" "^0.1.5" + "@emotion/babel-utils@^0.6.4": version "0.6.10" resolved "https://registry.yarnpkg.com/@emotion/babel-utils/-/babel-utils-0.6.10.tgz#83dbf3dfa933fae9fc566e54fbb45f14674c6ccc" @@ -1614,6 +1679,17 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" +"@emotion/cache@^11.4.0": + version "11.4.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.4.0.tgz#293fc9d9a7a38b9aad8e9337e5014366c3b09ac0" + integrity sha512-Zx70bjE7LErRO9OaZrhf22Qye1y4F7iDl+ITjet0J+i+B88PrAOBkKvaAWhxsZf72tDLajwCgfCjJ2dvH77C3g== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.0.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "^4.0.3" + "@emotion/core@^10.0.9", "@emotion/core@^10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" @@ -1626,6 +1702,14 @@ "@emotion/sheet" "0.9.4" "@emotion/utils" "0.11.3" +"@emotion/css-prettifier@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@emotion/css-prettifier/-/css-prettifier-1.0.0.tgz#3ed4240d93c9798c001cedf27dd0aa960bdddd1a" + integrity sha512-efxSrRTiTqHTQVKW15Gz5H4pNAw8OqcG8NaiwkJIkqIdNXTD4Qr1zC1Ou6r2acd1oJJ2s56nb1ClnXMiWoj6gQ== + dependencies: + "@emotion/memoize" "^0.7.4" + stylis "^4.0.3" + "@emotion/css@^10.0.27", "@emotion/css@^10.0.9": version "10.0.27" resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" @@ -1635,7 +1719,7 @@ "@emotion/utils" "0.11.3" babel-plugin-emotion "^10.0.27" -"@emotion/hash@0.8.0": +"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== @@ -1652,6 +1736,17 @@ dependencies: "@emotion/memoize" "0.7.4" +"@emotion/jest@^11.3.0": + version "11.3.0" + resolved "https://registry.yarnpkg.com/@emotion/jest/-/jest-11.3.0.tgz#43bed6dcb47c8691b346cee231861ebc8f9b0016" + integrity sha512-LZqYc3yerhic1IvAcEwBLRs1DsUt3oY7Oz6n+e+HU32iYOK/vpfzlhgmQURE94BHfv6eCOj6DV38f3jSnIkBkQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/css-prettifier" "^1.0.0" + chalk "^4.1.0" + specificity "^0.4.1" + stylis "^4.0.3" + "@emotion/memoize@0.7.4": version "0.7.4" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" @@ -1662,6 +1757,24 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b" integrity sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ== +"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/react@^11.4.0": + version "11.4.0" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.4.0.tgz#2465ad7b073a691409b88dfd96dc17097ddad9b7" + integrity sha512-4XklWsl9BdtatLoJpSjusXhpKv9YVteYKh9hPKP1Sxl+mswEFoUe0WtmtWjxEjkA51DQ2QRMCNOvKcSlCQ7ivg== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/cache" "^11.4.0" + "@emotion/serialize" "^1.0.2" + "@emotion/sheet" "^1.0.1" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": version "0.11.16" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" @@ -1683,11 +1796,27 @@ "@emotion/unitless" "^0.6.7" "@emotion/utils" "^0.8.2" +"@emotion/serialize@^1.0.0", "@emotion/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" + integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + "@emotion/sheet@0.9.4": version "0.9.4" resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== +"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.1.tgz#245f54abb02dfd82326e28689f34c27aa9b2a698" + integrity sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g== + "@emotion/styled-base@^10.0.27": version "10.0.31" resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a" @@ -1716,7 +1845,7 @@ resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.7.1.tgz#50f63225e712d99e2b2b39c19c70fff023793ca5" integrity sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ== -"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4": +"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== @@ -1736,7 +1865,12 @@ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.8.2.tgz#576ff7fb1230185b619a75d258cbc98f0867a8dc" integrity sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw== -"@emotion/weak-memoize@0.2.5": +"@emotion/utils@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af" + integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA== + +"@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5": version "0.2.5" resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== @@ -7790,7 +7924,7 @@ babel-plugin-jest-hoist@^26.6.2: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0: +babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.6.1, babel-plugin-macros@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== @@ -9487,15 +9621,6 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -clipboard@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.4.tgz#836dafd66cf0fea5d71ce5d5b0bf6e958009112d" - integrity sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ== - dependencies: - good-listener "^1.2.2" - select "^1.1.2" - tiny-emitter "^2.0.0" - cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" @@ -10718,6 +10843,11 @@ csstype@^2.5.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.14.tgz#004822a4050345b55ad4dcc00be1d9cf2f4296de" integrity sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A== +csstype@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" + integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g== + cucumber-expressions@^5.0.13: version "5.0.18" resolved "https://registry.yarnpkg.com/cucumber-expressions/-/cucumber-expressions-5.0.18.tgz#6c70779efd3aebc5e9e7853938b1110322429596" @@ -11589,11 +11719,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delegate@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" - integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== - delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -14789,13 +14914,6 @@ gonzales-pe@^4.3.0: dependencies: minimist "^1.2.5" -good-listener@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" - integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= - dependencies: - delegate "^3.1.2" - got@5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/got/-/got-5.6.0.tgz#bb1d7ee163b78082bbc8eb836f3f395004ea6fbf" @@ -15410,7 +15528,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.5, hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.5, hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -22172,8 +22290,6 @@ prismjs@1.24.0, prismjs@^1.22.0, prismjs@~1.23.0: version "1.24.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.24.0.tgz#0409c30068a6c52c89ef7f1089b3ca4de56be2ac" integrity sha512-SqV5GRsNqnzCL8k5dfAjCNhUrF3pR0A9lTDSCUZeh/LIshheXJEaP0hwLz2t4XHivd2J/v2HR+gRnigzeKe3cQ== - optionalDependencies: - clipboard "^2.0.0" private@^0.1.8, private@~0.1.5: version "0.1.8" @@ -24791,11 +24907,6 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -select@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" - integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= - selenium-webdriver@^4.0.0-alpha.7: version "4.0.0-alpha.7" resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz#e3879d8457fd7ad8e4424094b7dc0540d99e6797" @@ -26207,6 +26318,11 @@ stylis@^3.5.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe" integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q== +stylis@^4.0.3: + version "4.0.7" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.7.tgz#412a90c28079417f3d27c028035095e4232d2904" + integrity sha512-OFFeUXFgwnGOKvEXaSv0D0KQ5ADP0n6g3SVONx6I/85JzNZ3u50FRwB3lVIk1QO2HNdI75tbVzc4Z66Gdp9voA== + subarg@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" @@ -26828,11 +26944,6 @@ timsort@^0.3.0, timsort@~0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -tiny-emitter@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c" - integrity sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow== - tiny-inflate@^1.0.0, tiny-inflate@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4"