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"