{strings.fatal.callout.title()}}
+ title={{strings.fatal.callout.title()}
}
color="danger"
iconType="error"
body={
<>
- {strings.fatal.callout.body()}
+ {strings.fatal.callout.body()}
{strings.fatal.callout.pageReloadButton()}
- setIsFlyoutVisible(true)}>
+ setIsFlyoutVisible(true)}
+ data-test-subj="errorBoundaryFatalShowDetailsBtn"
+ >
{strings.fatal.callout.showDetailsButton()}
{isFlyoutVisible ? (
@@ -128,17 +132,25 @@ export const RecoverablePrompt = (props: ErrorCalloutProps) => {
const { onClickRefresh } = props;
return (
{strings.recoverable.callout.title()}}
- body={{strings.recoverable.callout.body()}
}
+ title={
+
+ {strings.recoverable.callout.title()}
+
+ }
color="warning"
+ iconType="warning"
+ body={
+
+ {strings.recoverable.callout.body()}
+
+ }
actions={
{strings.recoverable.callout.pageReloadButton()}
diff --git a/src/cli/dist.js b/src/cli/dist.js
index 9bd7696a44561..5551c4e5c7774 100644
--- a/src/cli/dist.js
+++ b/src/cli/dist.js
@@ -9,4 +9,5 @@
require('../setup_node_env/dist');
require('./apm')();
require('../setup_node_env/root');
+require('../setup_node_env/mute_libraries');
require('./cli');
diff --git a/src/core/server/integration_tests/capabilities/capabilities_service.test.ts b/src/core/server/integration_tests/capabilities/capabilities_service.test.ts
index 23a8905bcb565..6ee87dc5a7931 100644
--- a/src/core/server/integration_tests/capabilities/capabilities_service.test.ts
+++ b/src/core/server/integration_tests/capabilities/capabilities_service.test.ts
@@ -82,7 +82,7 @@ describe('CapabilitiesService', () => {
serviceSetup.registerProvider(() => getInitialCapabilities());
const switcher = jest.fn((_, capabilities) => capabilities);
- serviceSetup.registerSwitcher(switcher);
+ serviceSetup.registerSwitcher(switcher, { capabilityPath: '*' });
const result = await supertest(httpSetup.server.listener)
.post('/api/core/capabilities')
@@ -113,7 +113,7 @@ describe('CapabilitiesService', () => {
serviceSetup.registerProvider(() => getInitialCapabilities());
const switcher = jest.fn((_, capabilities) => capabilities);
- serviceSetup.registerSwitcher(switcher);
+ serviceSetup.registerSwitcher(switcher, { capabilityPath: '*' });
const result = await supertest(httpSetup.server.listener)
.post('/api/core/capabilities?useDefaultCapabilities=true')
diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile
index 8db4b419a184a..25f4345ffbcc3 100644
--- a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile
+++ b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile
@@ -128,6 +128,7 @@ COPY --chown=1000:0 config/serverless.oblt.yml /usr/share/kibana/config/serverle
COPY --chown=1000:0 config/serverless.security.yml /usr/share/kibana/config/serverless.security.yml
# Supportability enhancement: enable capturing heap snapshots. See https://nodejs.org/api/cli.html#--heapsnapshot-signalsignal
RUN echo '\n--heapsnapshot-signal=SIGUSR2' >> config/node.options
+RUN echo '--diagnostic-dir=./data' >> config/node.options
{{/serverless}}
{{^opensslLegacyProvider}}
RUN sed 's/\(--openssl-legacy-provider\)/#\1/' -i config/node.options
diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile
index b68130f1d201c..7fbba7d72ea78 100644
--- a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile
+++ b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/Dockerfile
@@ -4,7 +4,7 @@
################################################################################
ARG BASE_REGISTRY=registry1.dso.mil
ARG BASE_IMAGE=redhat/ubi/ubi9
-ARG BASE_TAG=9.2
+ARG BASE_TAG=9.3
FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as prep_files
diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml
index 3bbd4d7f31d12..43800a045da9c 100644
--- a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml
+++ b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml
@@ -14,7 +14,7 @@ tags:
# Build args passed to Dockerfile ARGs
args:
BASE_IMAGE: 'redhat/ubi/ubi9'
- BASE_TAG: '9.2'
+ BASE_TAG: '9.3'
# Docker image labels
labels:
diff --git a/src/plugins/data_views/server/data_views_service_factory.ts b/src/plugins/data_views/server/data_views_service_factory.ts
index e5324b2eb02d2..430ebd36489b6 100644
--- a/src/plugins/data_views/server/data_views_service_factory.ts
+++ b/src/plugins/data_views/server/data_views_service_factory.ts
@@ -63,13 +63,21 @@ export const dataViewsServiceFactory = (deps: DataViewsServiceFactoryDeps) =>
byPassCapabilities
? true
: request
- ? (await capabilities.resolveCapabilities(request)).indexPatterns.save === true
+ ? (
+ await capabilities.resolveCapabilities(request, {
+ capabilityPath: 'indexPatterns.save',
+ })
+ ).indexPatterns.save === true
: false,
getCanSaveAdvancedSettings: async () =>
byPassCapabilities
? true
: request
- ? (await capabilities.resolveCapabilities(request)).advancedSettings.save === true
+ ? (
+ await capabilities.resolveCapabilities(request, {
+ capabilityPath: 'advancedSettings.save',
+ })
+ ).advancedSettings.save === true
: false,
scriptedFieldsEnabled: deps.scriptedFieldsEnabled,
});
diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_renderer.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable_renderer.test.tsx
index b919672ad01e3..a1be9c560bf3c 100644
--- a/src/plugins/embeddable/public/lib/embeddables/embeddable_renderer.test.tsx
+++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_renderer.test.tsx
@@ -7,7 +7,7 @@
*/
import React from 'react';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import {
diff --git a/src/plugins/ui_actions/public/context_menu/open_context_menu.test.ts b/src/plugins/ui_actions/public/context_menu/open_context_menu.test.ts
index f8b54fb33e122..ddd7d77812add 100644
--- a/src/plugins/ui_actions/public/context_menu/open_context_menu.test.ts
+++ b/src/plugins/ui_actions/public/context_menu/open_context_menu.test.ts
@@ -7,7 +7,7 @@
*/
import { createInteractionPositionTracker } from './open_context_menu';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
let targetEl: Element;
const top = 100;
diff --git a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts
index 950c70ec7c60d..ea9d343845442 100644
--- a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts
+++ b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts
@@ -10,7 +10,7 @@ import { ActionDefinition } from '../actions';
import { openContextMenu } from '../context_menu';
import { uiActionsPluginMock } from '../mocks';
import type { Trigger } from '@kbn/ui-actions-browser';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
jest.mock('../context_menu');
diff --git a/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts b/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts
index e6f3aeaa3a002..3135f3c86f465 100644
--- a/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts
+++ b/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts
@@ -15,7 +15,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { searchSourceInstanceMock } from '@kbn/data-plugin/common/search/search_source/mocks';
import { of, Subject, throwError } from 'rxjs';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import { DataViewType, SearchSourceSearchOptions } from '@kbn/data-plugin/common';
import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks';
diff --git a/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx b/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx
index 8e60c720e1154..aa348d59d85f4 100644
--- a/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx
+++ b/src/plugins/unified_search/public/query_string_input/query_string_input.test.tsx
@@ -15,8 +15,7 @@ import {
import React from 'react';
import { I18nProvider } from '@kbn/i18n-react';
import { mount } from 'enzyme';
-import { waitFor } from '@testing-library/dom';
-import { render } from '@testing-library/react';
+import { waitFor, render } from '@testing-library/react';
import { EuiTextArea, EuiIcon } from '@elastic/eui';
diff --git a/src/setup_node_env/heap_snapshot.js b/src/setup_node_env/heap_snapshot.js
new file mode 100644
index 0000000000000..94e4b35e2f887
--- /dev/null
+++ b/src/setup_node_env/heap_snapshot.js
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+var getopts = require('getopts');
+var path = require('path');
+var v8 = require('node:v8');
+var worker = require('node:worker_threads');
+
+var execOpts = getopts(process.execArgv);
+var envOpts = getopts(process.env.NODE_OPTIONS ? process.env.NODE_OPTIONS.split(/\s+/) : []);
+var diagnosticDir = execOpts['diagnostic-dir'] || envOpts['diagnostic-dir'];
+var heapSnapshotSignal = execOpts['heapsnapshot-signal'] || envOpts['heapsnapshot-signal'];
+var heapSnapshotSerial = 0;
+
+function getHeapSnapshotPath() {
+ var now = new Date();
+
+ var year = now.getFullYear();
+ var month = String(now.getMonth() + 1).padStart(2, '0');
+ var day = String(now.getDate()).padStart(2, '0');
+ var hours = String(now.getHours()).padStart(2, '0');
+ var minutes = String(now.getMinutes()).padStart(2, '0');
+ var seconds = String(now.getSeconds()).padStart(2, '0');
+
+ var date = `${year}${month}${day}`;
+ var time = `${hours}${minutes}${seconds}`;
+ var pid = process.pid;
+ var threadId = worker.threadId;
+ var serial = (++heapSnapshotSerial).toString().padStart(3, '0');
+
+ return path.join(diagnosticDir, `Heap.${date}.${time}.${pid}.${threadId}.${serial}.heapsnapshot`);
+}
+
+if (diagnosticDir && heapSnapshotSignal) {
+ process.removeAllListeners(heapSnapshotSignal);
+
+ process.on(heapSnapshotSignal, function () {
+ var heapSnapshotPath = getHeapSnapshotPath();
+ v8.writeHeapSnapshot(heapSnapshotPath);
+ });
+}
diff --git a/src/setup_node_env/mute_libraries.js b/src/setup_node_env/mute_libraries.js
new file mode 100644
index 0000000000000..defb6347d80f7
--- /dev/null
+++ b/src/setup_node_env/mute_libraries.js
@@ -0,0 +1,11 @@
+/*
+ * 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.
+ */
+
+// disable moment deprecation warnings
+var moment = require('moment');
+moment.suppressDeprecationWarnings = true;
diff --git a/src/setup_node_env/setup_env.js b/src/setup_node_env/setup_env.js
index 7b37d98011cfb..d3076a2c3b9cf 100644
--- a/src/setup_node_env/setup_env.js
+++ b/src/setup_node_env/setup_env.js
@@ -11,6 +11,8 @@ require('./exit_on_warning');
require('./harden');
// The following require statements MUST be executed before any others - END
+// @todo Remove when migrated to Node 20 (#162696)
+require('./heap_snapshot');
require('symbol-observable');
require('source-map-support').install();
require('./node_version_validator');
diff --git a/test/common/plugins/otel_metrics/kibana.jsonc b/test/common/plugins/otel_metrics/kibana.jsonc
index 0b25b57d06a53..e64546f446052 100644
--- a/test/common/plugins/otel_metrics/kibana.jsonc
+++ b/test/common/plugins/otel_metrics/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/open-telemetry-instrumented-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "openTelemetryInstrumentedPlugin",
"server": true,
diff --git a/test/examples/config.js b/test/examples/config.js
index 36f4a007b7983..dbc9d32055cc7 100644
--- a/test/examples/config.js
+++ b/test/examples/config.js
@@ -31,6 +31,7 @@ export default async function ({ readConfigFile }) {
require.resolve('./content_management'),
require.resolve('./unified_field_list_examples'),
require.resolve('./discover_customization_examples'),
+ require.resolve('./error_boundary'),
],
services: {
...functionalConfig.get('services'),
diff --git a/test/examples/error_boundary/index.ts b/test/examples/error_boundary/index.ts
new file mode 100644
index 0000000000000..f240ebd1442b2
--- /dev/null
+++ b/test/examples/error_boundary/index.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 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 expect from '@kbn/expect';
+import { FtrProviderContext } from '../../functional/ftr_provider_context';
+
+// eslint-disable-next-line import/no-default-export
+export default function ({ getService, getPageObjects }: FtrProviderContext) {
+ const retry = getService('retry');
+ const testSubjects = getService('testSubjects');
+ const PageObjects = getPageObjects(['common']);
+ const log = getService('log');
+
+ describe('Error Boundary Examples', () => {
+ before(async () => {
+ await PageObjects.common.navigateToApp('errorBoundaryExample');
+ await testSubjects.existOrFail('errorBoundaryExampleHeader');
+ });
+
+ it('fatal error', async () => {
+ log.debug('clicking button for fatal error');
+ await testSubjects.click('fatalErrorBtn');
+ const errorHeader = await testSubjects.getVisibleText('errorBoundaryFatalHeader');
+ expect(errorHeader).to.not.be(undefined);
+
+ log.debug('checking that the error has taken over the page');
+ await testSubjects.missingOrFail('errorBoundaryExampleHeader');
+
+ await testSubjects.click('errorBoundaryFatalShowDetailsBtn');
+ const errorString = await testSubjects.getVisibleText('errorBoundaryFatalDetailsErrorString');
+ expect(errorString).to.match(/Error: Example of unknown error type/);
+
+ log.debug('closing error flyout');
+ await testSubjects.click('euiFlyoutCloseButton');
+
+ log.debug('clicking page refresh');
+ await testSubjects.click('errorBoundaryFatalPromptReloadBtn');
+
+ await retry.try(async () => {
+ log.debug('checking for page refresh');
+ await testSubjects.existOrFail('errorBoundaryExampleHeader');
+ });
+ });
+
+ it('recoverable error', async () => {
+ log.debug('clicking button for recoverable error');
+ await testSubjects.click('recoverableErrorBtn');
+ const errorHeader = await testSubjects.getVisibleText('errorBoundaryRecoverableHeader');
+ expect(errorHeader).to.not.be(undefined);
+
+ log.debug('checking that the error has taken over the page');
+ await testSubjects.missingOrFail('errorBoundaryExampleHeader');
+
+ log.debug('clicking page refresh');
+ await testSubjects.click('errorBoundaryRecoverablePromptReloadBtn');
+
+ await retry.try(async () => {
+ log.debug('checking for page refresh');
+ await testSubjects.existOrFail('errorBoundaryExampleHeader');
+ });
+ });
+ });
+}
diff --git a/test/functional/apps/visualize/group3/_annotation_listing.ts b/test/functional/apps/visualize/group3/_annotation_listing.ts
index 71489388b54b5..53ae9d48e2b5c 100644
--- a/test/functional/apps/visualize/group3/_annotation_listing.ts
+++ b/test/functional/apps/visualize/group3/_annotation_listing.ts
@@ -18,8 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const retry = getService('retry');
const log = getService('log');
- // Failing: See https://github.com/elastic/kibana/issues/170578
- describe.skip('annotation listing page', function () {
+ describe('annotation listing page', function () {
before(async function () {
await kibanaServer.importExport.load(
'test/functional/fixtures/kbn_archiver/annotation_listing_page_search'
@@ -122,8 +121,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await listingTable.expectItemsCount('eventAnnotation', 1);
});
- // FLAKY: https://github.com/elastic/kibana/issues/170568
- describe.skip('individual annotations', () => {
+ describe('individual annotations', () => {
it('edits an existing annotation', async function () {
await listingTable.clickItemLink('eventAnnotation', 'edited title');
expect(await PageObjects.annotationEditor.getAnnotationCount()).to.be(1);
@@ -156,11 +154,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
await PageObjects.annotationEditor.saveGroup();
- await listingTable.clearSearchFilter();
});
});
describe('data view switching', () => {
+ before(async () => {
+ await listingTable.clearSearchFilter();
+ });
+
it('recovers from missing data view', async () => {
await listingTable.clickItemLink('eventAnnotation', 'missing data view');
diff --git a/test/functional/page_objects/annotation_library_editor_page.ts b/test/functional/page_objects/annotation_library_editor_page.ts
index f5c66b9f6c1e9..2a031d98429b3 100644
--- a/test/functional/page_objects/annotation_library_editor_page.ts
+++ b/test/functional/page_objects/annotation_library_editor_page.ts
@@ -10,6 +10,7 @@ import { FtrService } from '../ftr_provider_context';
export class AnnotationEditorPageObject extends FtrService {
private readonly testSubjects = this.ctx.getService('testSubjects');
+ private readonly find = this.ctx.getService('find');
private readonly retry = this.ctx.getService('retry');
/**
@@ -56,12 +57,20 @@ export class AnnotationEditorPageObject extends FtrService {
const queryInput = await this.testSubjects.find('annotation-query-based-query-input');
await queryInput.type(config.query);
- await this.testSubjects.setValue('lnsXYThickness', '' + config.lineThickness);
+ const titles = await this.find.allByCssSelector(
+ '.euiFlyout h3.lnsDimensionEditorSection__heading'
+ );
+ const lastTitle = titles[titles.length - 1];
+ await lastTitle.click(); // close query input pop-up
+ await lastTitle.focus(); // scroll down to the bottom of the section
await this.testSubjects.setValue(
'euiColorPickerAnchor indexPattern-dimension-colorPicker',
config.color
);
+ await lastTitle.click(); // close color picker pop-up
+
+ await this.testSubjects.setValue('lnsXYThickness', '' + config.lineThickness);
await this.retry.waitFor('annotation editor UI to close', async () => {
await this.testSubjects.click('backToGroupSettings');
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 107b8e1f6ff46..40b1ede664328 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -700,6 +700,8 @@
"@kbn/encrypted-saved-objects-plugin/*": ["x-pack/plugins/encrypted_saved_objects/*"],
"@kbn/enterprise-search-plugin": ["x-pack/plugins/enterprise_search"],
"@kbn/enterprise-search-plugin/*": ["x-pack/plugins/enterprise_search/*"],
+ "@kbn/error-boundary-example-plugin": ["examples/error_boundary"],
+ "@kbn/error-boundary-example-plugin/*": ["examples/error_boundary/*"],
"@kbn/es": ["packages/kbn-es"],
"@kbn/es/*": ["packages/kbn-es/*"],
"@kbn/es-archiver": ["packages/kbn-es-archiver"],
diff --git a/x-pack/examples/exploratory_view_example/kibana.jsonc b/x-pack/examples/exploratory_view_example/kibana.jsonc
index c524e4fda32f7..6cf8fa64983ac 100644
--- a/x-pack/examples/exploratory_view_example/kibana.jsonc
+++ b/x-pack/examples/exploratory_view_example/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/exploratory-view-example-plugin",
- "owner": "@elastic/uptime",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "exploratoryViewExample",
"server": false,
diff --git a/x-pack/packages/kbn-infra-forge/kibana.jsonc b/x-pack/packages/kbn-infra-forge/kibana.jsonc
index a66a733662735..a450d148358a9 100644
--- a/x-pack/packages/kbn-infra-forge/kibana.jsonc
+++ b/x-pack/packages/kbn-infra-forge/kibana.jsonc
@@ -1,5 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/infra-forge",
- "owner": "@elastic/actionable-observability"
+ "owner": "@elastic/obs-ux-management-team"
}
diff --git a/x-pack/packages/kbn-slo-schema/kibana.jsonc b/x-pack/packages/kbn-slo-schema/kibana.jsonc
index 2d12cd108585c..b4ca324fc112b 100644
--- a/x-pack/packages/kbn-slo-schema/kibana.jsonc
+++ b/x-pack/packages/kbn-slo-schema/kibana.jsonc
@@ -1,5 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/slo-schema",
- "owner": "@elastic/actionable-observability",
+ "owner": "@elastic/obs-ux-management-team"
}
diff --git a/x-pack/packages/security-solution/navigation/src/navigation.test.ts b/x-pack/packages/security-solution/navigation/src/navigation.test.ts
index ab9ab891aaef8..a4290563476ea 100644
--- a/x-pack/packages/security-solution/navigation/src/navigation.test.ts
+++ b/x-pack/packages/security-solution/navigation/src/navigation.test.ts
@@ -7,7 +7,7 @@
import { useGetAppUrl, useNavigateTo } from './navigation';
import { mockGetUrlForApp, mockNavigateToApp, mockNavigateToUrl } from '../mocks/context';
import { renderHook } from '@testing-library/react-hooks';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
jest.mock('./context');
diff --git a/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx
index e6bd2a4071b27..d72f0bda9dc93 100644
--- a/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx
+++ b/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { MaintenanceWindow } from '../pages/maintenance_windows/types';
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
diff --git a/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx
index 195af1bb083e5..f827287532445 100644
--- a/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx
+++ b/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { MaintenanceWindow } from '../pages/maintenance_windows/types';
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
diff --git a/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx b/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx
index 2080b9ff39d43..d21b145aea937 100644
--- a/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx
+++ b/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
import { useFindMaintenanceWindows } from './use_find_maintenance_windows';
diff --git a/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx
index b80dbbae355bc..453a3b88cef8f 100644
--- a/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx
+++ b/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { MaintenanceWindow } from '../pages/maintenance_windows/types';
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
diff --git a/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx
index ed534cb835c8d..06608125fd836 100644
--- a/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx
+++ b/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { MaintenanceWindow } from '../pages/maintenance_windows/types';
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
diff --git a/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx
index eaef1f4fc4b99..3003f1003ce12 100644
--- a/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx
+++ b/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
import { useGetMaintenanceWindow } from './use_get_maintenance_window';
diff --git a/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx
index 897b44295d8c0..b29161f0e006d 100644
--- a/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx
+++ b/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { MaintenanceWindow } from '../pages/maintenance_windows/types';
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/status_filter.test.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/status_filter.test.tsx
index f7cb8023323ef..3875545e36df4 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/status_filter.test.tsx
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/status_filter.test.tsx
@@ -6,7 +6,7 @@
*/
import { Query } from '@elastic/eui';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import React from 'react';
import { AppMockRenderer, createAppMockRenderer } from '../../../lib/test_utils';
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/table_actions_popover.test.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/table_actions_popover.test.tsx
index 2b1a1057084f5..8da3e12847e3a 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/table_actions_popover.test.tsx
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/table_actions_popover.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import React from 'react';
import { AppMockRenderer, createAppMockRenderer } from '../../../lib/test_utils';
diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts
index 3b3cd3a972825..0c032dd6a3e92 100644
--- a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts
+++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts
@@ -301,6 +301,7 @@ describe('Execution Handler', () => {
foo: true,
stateVal: 'My goes here',
},
+ ruleName: rule.name,
});
expect(ruleRunMetricsStore.getTriggeredActionsStatus()).toBe(ActionsCompletion.COMPLETE);
@@ -1988,6 +1989,7 @@ describe('Execution Handler', () => {
"val": "rule url: http://localhost:12345/s/test1/app/management/insightsAndAlerting/triggersActions/rule/1",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": Object {
"absoluteUrl": "http://localhost:12345/s/test1/app/management/insightsAndAlerting/triggersActions/rule/1",
"basePathname": "",
@@ -2060,6 +2062,7 @@ describe('Execution Handler', () => {
"val": "rule url: http://localhost:12345/basePath/s/test1/app/test/rule/1?start=30000&end=90000",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": Object {
"absoluteUrl": "http://localhost:12345/basePath/s/test1/app/test/rule/1?start=30000&end=90000",
"basePathname": "/basePath",
@@ -2095,6 +2098,7 @@ describe('Execution Handler', () => {
"val": "rule url: http://localhost:12345/app/management/insightsAndAlerting/triggersActions/rule/1",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": Object {
"absoluteUrl": "http://localhost:12345/app/management/insightsAndAlerting/triggersActions/rule/1",
"basePathname": "",
@@ -2127,6 +2131,7 @@ describe('Execution Handler', () => {
"val": "rule url: http://localhost:12345/s/test1/app/management/insightsAndAlerting/triggersActions/rule/1",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": Object {
"absoluteUrl": "http://localhost:12345/s/test1/app/management/insightsAndAlerting/triggersActions/rule/1",
"basePathname": "",
@@ -2159,6 +2164,7 @@ describe('Execution Handler', () => {
"val": "rule url: ",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": undefined,
},
]
@@ -2188,6 +2194,7 @@ describe('Execution Handler', () => {
"val": "rule url: ",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": undefined,
},
]
@@ -2217,6 +2224,7 @@ describe('Execution Handler', () => {
"val": "rule url: ",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": undefined,
},
]
@@ -2249,6 +2257,7 @@ describe('Execution Handler', () => {
"val": "rule url: http://localhost:12345/s/test1/app/management/some/other/place",
},
"actionTypeId": "test",
+ "ruleName": "name-of-alert",
"ruleUrl": Object {
"absoluteUrl": "http://localhost:12345/s/test1/app/management/some/other/place",
"basePathname": "",
diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts
index 33c4c93abe111..288a4126c25a2 100644
--- a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts
+++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts
@@ -256,6 +256,7 @@ export class ExecutionHandler<
params: injectActionParams({
actionTypeId,
ruleUrl,
+ ruleName: this.rule.name,
actionParams: transformSummaryActionParams({
alerts: summarizedAlerts,
rule: this.rule,
@@ -296,6 +297,7 @@ export class ExecutionHandler<
params: injectActionParams({
actionTypeId,
ruleUrl,
+ ruleName: this.rule.name,
actionParams: transformActionParams({
actionsPlugin,
alertId: ruleId,
diff --git a/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts b/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts
index 9964f5f848b2d..d099c16bf52ed 100644
--- a/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts
+++ b/x-pack/plugins/alerting/server/task_runner/inject_action_params.test.ts
@@ -8,14 +8,16 @@
import { injectActionParams } from './inject_action_params';
describe('injectActionParams', () => {
- test(`passes through when actionTypeId isn't .email`, () => {
+ test(`passes through when actionTypeId isn't .email or .pagerduty`, () => {
const actionParams = {
message: 'State: "{{state.value}}", Context: "{{context.value}}"',
};
+
const result = injectActionParams({
actionParams,
actionTypeId: '.server-log',
});
+
expect(result).toMatchInlineSnapshot(`
Object {
"message": "State: \\"{{state.value}}\\", Context: \\"{{context.value}}\\"",
@@ -55,6 +57,146 @@ describe('injectActionParams', () => {
`);
});
+ test('injects the absoluteUrl to the links when actionTypeId is .pagerduty and there are no links', () => {
+ const actionParams = {
+ summary: 'My summary',
+ };
+
+ const ruleUrl = {
+ absoluteUrl:
+ 'http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1',
+ kibanaBaseUrl: 'http://localhost:5601',
+ basePathname: '',
+ spaceIdSegment: '',
+ relativePath: '/app/management/insightsAndAlerting/triggersActions/rule/1',
+ };
+
+ const result = injectActionParams({
+ actionParams,
+ actionTypeId: '.pagerduty',
+ ruleUrl,
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "links": Array [
+ Object {
+ "href": "http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1",
+ "text": "Elastic Rule \\"Unknown\\"",
+ },
+ ],
+ "summary": "My summary",
+ }
+ `);
+ });
+
+ test('adds the rule name if the rule is defined when actionTypeId is .pagerduty', () => {
+ const actionParams = {
+ summary: 'My summary',
+ };
+
+ const ruleUrl = {
+ absoluteUrl:
+ 'http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1',
+ kibanaBaseUrl: 'http://localhost:5601',
+ basePathname: '',
+ spaceIdSegment: '',
+ relativePath: '/app/management/insightsAndAlerting/triggersActions/rule/1',
+ };
+
+ const result = injectActionParams({
+ actionParams,
+ actionTypeId: '.pagerduty',
+ ruleUrl,
+ ruleName: 'My rule',
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "links": Array [
+ Object {
+ "href": "http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1",
+ "text": "Elastic Rule \\"My rule\\"",
+ },
+ ],
+ "summary": "My summary",
+ }
+ `);
+ });
+
+ test('does not produce a runtime error when the actionTypeId is .pagerduty and the links are not an array', () => {
+ const actionParams = {
+ summary: 'My summary',
+ links: 'error',
+ };
+
+ const ruleUrl = {
+ absoluteUrl:
+ 'http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1',
+ kibanaBaseUrl: 'http://localhost:5601',
+ basePathname: '',
+ spaceIdSegment: '',
+ relativePath: '/app/management/insightsAndAlerting/triggersActions/rule/1',
+ };
+
+ const result = injectActionParams({
+ actionParams,
+ actionTypeId: '.pagerduty',
+ ruleUrl,
+ ruleName: 'My rule',
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "links": Array [
+ Object {
+ "href": "http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1",
+ "text": "Elastic Rule \\"My rule\\"",
+ },
+ ],
+ "summary": "My summary",
+ }
+ `);
+ });
+
+ test('injects the absoluteUrl to the links when actionTypeId is .pagerduty with links', () => {
+ const actionParams = {
+ summary: 'My summary',
+ links: [{ href: 'https://example.com', text: 'My link' }],
+ };
+
+ const ruleUrl = {
+ absoluteUrl:
+ 'http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1',
+ kibanaBaseUrl: 'http://localhost:5601',
+ basePathname: '',
+ spaceIdSegment: '',
+ relativePath: '/app/management/insightsAndAlerting/triggersActions/rule/1',
+ };
+
+ const result = injectActionParams({
+ actionParams,
+ actionTypeId: '.pagerduty',
+ ruleUrl,
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "links": Array [
+ Object {
+ "href": "http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rule/1",
+ "text": "Elastic Rule \\"Unknown\\"",
+ },
+ Object {
+ "href": "https://example.com",
+ "text": "My link",
+ },
+ ],
+ "summary": "My summary",
+ }
+ `);
+ });
+
test('injects viewInKibanaPath and viewInKibanaText when actionTypeId is .email with basePathname and spaceId', () => {
const actionParams = {
body: {
@@ -88,16 +230,18 @@ describe('injectActionParams', () => {
`);
});
- test('injects viewInKibanaPath as empty string when the ruleUrl is undefined', () => {
+ test('injects viewInKibanaPath as empty string when the ruleUrl is undefined and the actionTypeId is .email', () => {
const actionParams = {
body: {
message: 'State: "{{state.value}}", Context: "{{context.value}}"',
},
};
+
const result = injectActionParams({
actionParams,
actionTypeId: '.email',
});
+
expect(result).toMatchInlineSnapshot(`
Object {
"body": Object {
@@ -110,4 +254,21 @@ describe('injectActionParams', () => {
}
`);
});
+
+ test('does not add the rule URL when the absoluteUrl is undefined and the actionTypeId is .pagerduty', () => {
+ const actionParams = {
+ summary: 'My summary',
+ };
+
+ const result = injectActionParams({
+ actionParams,
+ actionTypeId: '.pagerduty',
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "summary": "My summary",
+ }
+ `);
+ });
});
diff --git a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts
index 321819188f39a..65cb7f9e65bad 100644
--- a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts
+++ b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts
@@ -13,11 +13,13 @@ export interface InjectActionParamsOpts {
actionTypeId: string;
actionParams: RuleActionParams;
ruleUrl?: RuleUrl;
+ ruleName?: string;
}
export function injectActionParams({
actionTypeId,
actionParams,
+ ruleName,
ruleUrl = {},
}: InjectActionParamsOpts) {
// Inject kibanaFooterLink if action type is email. This is used by the email action type
@@ -36,6 +38,33 @@ export function injectActionParams({
};
}
+ if (actionTypeId === '.pagerduty') {
+ /**
+ * TODO: Remove and use connector adapters
+ */
+ const path = ruleUrl?.absoluteUrl ?? '';
+
+ if (path.length === 0) {
+ return actionParams;
+ }
+
+ const links = Array.isArray(actionParams.links) ? actionParams.links : [];
+
+ return {
+ ...actionParams,
+ links: [
+ {
+ href: path,
+ text: i18n.translate('xpack.alerting.injectActionParams.pagerduty.kibanaLinkText', {
+ defaultMessage: 'Elastic Rule "{ruleName}"',
+ values: { ruleName: ruleName ?? 'Unknown' },
+ }),
+ },
+ ...links,
+ ],
+ };
+ }
+
// Fallback, return action params unchanged
return actionParams;
}
diff --git a/x-pack/plugins/apm/kibana.jsonc b/x-pack/plugins/apm/kibana.jsonc
index 61ba6be743370..858cd142f399c 100644
--- a/x-pack/plugins/apm/kibana.jsonc
+++ b/x-pack/plugins/apm/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/apm-plugin",
- "owner": "@elastic/apm-ui",
+ "owner": "@elastic/obs-ux-infra_services-team",
"description": "The user interface for Elastic APM",
"plugin": {
"id": "apm",
diff --git a/x-pack/plugins/apm/public/components/app/mobile/service_overview/stats/stats.tsx b/x-pack/plugins/apm/public/components/app/mobile/service_overview/stats/stats.tsx
index a0caf4b3002ac..85e29bbe53e39 100644
--- a/x-pack/plugins/apm/public/components/app/mobile/service_overview/stats/stats.tsx
+++ b/x-pack/plugins/apm/public/components/app/mobile/service_overview/stats/stats.tsx
@@ -7,9 +7,9 @@
import { MetricDatum, MetricTrendShape } from '@elastic/charts';
import { i18n } from '@kbn/i18n';
import {
- EuiIcon,
EuiFlexGroup,
EuiFlexItem,
+ EuiIcon,
EuiLoadingSpinner,
} from '@elastic/eui';
import React, { useCallback } from 'react';
@@ -17,9 +17,9 @@ import { useTheme } from '@kbn/observability-shared-plugin/public';
import { NOT_AVAILABLE_LABEL } from '../../../../../../common/i18n';
import { useAnyOfApmParams } from '../../../../../hooks/use_apm_params';
import {
- useFetcher,
FETCH_STATUS,
isPending,
+ useFetcher,
} from '../../../../../hooks/use_fetcher';
import { MetricItem } from './metric_item';
import { usePreviousPeriodLabel } from '../../../../../hooks/use_previous_period_text';
@@ -120,17 +120,20 @@ export function MobileStats({
trendShape: MetricTrendShape.Area,
},
{
- color: euiTheme.eui.euiColorDisabled,
+ color: euiTheme.eui.euiColorLightestShade,
title: i18n.translate('xpack.apm.mobile.metrics.load.time', {
- defaultMessage: 'Slowest App load time',
- }),
- subtitle: i18n.translate('xpack.apm.mobile.coming.soon', {
- defaultMessage: 'Coming Soon',
+ defaultMessage: 'Average app load time',
}),
icon: getIcon('visGauge'),
- value: 'N/A',
- valueFormatter: (value: number) => valueFormatter(value, 's'),
- trend: [],
+ value: data?.currentPeriod?.launchTimes?.value ?? NaN,
+ valueFormatter: (value: number) =>
+ Number.isNaN(value)
+ ? NOT_AVAILABLE_LABEL
+ : valueFormatter(Number(value.toFixed(1)), 'ms'),
+ trend: data?.currentPeriod?.launchTimes?.timeseries,
+ extra: getComparisonValueFormatter(
+ data?.previousPeriod.launchTimes?.value?.toFixed(1)
+ ),
trendShape: MetricTrendShape.Area,
},
{
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx
index 1aa7c9ecb127b..f705244d6963e 100644
--- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx
+++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/accordion_waterfall.tsx
@@ -12,11 +12,13 @@ import {
EuiFlexItem,
EuiIcon,
EuiText,
+ EuiToolTip,
} from '@elastic/eui';
import { euiStyled } from '@kbn/kibana-react-plugin/common';
import { groupBy } from 'lodash';
import { transparentize } from 'polished';
import React, { useState } from 'react';
+import { asBigNumber } from '../../../../../../../common/utils/formatters';
import { getCriticalPath } from '../../../../../../../common/critical_path/get_critical_path';
import { useTheme } from '../../../../../../hooks/use_theme';
import { Margins } from '../../../../../shared/charts/timeline';
@@ -148,7 +150,7 @@ export function AccordionWaterfall(props: AccordionWaterfallProps) {
@@ -200,12 +202,12 @@ export function AccordionWaterfall(props: AccordionWaterfallProps) {
function ToggleAccordionButton({
show,
isOpen,
- childrenAmount,
+ childrenCount,
onClick,
}: {
show: boolean;
isOpen: boolean;
- childrenAmount: number;
+ childrenCount: number;
onClick: () => void;
}) {
if (!show) {
@@ -213,7 +215,12 @@ function ToggleAccordionButton({
}
return (
-
+
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
@@ -226,8 +233,18 @@ function ToggleAccordionButton({
-
- {childrenAmount}
+
+
+
+ {asBigNumber(childrenCount)}
+
+
diff --git a/x-pack/plugins/apm/server/routes/mobile/get_mobile_average_launch_time.ts b/x-pack/plugins/apm/server/routes/mobile/get_mobile_average_launch_time.ts
new file mode 100644
index 0000000000000..e711d5c72fb3b
--- /dev/null
+++ b/x-pack/plugins/apm/server/routes/mobile/get_mobile_average_launch_time.ts
@@ -0,0 +1,161 @@
+/*
+ * 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 { ProcessorEvent } from '@kbn/observability-plugin/common';
+import {
+ kqlQuery,
+ rangeQuery,
+ termQuery,
+} from '@kbn/observability-plugin/server';
+import { offsetPreviousPeriodCoordinates } from '../../../common/utils/offset_previous_period_coordinate';
+import { APP_LAUNCH_TIME, SERVICE_NAME } from '../../../common/es_fields/apm';
+import { environmentQuery } from '../../../common/utils/environment_query';
+import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms';
+import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
+import { getBucketSize } from '../../../common/utils/get_bucket_size';
+import { Coordinate } from '../../../typings/timeseries';
+import { Maybe } from '../../../typings/common';
+
+export interface AvgLaunchTimeTimeseries {
+ currentPeriod: { timeseries: Coordinate[]; value: Maybe };
+ previousPeriod: { timeseries: Coordinate[]; value: Maybe };
+}
+
+interface Props {
+ apmEventClient: APMEventClient;
+ serviceName: string;
+ transactionName?: string;
+ environment: string;
+ start: number;
+ end: number;
+ kuery: string;
+ offset?: string;
+}
+
+async function getAvgLaunchTimeTimeseries({
+ apmEventClient,
+ serviceName,
+ transactionName,
+ environment,
+ start,
+ end,
+ kuery,
+ offset,
+}: Props) {
+ const { startWithOffset, endWithOffset } = getOffsetInMs({
+ start,
+ end,
+ offset,
+ });
+
+ const { intervalString } = getBucketSize({
+ start: startWithOffset,
+ end: endWithOffset,
+ minBucketSize: 60,
+ });
+
+ const aggs = {
+ launchTimeAvg: {
+ avg: { field: APP_LAUNCH_TIME },
+ },
+ };
+
+ const response = await apmEventClient.search('get_mobile_launch_time', {
+ apm: {
+ events: [ProcessorEvent.metric],
+ },
+ body: {
+ track_total_hits: false,
+ size: 0,
+ query: {
+ bool: {
+ filter: [
+ ...termQuery(SERVICE_NAME, serviceName),
+ ...rangeQuery(startWithOffset, endWithOffset),
+ ...environmentQuery(environment),
+ ...kqlQuery(kuery),
+ ],
+ },
+ },
+ aggs: {
+ timeseries: {
+ date_histogram: {
+ field: '@timestamp',
+ fixed_interval: intervalString,
+ min_doc_count: 0,
+ extended_bounds: { min: startWithOffset, max: endWithOffset },
+ },
+ aggs,
+ },
+ ...aggs,
+ },
+ },
+ });
+
+ const timeseries =
+ response?.aggregations?.timeseries.buckets.map((bucket) => {
+ return {
+ x: bucket.key,
+ y: bucket.launchTimeAvg.value,
+ };
+ }) ?? [];
+
+ return {
+ timeseries,
+ value: response.aggregations?.launchTimeAvg?.value,
+ };
+}
+
+export async function getMobileAvgLaunchTime({
+ kuery,
+ apmEventClient,
+ serviceName,
+ transactionName,
+ environment,
+ start,
+ end,
+ offset,
+}: Props): Promise {
+ const options = {
+ serviceName,
+ transactionName,
+ apmEventClient,
+ kuery,
+ environment,
+ };
+
+ const currentPeriodPromise = getAvgLaunchTimeTimeseries({
+ ...options,
+ start,
+ end,
+ });
+
+ const previousPeriodPromise = offset
+ ? getAvgLaunchTimeTimeseries({
+ ...options,
+ start,
+ end,
+ offset,
+ })
+ : { timeseries: [], value: null };
+
+ const [currentPeriod, previousPeriod] = await Promise.all([
+ currentPeriodPromise,
+ previousPeriodPromise,
+ ]);
+
+ return {
+ currentPeriod,
+ previousPeriod: {
+ timeseries: offsetPreviousPeriodCoordinates({
+ currentPeriodTimeseries: currentPeriod.timeseries,
+ previousPeriodTimeseries: previousPeriod.timeseries,
+ }),
+ value: previousPeriod?.value,
+ },
+ };
+}
diff --git a/x-pack/plugins/apm/server/routes/mobile/get_mobile_stats.ts b/x-pack/plugins/apm/server/routes/mobile/get_mobile_stats.ts
index 071487298ab7a..116117426405c 100644
--- a/x-pack/plugins/apm/server/routes/mobile/get_mobile_stats.ts
+++ b/x-pack/plugins/apm/server/routes/mobile/get_mobile_stats.ts
@@ -10,16 +10,19 @@ import { getOffsetInMs } from '../../../common/utils/get_offset_in_ms';
import { getMobileSessions } from './get_mobile_sessions';
import { getMobileHttpRequests } from './get_mobile_http_requests';
import { getMobileCrashRate } from './get_mobile_crash_rate';
+import { getMobileAvgLaunchTime } from './get_mobile_average_launch_time';
import { Maybe } from '../../../typings/common';
export interface Timeseries {
x: number;
y: number;
}
+
interface MobileStats {
sessions: { timeseries: Timeseries[]; value: Maybe };
requests: { timeseries: Timeseries[]; value: Maybe };
crashRate: { timeseries: Timeseries[]; value: Maybe };
+ launchTimes: { timeseries: Timeseries[]; value: Maybe };
}
export interface MobilePeriodStats {
@@ -62,10 +65,11 @@ async function getMobileStats({
offset,
};
- const [sessions, httpRequests, crashes] = await Promise.all([
+ const [sessions, httpRequests, crashes, launchTimeAvg] = await Promise.all([
getMobileSessions({ ...commonProps }),
getMobileHttpRequests({ ...commonProps }),
getMobileCrashRate({ ...commonProps }),
+ getMobileAvgLaunchTime({ ...commonProps }),
]);
return {
@@ -89,6 +93,10 @@ async function getMobileStats({
};
}) as Timeseries[],
},
+ launchTimes: {
+ value: launchTimeAvg.currentPeriod.value,
+ timeseries: launchTimeAvg.currentPeriod.timeseries as Timeseries[],
+ },
};
}
@@ -123,6 +131,7 @@ export async function getMobileStatsPeriods({
sessions: { timeseries: [], value: null },
requests: { timeseries: [], value: null },
crashRate: { timeseries: [], value: null },
+ launchTimes: { timeseries: [], value: null },
};
const [currentPeriod, previousPeriod] = await Promise.all([
diff --git a/x-pack/plugins/apm_data_access/kibana.jsonc b/x-pack/plugins/apm_data_access/kibana.jsonc
index d0ee0befda101..ede5cd53c9a6c 100644
--- a/x-pack/plugins/apm_data_access/kibana.jsonc
+++ b/x-pack/plugins/apm_data_access/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/apm-data-access-plugin",
- "owner": "@elastic/apm-ui",
+ "owner": ["@elastic/obs-knowledge-team", "@elastic/obs-ux-infra_services-team"],
"plugin": {
"id": "apmDataAccess",
"server": true,
diff --git a/x-pack/plugins/asset_manager/kibana.jsonc b/x-pack/plugins/asset_manager/kibana.jsonc
index b3fcd1b3a4fa1..1ee4b12d55ea7 100644
--- a/x-pack/plugins/asset_manager/kibana.jsonc
+++ b/x-pack/plugins/asset_manager/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/assetManager-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-knowledge-team",
"description": "Asset manager plugin for entity assets (inventory, topology, etc)",
"plugin": {
"id": "assetManager",
diff --git a/x-pack/plugins/cases/docs/openapi/bundled.json b/x-pack/plugins/cases/docs/openapi/bundled.json
index 80cdefd30e957..54a9c31d34312 100644
--- a/x-pack/plugins/cases/docs/openapi/bundled.json
+++ b/x-pack/plugins/cases/docs/openapi/bundled.json
@@ -1206,8 +1206,11 @@
"$ref": "#/components/schemas/case_response_properties"
},
"examples": {
- "getCaseResponse": {
+ "getDefaultCaseResponse": {
"$ref": "#/components/examples/get_case_response"
+ },
+ "getDefaultObservabilityCaseReponse": {
+ "$ref": "#/components/examples/get_case_observability_response"
}
}
}
@@ -3078,6 +3081,9 @@
"examples": {
"getCaseResponse": {
"$ref": "#/components/examples/get_case_response"
+ },
+ "getObservabilityCaseReponse": {
+ "$ref": "#/components/examples/get_case_observability_response"
}
}
}
@@ -4614,13 +4620,16 @@
],
"properties": {
"alertId": {
- "type": "string",
- "example": "6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42"
+ "type": "array",
+ "items": {
+ "type": "string",
+ "example": "a6e12ac4-7bce-457b-84f6-d7ce8deb8446"
+ }
},
"created_at": {
"type": "string",
"format": "date-time",
- "example": "2022-03-24T02:31:03.210Z"
+ "example": "2023-11-06T19:29:38.424Z"
},
"created_by": {
"type": "object",
@@ -4656,8 +4665,11 @@
"example": "73362370-ab1a-11ec-985f-97e55adae8b9"
},
"index": {
- "type": "string",
- "example": ".internal.alerts-security.alerts-default-000001"
+ "type": "array",
+ "items": {
+ "type": "string",
+ "example": ".internal.alerts-security.alerts-default-000001"
+ }
},
"owner": {
"$ref": "#/components/schemas/owners"
@@ -4723,10 +4735,11 @@
"updated_at": {
"type": "string",
"format": "date-time",
- "example": null
+ "nullable": true
},
"updated_by": {
"type": "object",
+ "nullable": true,
"required": [
"email",
"full_name",
@@ -6971,6 +6984,7 @@
"syncAlerts": true
},
"owner": "cases",
+ "category": null,
"customFields": [
{
"type": "text",
@@ -7017,6 +7031,104 @@
"external_service": null
}
},
+ "get_case_observability_response": {
+ "summary": "Retrieves information about an Observability case including its alerts and comments.",
+ "value": {
+ "description": "An Observability case description.",
+ "owner": "observability",
+ "settings": {
+ "syncAlerts": false
+ },
+ "tags": [
+ "observability",
+ "tag 1"
+ ],
+ "title": "Observability case title 1",
+ "category": null,
+ "customFields": [],
+ "assignees": [
+ {
+ "uid": "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0"
+ }
+ ],
+ "connector": {
+ "id": "none",
+ "type": ".none",
+ "fields": null,
+ "name": "none"
+ },
+ "severity": "low",
+ "status": "in-progress",
+ "duration": null,
+ "closed_at": null,
+ "closed_by": null,
+ "created_at": "2023-11-06T19:29:04.086Z",
+ "created_by": {
+ "username": "elastic",
+ "full_name": null,
+ "email": null
+ },
+ "updated_at": "2023-11-06T19:47:55.662Z",
+ "updated_by": {
+ "username": "elastic",
+ "full_name": null,
+ "email": null,
+ "profile_uid": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"
+ },
+ "external_service": null,
+ "id": "c3ff7550-def1-4e90-b6bc-c9969a4a09b1",
+ "version": "WzI0NywyXQ==",
+ "totalComment": 1,
+ "totalAlerts": 1,
+ "comments": [
+ {
+ "alertId": [
+ "a6e12ac4-7bce-457b-84f6-d7ce8deb8446"
+ ],
+ "index": [
+ ".internal.alerts-observability.logs.alerts-default-000001"
+ ],
+ "type": "alert",
+ "rule": {
+ "id": "03e4eb87-62ca-4e5d-9570-3d7625e9669d",
+ "name": "Observability rule"
+ },
+ "owner": "observability",
+ "created_at": "2023-11-06T19:29:38.424Z",
+ "created_by": {
+ "email": null,
+ "full_name": null,
+ "username": "elastic",
+ "profile_uid": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"
+ },
+ "pushed_at": null,
+ "pushed_by": null,
+ "updated_at": null,
+ "updated_by": null,
+ "id": "59d438d0-79a9-4864-8d4b-e63adacebf6e",
+ "version": "WzY3LDJd"
+ },
+ {
+ "comment": "The first comment.",
+ "type": "user",
+ "owner": "observability",
+ "created_at": "2023-11-06T19:29:57.812Z",
+ "created_by": {
+ "email": null,
+ "full_name": null,
+ "username": "elastic",
+ "profile_uid": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"
+ },
+ "pushed_at": null,
+ "pushed_by": null,
+ "updated_at": null,
+ "updated_by": null,
+ "id": "d99342d3-3aa3-4b80-90ec-a702607604f5",
+ "version": "WzcyLDJd"
+ }
+ ]
+ }
+ },
"get_case_alerts_response": {
"summary": "Retrieves all alerts attached to a case",
"value": [
diff --git a/x-pack/plugins/cases/docs/openapi/bundled.yaml b/x-pack/plugins/cases/docs/openapi/bundled.yaml
index ec5c1db337f29..8347d7d85741b 100644
--- a/x-pack/plugins/cases/docs/openapi/bundled.yaml
+++ b/x-pack/plugins/cases/docs/openapi/bundled.yaml
@@ -811,8 +811,10 @@ paths:
schema:
$ref: '#/components/schemas/case_response_properties'
examples:
- getCaseResponse:
+ getDefaultCaseResponse:
$ref: '#/components/examples/get_case_response'
+ getDefaultObservabilityCaseReponse:
+ $ref: '#/components/examples/get_case_observability_response'
'401':
description: Authorization information is missing or invalid.
content:
@@ -2017,6 +2019,8 @@ paths:
examples:
getCaseResponse:
$ref: '#/components/examples/get_case_response'
+ getObservabilityCaseReponse:
+ $ref: '#/components/examples/get_case_observability_response'
'401':
description: Authorization information is missing or invalid.
content:
@@ -3068,12 +3072,14 @@ components:
- type
properties:
alertId:
- type: string
- example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42
+ type: array
+ items:
+ type: string
+ example: a6e12ac4-7bce-457b-84f6-d7ce8deb8446
created_at:
type: string
format: date-time
- example: '2022-03-24T02:31:03.210Z'
+ example: '2023-11-06T19:29:38.424Z'
created_by:
type: object
required:
@@ -3100,8 +3106,10 @@ components:
type: string
example: 73362370-ab1a-11ec-985f-97e55adae8b9
index:
- type: string
- example: .internal.alerts-security.alerts-default-000001
+ type: array
+ items:
+ type: string
+ example: .internal.alerts-security.alerts-default-000001
owner:
$ref: '#/components/schemas/owners'
pushed_at:
@@ -3151,9 +3159,10 @@ components:
updated_at:
type: string
format: date-time
- example: null
+ nullable: true
updated_by:
type: object
+ nullable: true
required:
- email
- full_name
@@ -4769,6 +4778,7 @@ components:
settings:
syncAlerts: true
owner: cases
+ category: null
customFields:
- type: text
key: d312efda-ec2b-42ec-9e2c-84981795c581
@@ -4802,6 +4812,84 @@ components:
type: .none
fields: null
external_service: null
+ get_case_observability_response:
+ summary: Retrieves information about an Observability case including its alerts and comments.
+ value:
+ description: An Observability case description.
+ owner: observability
+ settings:
+ syncAlerts: false
+ tags:
+ - observability
+ - tag 1
+ title: Observability case title 1
+ category: null
+ customFields: []
+ assignees:
+ - uid: u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0
+ connector:
+ id: none
+ type: .none
+ fields: null
+ name: none
+ severity: low
+ status: in-progress
+ duration: null
+ closed_at: null
+ closed_by: null
+ created_at: '2023-11-06T19:29:04.086Z'
+ created_by:
+ username: elastic
+ full_name: null
+ email: null
+ updated_at: '2023-11-06T19:47:55.662Z'
+ updated_by:
+ username: elastic
+ full_name: null
+ email: null
+ profile_uid: u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0
+ external_service: null
+ id: c3ff7550-def1-4e90-b6bc-c9969a4a09b1
+ version: WzI0NywyXQ==
+ totalComment: 1
+ totalAlerts: 1
+ comments:
+ - alertId:
+ - a6e12ac4-7bce-457b-84f6-d7ce8deb8446
+ index:
+ - .internal.alerts-observability.logs.alerts-default-000001
+ type: alert
+ rule:
+ id: 03e4eb87-62ca-4e5d-9570-3d7625e9669d
+ name: Observability rule
+ owner: observability
+ created_at: '2023-11-06T19:29:38.424Z'
+ created_by:
+ email: null
+ full_name: null
+ username: elastic
+ profile_uid: u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0
+ pushed_at: null
+ pushed_by: null
+ updated_at: null
+ updated_by: null
+ id: 59d438d0-79a9-4864-8d4b-e63adacebf6e
+ version: WzY3LDJd
+ - comment: The first comment.
+ type: user
+ owner: observability
+ created_at: '2023-11-06T19:29:57.812Z'
+ created_by:
+ email: null
+ full_name: null
+ username: elastic
+ profile_uid: u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0
+ pushed_at: null
+ pushed_by: null
+ updated_at: null
+ updated_by: null
+ id: d99342d3-3aa3-4b80-90ec-a702607604f5
+ version: WzcyLDJd
get_case_alerts_response:
summary: Retrieves all alerts attached to a case
value:
diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/get_case_observability_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/get_case_observability_response.yaml
new file mode 100644
index 0000000000000..49b9aa692a335
--- /dev/null
+++ b/x-pack/plugins/cases/docs/openapi/components/examples/get_case_observability_response.yaml
@@ -0,0 +1,97 @@
+summary: Retrieves information about an Observability case including its alerts and comments.
+value:
+ {
+ "description": "An Observability case description.",
+ "owner": "observability",
+ "settings": {
+ "syncAlerts": false
+ },
+ "tags": [
+ "observability",
+ "tag 1"
+ ],
+ "title": "Observability case title 1",
+ "category": null,
+ "customFields": [],
+ "assignees": [
+ {
+ "uid": "u_0wpfV1MqYDaXzLtRVY-gLMrddKDEmfz51Fszhj7hWC8_0"
+ }
+ ],
+ "connector": {
+ "id": "none",
+ "type": ".none",
+ "fields": null,
+ "name": "none"
+ },
+ "severity": "low",
+ "status": "in-progress",
+ "duration": null,
+ "closed_at": null,
+ "closed_by": null,
+ "created_at": "2023-11-06T19:29:04.086Z",
+ "created_by": {
+ "username": "elastic",
+ "full_name": null,
+ "email": null
+ },
+ "updated_at": "2023-11-06T19:47:55.662Z",
+ "updated_by": {
+ "username": "elastic",
+ "full_name": null,
+ "email": null,
+ "profile_uid": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"
+ },
+ "external_service": null,
+ "id": "c3ff7550-def1-4e90-b6bc-c9969a4a09b1",
+ "version": "WzI0NywyXQ==",
+ "totalComment": 1,
+ "totalAlerts": 1,
+ "comments": [
+ {
+ "alertId": [
+ "a6e12ac4-7bce-457b-84f6-d7ce8deb8446"
+ ],
+ "index": [
+ ".internal.alerts-observability.logs.alerts-default-000001"
+ ],
+ "type": "alert",
+ "rule": {
+ "id": "03e4eb87-62ca-4e5d-9570-3d7625e9669d",
+ "name": "Observability rule"
+ },
+ "owner": "observability",
+ "created_at": "2023-11-06T19:29:38.424Z",
+ "created_by": {
+ "email": null,
+ "full_name": null,
+ "username": "elastic",
+ "profile_uid": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"
+ },
+ "pushed_at": null,
+ "pushed_by": null,
+ "updated_at": null,
+ "updated_by": null,
+ "id": "59d438d0-79a9-4864-8d4b-e63adacebf6e",
+ "version": "WzY3LDJd"
+ },
+ {
+ "comment": "The first comment.",
+ "type": "user",
+ "owner": "observability",
+ "created_at": "2023-11-06T19:29:57.812Z",
+ "created_by": {
+ "email": null,
+ "full_name": null,
+ "username": "elastic",
+ "profile_uid": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0"
+ },
+ "pushed_at": null,
+ "pushed_by": null,
+ "updated_at": null,
+ "updated_by": null,
+ "id": "d99342d3-3aa3-4b80-90ec-a702607604f5",
+ "version": "WzcyLDJd"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml
index d4fc3db97a169..50dabd2dc8a9b 100644
--- a/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml
+++ b/x-pack/plugins/cases/docs/openapi/components/examples/get_case_response.yaml
@@ -27,6 +27,7 @@ value:
"tags":["tag 1"],
"settings":{"syncAlerts":true},
"owner":"cases",
+ "category":null,
"customFields": [
{
"type": "text",
diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml
index aa39aad1381a0..443d9dcc55523 100644
--- a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml
+++ b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml
@@ -4,12 +4,14 @@ required:
- type
properties:
alertId:
- type: string
- example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42
+ type: array
+ items:
+ type: string
+ example: a6e12ac4-7bce-457b-84f6-d7ce8deb8446
created_at:
type: string
format: date-time
- example: 2022-03-24T02:31:03.210Z
+ example: 2023-11-06T19:29:38.424Z
created_by:
type: object
required:
@@ -22,8 +24,10 @@ properties:
type: string
example: 73362370-ab1a-11ec-985f-97e55adae8b9
index:
- type: string
- example: .internal.alerts-security.alerts-default-000001
+ type: array
+ items:
+ type: string
+ example: .internal.alerts-security.alerts-default-000001
owner:
$ref: 'owners.yaml'
pushed_at:
@@ -52,9 +56,10 @@ properties:
updated_at:
type: string
format: date-time
- example: null
+ nullable: true
updated_by:
type: object
+ nullable: true
required:
- email
- full_name
diff --git a/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}.yaml b/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}.yaml
index 9629049c9b342..c5b52a52b741f 100644
--- a/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}.yaml
+++ b/x-pack/plugins/cases/docs/openapi/paths/api@cases@{caseid}.yaml
@@ -18,8 +18,10 @@ get:
schema:
$ref: '../components/schemas/case_response_properties.yaml'
examples:
- getCaseResponse:
+ getDefaultCaseResponse:
$ref: '../components/examples/get_case_response.yaml'
+ getDefaultObservabilityCaseReponse:
+ $ref: '../components/examples/get_case_observability_response.yaml'
'401':
description: Authorization information is missing or invalid.
content:
diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml
index 32e3434f15add..aecd3f6394bb7 100644
--- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml
+++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml
@@ -21,6 +21,8 @@ get:
examples:
getCaseResponse:
$ref: '../components/examples/get_case_response.yaml'
+ getObservabilityCaseReponse:
+ $ref: '../components/examples/get_case_observability_response.yaml'
'401':
description: Authorization information is missing or invalid.
content:
diff --git a/x-pack/plugins/cases/public/common/mock/test_providers.tsx b/x-pack/plugins/cases/public/common/mock/test_providers.tsx
index 7dfed5d7188de..846ae8172b327 100644
--- a/x-pack/plugins/cases/public/common/mock/test_providers.tsx
+++ b/x-pack/plugins/cases/public/common/mock/test_providers.tsx
@@ -11,6 +11,7 @@ import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';
+import { render as reactRender } from '@testing-library/react';
import type { RenderOptions, RenderResult } from '@testing-library/react';
import type { ILicense } from '@kbn/licensing-plugin/public';
import type { ScopedFilesClient } from '@kbn/files-plugin/public';
@@ -20,7 +21,6 @@ import { I18nProvider } from '@kbn/i18n-react';
import { createMockFilesClient } from '@kbn/shared-ux-file-mocks';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { render as reactRender } from '@testing-library/react';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { FilesContext } from '@kbn/shared-ux-file-context';
diff --git a/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx b/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx
index d6597e31362e7..53fe9118a6aa0 100644
--- a/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx
+++ b/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx
@@ -14,7 +14,7 @@ import { alertComment, basicComment, mockCase } from '../containers/mock';
import React from 'react';
import userEvent from '@testing-library/user-event';
import type { SupportedCaseAttachment } from '../types';
-import { getByTestId } from '@testing-library/dom';
+import { getByTestId } from '@testing-library/react';
import { OWNER_INFO } from '../../common/constants';
jest.mock('./lib/kibana');
diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx
index 2cfaacc8383ca..a80e1935d1add 100644
--- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx
+++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { act, renderHook } from '@testing-library/react-hooks';
import userEvent from '@testing-library/user-event';
import React from 'react';
diff --git a/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx b/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx
index 30d5c75e63589..26169e16c5bed 100644
--- a/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx
+++ b/x-pack/plugins/cases/public/components/all_cases/severity_filter.test.tsx
@@ -10,7 +10,7 @@ import React from 'react';
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
import userEvent from '@testing-library/user-event';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
import { SeverityFilter } from './severity_filter';
diff --git a/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx
index 0efc7a5862893..ecc9233fc327c 100644
--- a/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx
+++ b/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx
@@ -6,7 +6,7 @@
*/
import userEvent from '@testing-library/user-event';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks/dom';
import { useActions } from './use_actions';
diff --git a/x-pack/plugins/cases/public/components/case_action_bar/actions.test.tsx b/x-pack/plugins/cases/public/components/case_action_bar/actions.test.tsx
index c79e88ce350ab..ef97a5f8d854d 100644
--- a/x-pack/plugins/cases/public/components/case_action_bar/actions.test.tsx
+++ b/x-pack/plugins/cases/public/components/case_action_bar/actions.test.tsx
@@ -13,7 +13,7 @@ import { basicCase, basicPush } from '../../containers/mock';
import { Actions } from './actions';
import * as i18n from '../case_view/translations';
import * as api from '../../containers/api';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
jest.mock('../../containers/api');
diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx
index cba9169590839..b85dbe7564cf9 100644
--- a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx
+++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { OBSERVABILITY_OWNER } from '../../../../common/constants';
import { alertCommentWithIndices, basicCase } from '../../../containers/mock';
import type { AppMockRenderer } from '../../../common/mock';
diff --git a/x-pack/plugins/cases/public/components/case_view/index.test.tsx b/x-pack/plugins/cases/public/components/case_view/index.test.tsx
index 07b58820b52b7..13524989bc7b8 100644
--- a/x-pack/plugins/cases/public/components/case_view/index.test.tsx
+++ b/x-pack/plugins/cases/public/components/case_view/index.test.tsx
@@ -30,7 +30,7 @@ import { useGetSupportedActionConnectors } from '../../containers/configure/use_
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
import CaseView from '.';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { useGetTags } from '../../containers/use_get_tags';
import { casesQueriesKeys } from '../../containers/constants';
import {
diff --git a/x-pack/plugins/cases/public/components/create/form.test.tsx b/x-pack/plugins/cases/public/components/create/form.test.tsx
index e7bd2fc754f34..05e7788624800 100644
--- a/x-pack/plugins/cases/public/components/create/form.test.tsx
+++ b/x-pack/plugins/cases/public/components/create/form.test.tsx
@@ -7,8 +7,7 @@
import React from 'react';
import { mount } from 'enzyme';
-import { act, render, within, fireEvent } from '@testing-library/react';
-import { waitFor } from '@testing-library/dom';
+import { act, render, within, fireEvent, waitFor } from '@testing-library/react';
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';
import { NONE_CONNECTOR_ID } from '../../../common/constants';
diff --git a/x-pack/plugins/cases/public/components/create/severity.test.tsx b/x-pack/plugins/cases/public/components/create/severity.test.tsx
index 328b9b4cd5e00..bf81dfc357fc7 100644
--- a/x-pack/plugins/cases/public/components/create/severity.test.tsx
+++ b/x-pack/plugins/cases/public/components/create/severity.test.tsx
@@ -15,7 +15,7 @@ import { Severity } from './severity';
import type { FormProps } from './schema';
import { schema } from './schema';
import userEvent from '@testing-library/user-event';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
let globalForm: FormHook;
diff --git a/x-pack/plugins/cases/public/components/custom_fields/index.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/index.test.tsx
index d81e31ba69d6d..7864361063b31 100644
--- a/x-pack/plugins/cases/public/components/custom_fields/index.test.tsx
+++ b/x-pack/plugins/cases/public/components/custom_fields/index.test.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
-import { screen, waitFor } from '@testing-library/dom';
+import { screen, waitFor } from '@testing-library/react';
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
diff --git a/x-pack/plugins/cases/public/components/experimental_badge/experimental_badge.test.tsx b/x-pack/plugins/cases/public/components/experimental_badge/experimental_badge.test.tsx
index a13aea90e8e6e..38b5960898cf0 100644
--- a/x-pack/plugins/cases/public/components/experimental_badge/experimental_badge.test.tsx
+++ b/x-pack/plugins/cases/public/components/experimental_badge/experimental_badge.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { screen } from '@testing-library/dom';
+import { screen } from '@testing-library/react';
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx
index 9c911e5aa89b4..a32ece05eac74 100644
--- a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx
+++ b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_existing_case.test.tsx
@@ -24,7 +24,7 @@ import {
mockTimeRange,
} from './mocks';
import { useKibana } from '../../../common/lib/kibana';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { canUseCases } from '../../../client/helpers/can_use_cases';
import { getCaseOwnerByAppId } from '../../../../common/utils/owner';
diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_new_case.test.tsx b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_new_case.test.tsx
index f55f95cbfb0ec..3549ca3301d18 100644
--- a/x-pack/plugins/cases/public/components/visualizations/actions/add_to_new_case.test.tsx
+++ b/x-pack/plugins/cases/public/components/visualizations/actions/add_to_new_case.test.tsx
@@ -8,7 +8,7 @@
import { LENS_EMBEDDABLE_TYPE, type Embeddable as LensEmbeddable } from '@kbn/lens-plugin/public';
import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public';
import type { Action } from '@kbn/ui-actions-plugin/public';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { createAddToNewCaseLensAction } from './add_to_new_case';
import type { ActionContext } from './types';
diff --git a/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx
index 1cb8685e26cbf..d625e247cb572 100644
--- a/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx
+++ b/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx
@@ -8,7 +8,7 @@
import { renderHook } from '@testing-library/react-hooks';
import { useGetCaseConfiguration } from './use_get_case_configuration';
import * as api from './api';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { useToasts } from '../../common/lib/kibana';
import type { AppMockRenderer } from '../../common/mock';
import { createAppMockRenderer } from '../../common/mock';
diff --git a/x-pack/plugins/cases/public/containers/use_get_case.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case.test.tsx
index 0514acf4a71ea..2b5082a9e22a5 100644
--- a/x-pack/plugins/cases/public/containers/use_get_case.test.tsx
+++ b/x-pack/plugins/cases/public/containers/use_get_case.test.tsx
@@ -8,7 +8,7 @@
import { renderHook } from '@testing-library/react-hooks';
import { useGetCase } from './use_get_case';
import * as api from './api';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useToasts } from '../common/lib/kibana';
diff --git a/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx b/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx
index fdec17c215fda..298abb5d133e7 100644
--- a/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx
+++ b/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx
@@ -6,7 +6,7 @@
*/
import { renderHook } from '@testing-library/react-hooks';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { useToasts } from '../common/lib/kibana';
import type { AppMockRenderer } from '../common/mock';
import { createAppMockRenderer } from '../common/mock';
diff --git a/x-pack/plugins/cases/server/services/notifications/templates/assignees/renderer.test.ts b/x-pack/plugins/cases/server/services/notifications/templates/assignees/renderer.test.ts
index ecd0bc08393bb..fb6509aeceeb4 100644
--- a/x-pack/plugins/cases/server/services/notifications/templates/assignees/renderer.test.ts
+++ b/x-pack/plugins/cases/server/services/notifications/templates/assignees/renderer.test.ts
@@ -6,7 +6,7 @@
*/
import { mockCases } from '../../../../mocks';
-import { getByText } from '@testing-library/dom';
+import { getByText } from '@testing-library/react';
import { assigneesTemplateRenderer } from './renderer';
import type { CaseSavedObjectTransformed } from '../../../../common/types/case';
diff --git a/x-pack/plugins/cases/server/services/notifications/templates/assignees/template.test.ts b/x-pack/plugins/cases/server/services/notifications/templates/assignees/template.test.ts
index b888cd6017b24..79589f4e58bef 100644
--- a/x-pack/plugins/cases/server/services/notifications/templates/assignees/template.test.ts
+++ b/x-pack/plugins/cases/server/services/notifications/templates/assignees/template.test.ts
@@ -6,7 +6,7 @@
*/
import { mockCases } from '../../../../mocks';
-import { getByText } from '@testing-library/dom';
+import { getByText } from '@testing-library/react';
import { assigneesTemplateRenderer } from './renderer';
import type { CaseSavedObjectTransformed } from '../../../../common/types/case';
diff --git a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx
index 3f6c78fe6b2ef..8f866079ab160 100644
--- a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx
@@ -45,7 +45,7 @@ export const ComplianceScoreBar = ({
gutterSize="none"
alignItems="center"
justifyContent="flexEnd"
- style={{ gap: euiTheme.size.s }}
+ style={{ gap: euiTheme.size.xs }}
>
-
+
-
+
+ -
+
+
-
{
return (
<>
-
+
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx
index 0545d4f3bb429..04c8382529593 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.test.tsx
@@ -6,13 +6,12 @@
*/
import React from 'react';
-import { render } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
import { expectIdsInDoc } from '../../../test/utils';
import { DASHBOARD_COUNTER_CARDS } from '../test_subjects';
import { SummarySection } from './summary_section';
import { mockDashboardData } from '../mock';
import { TestProvider } from '../../../test/test_provider';
-import { screen } from '@testing-library/react';
import { KSPM_POLICY_TEMPLATE } from '../../../../common/constants';
describe('', () => {
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx
index 524e893092e53..a6bb3b5bc08e3 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx
@@ -22,6 +22,7 @@ import {
EuiIcon,
EuiPagination,
EuiFlyoutFooter,
+ EuiToolTip,
} from '@elastic/eui';
import { assertNever } from '@kbn/std';
import { i18n } from '@kbn/i18n';
@@ -98,7 +99,9 @@ export const CisKubernetesIcons = ({
}) => (
-
+
+
+
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/engine_assignment_selector.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/engine_assignment_selector.test.tsx
index a8f8b2af988f2..74ca02e1d91db 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/engine_assignment_selector.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/engine_assignment_selector.test.tsx
@@ -13,7 +13,7 @@ import { engines } from '../../__mocks__/engines.mock';
import React from 'react';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { shallow } from 'enzyme';
import { EuiComboBox, EuiComboBoxOptionOption, EuiRadioGroup } from '@elastic/eui';
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/group_assignment_selector.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/group_assignment_selector.test.tsx
index 9312b1b6bbdb2..1cea94e434de1 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/group_assignment_selector.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/group_assignment_selector.test.tsx
@@ -11,7 +11,7 @@ import { setMockActions, setMockValues } from '../../../__mocks__/kea_logic';
import React from 'react';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { shallow } from 'enzyme';
import { EuiComboBox, EuiComboBoxOptionOption, EuiRadioGroup } from '@elastic/eui';
diff --git a/x-pack/plugins/enterprise_search/server/plugin.ts b/x-pack/plugins/enterprise_search/server/plugin.ts
index 4a5e3689ded5c..baaa772989eb2 100644
--- a/x-pack/plugins/enterprise_search/server/plugin.ts
+++ b/x-pack/plugins/enterprise_search/server/plugin.ts
@@ -103,7 +103,9 @@ export interface PluginsStart {
export interface RouteDependencies {
config: ConfigType;
enterpriseSearchRequestHandler: IEnterpriseSearchRequestHandler;
+
getSavedObjectsService?(): SavedObjectsServiceStart;
+
log: Logger;
ml?: MlPluginSetup;
router: IRouter;
@@ -112,6 +114,7 @@ export interface RouteDependencies {
export class EnterpriseSearchPlugin implements Plugin {
private readonly config: ConfigType;
private readonly logger: Logger;
+
/**
* Exposed services
*/
@@ -177,42 +180,47 @@ export class EnterpriseSearchPlugin implements Plugin {
/**
* Register user access to the Enterprise Search plugins
*/
- capabilities.registerSwitcher(async (request: KibanaRequest) => {
- const [, { spaces }] = await getStartServices();
-
- const dependencies = { config, security, spaces, request, log, ml };
-
- const { hasAppSearchAccess, hasWorkplaceSearchAccess } = await checkAccess(dependencies);
- const showEnterpriseSearch =
- hasAppSearchAccess || hasWorkplaceSearchAccess || !config.canDeployEntSearch;
-
- return {
- navLinks: {
- enterpriseSearch: showEnterpriseSearch,
- enterpriseSearchContent: showEnterpriseSearch,
- enterpriseSearchAnalytics: showEnterpriseSearch,
- enterpriseSearchApplications: showEnterpriseSearch,
- enterpriseSearchAISearch: showEnterpriseSearch,
- enterpriseSearchVectorSearch: showEnterpriseSearch,
- enterpriseSearchElasticsearch: showEnterpriseSearch,
- appSearch: hasAppSearchAccess && config.canDeployEntSearch,
- workplaceSearch: hasWorkplaceSearchAccess && config.canDeployEntSearch,
- searchExperiences: showEnterpriseSearch,
- },
- catalogue: {
- enterpriseSearch: showEnterpriseSearch,
- enterpriseSearchContent: showEnterpriseSearch,
- enterpriseSearchAnalytics: showEnterpriseSearch,
- enterpriseSearchApplications: showEnterpriseSearch,
- enterpriseSearchAISearch: showEnterpriseSearch,
- enterpriseSearchVectorSearch: showEnterpriseSearch,
- enterpriseSearchElasticsearch: showEnterpriseSearch,
- appSearch: hasAppSearchAccess && config.canDeployEntSearch,
- workplaceSearch: hasWorkplaceSearchAccess && config.canDeployEntSearch,
- searchExperiences: showEnterpriseSearch,
- },
- };
- });
+ capabilities.registerSwitcher(
+ async (request: KibanaRequest) => {
+ const [, { spaces }] = await getStartServices();
+
+ const dependencies = { config, security, spaces, request, log, ml };
+
+ const { hasAppSearchAccess, hasWorkplaceSearchAccess } = await checkAccess(dependencies);
+ const showEnterpriseSearch =
+ hasAppSearchAccess || hasWorkplaceSearchAccess || !config.canDeployEntSearch;
+
+ return {
+ navLinks: {
+ enterpriseSearch: showEnterpriseSearch,
+ enterpriseSearchContent: showEnterpriseSearch,
+ enterpriseSearchAnalytics: showEnterpriseSearch,
+ enterpriseSearchApplications: showEnterpriseSearch,
+ enterpriseSearchAISearch: showEnterpriseSearch,
+ enterpriseSearchVectorSearch: showEnterpriseSearch,
+ enterpriseSearchElasticsearch: showEnterpriseSearch,
+ appSearch: hasAppSearchAccess && config.canDeployEntSearch,
+ workplaceSearch: hasWorkplaceSearchAccess && config.canDeployEntSearch,
+ searchExperiences: showEnterpriseSearch,
+ },
+ catalogue: {
+ enterpriseSearch: showEnterpriseSearch,
+ enterpriseSearchContent: showEnterpriseSearch,
+ enterpriseSearchAnalytics: showEnterpriseSearch,
+ enterpriseSearchApplications: showEnterpriseSearch,
+ enterpriseSearchAISearch: showEnterpriseSearch,
+ enterpriseSearchVectorSearch: showEnterpriseSearch,
+ enterpriseSearchElasticsearch: showEnterpriseSearch,
+ appSearch: hasAppSearchAccess && config.canDeployEntSearch,
+ workplaceSearch: hasWorkplaceSearchAccess && config.canDeployEntSearch,
+ searchExperiences: showEnterpriseSearch,
+ },
+ };
+ },
+ {
+ capabilityPath: ['navLinks.*', 'catalogue.*'],
+ }
+ );
/**
* Register routes
diff --git a/x-pack/plugins/exploratory_view/kibana.jsonc b/x-pack/plugins/exploratory_view/kibana.jsonc
index e541ad7858650..b8041aaec89df 100644
--- a/x-pack/plugins/exploratory_view/kibana.jsonc
+++ b/x-pack/plugins/exploratory_view/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/exploratory-view-plugin",
- "owner": "@elastic/uptime",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "exploratoryView",
"server": false,
diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx
index c72899d8041c7..4e81ca840199f 100644
--- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx
+++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx
@@ -6,7 +6,7 @@
*/
import { render } from '../../rtl_helpers';
-import { fireEvent, screen } from '@testing-library/dom';
+import { fireEvent, screen } from '@testing-library/react';
import React from 'react';
import { sampleAttribute } from '../../configurations/test_data/sample_attribute';
import * as pluginHook from '../../../../../hooks/use_plugin_context';
diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx
index 443a6eb846cd8..7b4e0cb5cc57f 100644
--- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx
+++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { screen } from '@testing-library/dom';
+import { screen } from '@testing-library/react';
import { render, mockAppDataView } from './rtl_helpers';
import { ExploratoryView } from './exploratory_view';
import * as obsvDataViews from '../../../utils/observability_data_views/observability_data_views';
diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx
index a4d8a88507e82..ffccfdf6db3f2 100644
--- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx
+++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/add_to_case_action.test.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import { render, forNearestButton } from '../rtl_helpers';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import { AddToCaseAction } from './add_to_case_action';
import * as useCaseHook from '../hooks/use_add_to_case';
import * as datePicker from '../components/date_range_picker';
diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/chart_creation_info.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/chart_creation_info.test.tsx
index 570362a63c33f..f8da480072ab3 100644
--- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/chart_creation_info.test.tsx
+++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/header/chart_creation_info.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { screen } from '@testing-library/dom';
+import { screen } from '@testing-library/react';
import { render } from '../rtl_helpers';
import { ChartCreationInfo } from './chart_creation_info';
diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.test.tsx
index 9ab9d00d2bc82..3821c703e7cee 100644
--- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.test.tsx
+++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_add_to_case.test.tsx
@@ -9,7 +9,7 @@ import { useAddToCase } from './use_add_to_case';
import React, { useEffect } from 'react';
import { render } from '../rtl_helpers';
import { EuiButton } from '@elastic/eui';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import { act } from '@testing-library/react';
describe('useAddToCase', function () {
diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/add_series_button.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/add_series_button.test.tsx
index 978296a295efc..65f80245c2ceb 100644
--- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/add_series_button.test.tsx
+++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/add_series_button.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { screen, waitFor, fireEvent } from '@testing-library/dom';
+import { screen, waitFor, fireEvent } from '@testing-library/react';
import { render } from '../rtl_helpers';
import { AddSeriesButton } from './add_series_button';
import { DEFAULT_TIME, ReportTypes } from '../configurations/constants';
diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/view_actions.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/view_actions.test.tsx
index df709c94abcde..ae2d2ce65d91c 100644
--- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/view_actions.test.tsx
+++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/views/view_actions.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { screen, waitFor, fireEvent } from '@testing-library/dom';
+import { screen, waitFor, fireEvent } from '@testing-library/react';
import { render } from '../rtl_helpers';
import * as hooks from '../hooks/use_series_storage';
import { ViewActions } from './view_actions';
diff --git a/x-pack/plugins/file_upload/server/capabilities.test.ts b/x-pack/plugins/file_upload/server/capabilities.test.ts
index e5f0a01cd6abe..b32150b80fe6b 100644
--- a/x-pack/plugins/file_upload/server/capabilities.test.ts
+++ b/x-pack/plugins/file_upload/server/capabilities.test.ts
@@ -26,6 +26,16 @@ describe('setupCapabilities', () => {
`);
});
+ it('registers a capabilities switcher with the correct options', async () => {
+ const coreSetup = coreMock.createSetup();
+ setupCapabilities(coreSetup);
+
+ expect(coreSetup.capabilities.registerSwitcher).toHaveBeenCalledTimes(1);
+ expect(coreSetup.capabilities.registerSwitcher).toHaveBeenCalledWith(expect.any(Function), {
+ capabilityPath: 'fileUpload.*',
+ });
+ });
+
it('registers a capabilities switcher that returns unaltered capabilities when security is disabled', async () => {
const coreSetup = coreMock.createSetup();
setupCapabilities(coreSetup);
diff --git a/x-pack/plugins/file_upload/server/capabilities.ts b/x-pack/plugins/file_upload/server/capabilities.ts
index 9217176fb2b25..9e940a0e9a649 100644
--- a/x-pack/plugins/file_upload/server/capabilities.ts
+++ b/x-pack/plugins/file_upload/server/capabilities.ts
@@ -20,28 +20,33 @@ export const setupCapabilities = (
};
});
- core.capabilities.registerSwitcher(async (request, capabilities, useDefaultCapabilities) => {
- if (useDefaultCapabilities) {
- return {};
- }
- const [, { security }] = await core.getStartServices();
+ core.capabilities.registerSwitcher(
+ async (request, capabilities, useDefaultCapabilities) => {
+ if (useDefaultCapabilities) {
+ return {};
+ }
+ const [, { security }] = await core.getStartServices();
- // Check the bare minimum set of privileges required to get some utility out of this feature
- const { hasImportPermission } = await checkFileUploadPrivileges({
- authorization: security?.authz,
- request,
- checkCreateDataView: true,
- checkHasManagePipeline: false,
- });
+ // Check the bare minimum set of privileges required to get some utility out of this feature
+ const { hasImportPermission } = await checkFileUploadPrivileges({
+ authorization: security?.authz,
+ request,
+ checkCreateDataView: true,
+ checkHasManagePipeline: false,
+ });
- if (!hasImportPermission) {
- return {
- fileUpload: {
- show: false,
- },
- };
- }
+ if (!hasImportPermission) {
+ return {
+ fileUpload: {
+ show: false,
+ },
+ };
+ }
- return {};
- });
+ return {};
+ },
+ {
+ capabilityPath: 'fileUpload.*',
+ }
+ );
};
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx
index 2f05354b09a04..2d39700da5caa 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import { createFleetTestRendererMock } from '../../../../../../mock';
import type { Agent, AgentPolicy } from '../../../../types';
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx
index 9937126213c91..dffa4bc665bdb 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { fireEvent, waitFor } from '@testing-library/dom';
+import { fireEvent, waitFor } from '@testing-library/react';
import React from 'react';
import { createFleetTestRendererMock } from '../../../../../../mock';
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx
index a2fed8d3ed613..4e8d25f313ea5 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import { createFleetTestRendererMock } from '../../../../../../mock';
import type { Agent, AgentPolicy } from '../../../../types';
diff --git a/x-pack/plugins/global_search/server/services/context.test.ts b/x-pack/plugins/global_search/server/services/context.test.ts
index f90c0bc0f6c84..eebf583b6fc3a 100644
--- a/x-pack/plugins/global_search/server/services/context.test.ts
+++ b/x-pack/plugins/global_search/server/services/context.test.ts
@@ -26,7 +26,9 @@ describe('getContextFactory', () => {
expect(coreStart.uiSettings.asScopedToClient).toHaveBeenCalledWith(soClient);
expect(coreStart.capabilities.resolveCapabilities).toHaveBeenCalledTimes(1);
- expect(coreStart.capabilities.resolveCapabilities).toHaveBeenCalledWith(request);
+ expect(coreStart.capabilities.resolveCapabilities).toHaveBeenCalledWith(request, {
+ capabilityPath: '*',
+ });
expect(context).toEqual({
core: {
diff --git a/x-pack/plugins/global_search/server/services/context.ts b/x-pack/plugins/global_search/server/services/context.ts
index 02d86c909ab72..06be3f4acd35c 100644
--- a/x-pack/plugins/global_search/server/services/context.ts
+++ b/x-pack/plugins/global_search/server/services/context.ts
@@ -27,7 +27,9 @@ export const getContextFactory =
uiSettings: {
client: coreStart.uiSettings.asScopedToClient(soClient),
},
- capabilities: from(coreStart.capabilities.resolveCapabilities(request)),
+ capabilities: from(
+ coreStart.capabilities.resolveCapabilities(request, { capabilityPath: '*' })
+ ),
},
};
};
diff --git a/x-pack/plugins/infra/kibana.jsonc b/x-pack/plugins/infra/kibana.jsonc
index debd656bddeed..b97a273b91f71 100644
--- a/x-pack/plugins/infra/kibana.jsonc
+++ b/x-pack/plugins/infra/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/infra-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": ["@elastic/infra-monitoring-ui", "@elastic/obs-ux-logs-team", "@elastic/obs-ux-infra_services-team"],
"description": "This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions",
"plugin": {
"id": "infra",
diff --git a/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx b/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx
index 41fdc1b6f7d30..d3f564818f03e 100644
--- a/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx
+++ b/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx
@@ -41,6 +41,7 @@ export const AlertFlyout = ({ options, nodeType, filter, visible, setVisible }:
filter,
customMetrics,
},
+ useRuleProducer: true,
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[triggersActionsUI, visible]
diff --git a/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/anomalies.ts b/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/anomalies.ts
index b49e14850f7b6..543b46ceb17b9 100644
--- a/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/anomalies.ts
+++ b/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/anomalies.ts
@@ -16,7 +16,7 @@ const anomalies: GetMetricsHostsAnomaliesSuccessResponsePayload = {
actual: 758.8220213274412,
anomalyScore: 0.024881740359975164,
duration: 900,
- startTime: 1486845000000,
+ startTime: 1681038638000,
type: 'metrics_hosts',
partitionFieldName: 'airline',
partitionFieldValue: 'NKS',
@@ -42,7 +42,7 @@ const anomalies: GetMetricsHostsAnomaliesSuccessResponsePayload = {
actual: 758.8220213274412,
anomalyScore: 100.024881740359975164,
duration: 900,
- startTime: 1486845000000,
+ startTime: 1681038638000,
type: 'metrics_hosts',
partitionFieldName: 'airline',
partitionFieldValue: 'NKS',
diff --git a/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts b/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts
index 601c064471078..9d6b4efb96ec2 100644
--- a/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts
+++ b/x-pack/plugins/infra/public/components/asset_details/__stories__/context/fixtures/asset_details_props.ts
@@ -16,12 +16,6 @@ const tabs: Tab[] = [
defaultMessage: 'Overview',
}),
},
- {
- id: ContentTabIds.LOGS,
- name: i18n.translate('xpack.infra.nodeDetails.tabs.logs', {
- defaultMessage: 'Logs',
- }),
- },
{
id: ContentTabIds.METADATA,
name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.metadata', {
@@ -34,6 +28,12 @@ const tabs: Tab[] = [
defaultMessage: 'Processes',
}),
},
+ {
+ id: ContentTabIds.LOGS,
+ name: i18n.translate('xpack.infra.nodeDetails.tabs.logs', {
+ defaultMessage: 'Logs',
+ }),
+ },
{
id: ContentTabIds.ANOMALIES,
name: i18n.translate('xpack.infra.nodeDetails.tabs.anomalies', {
diff --git a/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx b/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx
index 11401bd256feb..e779808347ec4 100644
--- a/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx
+++ b/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx
@@ -11,24 +11,33 @@ import {
KibanaContextProvider,
type KibanaReactContextValue,
} from '@kbn/kibana-react-plugin/public';
-import { of } from 'rxjs';
+import { Observable, of } from 'rxjs';
import { action } from '@storybook/addon-actions';
import type { DecoratorFn } from '@storybook/react';
import { useParameter } from '@storybook/addons';
import type { DeepPartial } from 'utility-types';
import type { LocatorPublic } from '@kbn/share-plugin/public';
-import type { IKibanaSearchRequest, ISearchOptions } from '@kbn/data-plugin/public';
+import type {
+ IKibanaSearchRequest,
+ ISearchOptions,
+ SearchSessionState,
+} from '@kbn/data-plugin/public';
import { AlertSummaryWidget } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alert_summary_widget/alert_summary_widget';
import type { Theme } from '@elastic/charts/dist/utils/themes/theme';
import type { AlertSummaryWidgetProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alert_summary_widget';
import { defaultLogViewAttributes } from '@kbn/logs-shared-plugin/common';
import { DataView, DataViewField } from '@kbn/data-views-plugin/common';
+import { MemoryRouter } from 'react-router-dom';
+import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public';
+import { ObservabilityAIAssistantService } from '@kbn/observability-ai-assistant-plugin/public/types';
+import { PluginConfigProvider } from '../../../containers/plugin_config_context';
import type { PluginKibanaContextValue } from '../../../hooks/use_kibana';
import { SourceProvider } from '../../../containers/metrics_source';
import { getHttp } from './context/http';
import { assetDetailsProps, getLogEntries } from './context/fixtures';
import { ContextProviders } from '../context_providers';
import { DataViewsProvider } from '../hooks/use_data_views';
+import type { InfraConfig } from '../../../../server';
const settings: Record = {
'dateFormat:scaled': [['', 'HH:mm:ss.SSS']],
@@ -58,6 +67,10 @@ export const DecorateWithKibanaContext: DecoratorFn = (story) => {
search: (request: IKibanaSearchRequest, options?: ISearchOptions) => {
return getLogEntries(request, options) as any;
},
+ session: {
+ start: () => 'started',
+ state$: { closed: false } as unknown as Observable,
+ },
},
query: {
filterManager: {
@@ -144,14 +157,64 @@ export const DecorateWithKibanaContext: DecoratorFn = (story) => {
},
telemetry: {
reportAssetDetailsFlyoutViewed: () => {},
+ reportAssetDetailsPageViewed: () => {},
+ },
+ };
+
+ const config: InfraConfig = {
+ alerting: {
+ inventory_threshold: {
+ group_by_page_size: 11,
+ },
+ metric_threshold: {
+ group_by_page_size: 11,
+ },
+ },
+ enabled: true,
+ inventory: {
+ compositeSize: 11,
+ },
+ sources: {
+ default: {
+ fields: {
+ message: ['default'],
+ },
+ },
+ },
+ featureFlags: {
+ customThresholdAlertsEnabled: true,
+ logsUIEnabled: false,
+ metricsExplorerEnabled: false,
+ osqueryEnabled: true,
+ inventoryThresholdAlertRuleEnabled: true,
+ metricThresholdAlertRuleEnabled: true,
+ logThresholdAlertRuleEnabled: true,
+ alertsAndRulesDropdownEnabled: true,
},
};
return (
-
- {story()}
-
+
+
+
+ true,
+ callApi: () => {},
+ getCurrentUser: () => {},
+ getLicense: () => {},
+ getLicenseManagementLocator: () => {},
+ start: {},
+ } as unknown as ObservabilityAIAssistantService
+ }
+ >
+ {story()}
+
+
+
+
);
};
diff --git a/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx
index 0816e25dc800b..c85677dbace94 100644
--- a/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx
+++ b/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx
@@ -6,19 +6,32 @@
*/
import React, { useState } from 'react';
-import { EuiButton } from '@elastic/eui';
+import { EuiButton, EuiCallOut, EuiSelect, EuiSpacer } from '@elastic/eui';
import type { Meta, Story } from '@storybook/react/types-6-0';
+import { MemoryRouter } from 'react-router-dom';
+import { useArgs } from '@storybook/addons';
import { AssetDetails } from './asset_details';
import { decorateWithGlobalStorybookThemeProviders } from '../../test_utils/use_global_storybook_theme';
-import { type AssetDetailsProps } from './types';
+import { type TabIds, type AssetDetailsProps } from './types';
import { DecorateWithKibanaContext } from './__stories__/decorator';
import { assetDetailsProps } from './__stories__/context/fixtures';
-const stories: Meta = {
+interface AssetDetailsStoryArgs extends AssetDetailsProps {
+ tabId: TabIds;
+}
+
+const stories: Meta = {
title: 'infra/Asset Details View',
decorators: [decorateWithGlobalStorybookThemeProviders, DecorateWithKibanaContext],
component: AssetDetails,
argTypes: {
+ tabId: {
+ options: assetDetailsProps.tabs.filter(({ id }) => id !== 'linkToApm').map(({ id }) => id),
+ defaultValue: 'overview',
+ control: {
+ type: 'radio',
+ },
+ },
links: {
options: assetDetailsProps.links,
control: {
@@ -26,20 +39,42 @@ const stories: Meta = {
},
},
},
- args: {
- ...assetDetailsProps,
- },
+ args: { ...assetDetailsProps },
};
-const PageTemplate: Story = (args) => {
- return ;
+const PageTabTemplate: Story = (args) => {
+ return (
+
+
+
+ );
};
-const FlyoutTemplate: Story = (args) => {
+const FlyoutTemplate: Story = (args) => {
const [isOpen, setIsOpen] = useState(false);
const closeFlyout = () => setIsOpen(false);
+ const options = assetDetailsProps.tabs.filter(({ id }) => id !== 'linkToApm').map(({ id }) => id);
+ const [{ tabId }, updateArgs] = useArgs();
+
return (
+
+
+
{
+ updateArgs({ tabId: e.target.value as TabIds });
+ }}
+ options={options.map((id) => ({
+ text: id,
+ value: id,
+ }))}
+ />
+
setIsOpen(true)}
@@ -47,13 +82,33 @@ const FlyoutTemplate: Story = (args) => {
Open flyout
- {isOpen &&
}
+ {isOpen && (
+
+
+
+ )}
);
};
-export const Page = PageTemplate.bind({});
+export const OverviewTab = PageTabTemplate.bind({});
+OverviewTab.args = { tabId: 'overview' };
+
+export const MetadataTab = PageTabTemplate.bind({});
+MetadataTab.args = { tabId: 'metadata' };
+
+export const ProcessesTab = PageTabTemplate.bind({});
+ProcessesTab.args = { tabId: 'processes' };
+
+export const LogsTab = PageTabTemplate.bind({});
+LogsTab.args = { tabId: 'logs' };
+
+export const AnomaliesTab = PageTabTemplate.bind({});
+AnomaliesTab.args = { tabId: 'anomalies' };
export const Flyout = FlyoutTemplate.bind({});
diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/anomalies/anomalies.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/anomalies/anomalies.stories.tsx
deleted file mode 100644
index 25db2ae7445d6..0000000000000
--- a/x-pack/plugins/infra/public/components/asset_details/tabs/anomalies/anomalies.stories.tsx
+++ /dev/null
@@ -1,48 +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 React from 'react';
-import type { Meta, Story } from '@storybook/react/types-6-0';
-
-import { Anomalies } from './anomalies';
-import { decorateWithGlobalStorybookThemeProviders } from '../../../../test_utils/use_global_storybook_theme';
-import {
- DecorateWithKibanaContext,
- DecorateWithAssetDetailsStateContext,
-} from '../../__stories__/decorator';
-
-const stories: Meta = {
- title: 'infra/Asset Details View/Components/Anomalies',
- decorators: [
- decorateWithGlobalStorybookThemeProviders,
- DecorateWithKibanaContext,
- DecorateWithAssetDetailsStateContext,
- ],
- component: Anomalies,
-};
-
-const Template: Story = () => {
- return ;
-};
-
-export const Default = Template.bind({});
-
-export const NoData = Template.bind({});
-NoData.parameters = {
- apiResponse: {
- mock: 'noData',
- },
-};
-
-export const LoadingState = Template.bind({});
-LoadingState.parameters = {
- apiResponse: {
- mock: 'loading',
- },
-};
-
-export default stories;
diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.stories.tsx
index 4a48b63f73d41..323d3302589d9 100644
--- a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.stories.tsx
+++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.stories.tsx
@@ -18,8 +18,8 @@ const stories: Meta = {
title: 'infra/Asset Details View/Components/Metadata',
decorators: [
decorateWithGlobalStorybookThemeProviders,
- DecorateWithKibanaContext,
DecorateWithAssetDetailsStateContext,
+ DecorateWithKibanaContext,
],
component: Metadata,
};
@@ -30,11 +30,6 @@ const Template: Story = () => {
export const Default = Template.bind({});
-export const WithActions = Template.bind({});
-WithActions.args = {
- showActionsColumn: true,
-};
-
export const NoData = Template.bind({});
NoData.parameters = {
apiResponse: {
diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.stories.tsx
index feb055a6a14e0..94e153d1f0589 100644
--- a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.stories.tsx
+++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.stories.tsx
@@ -18,8 +18,8 @@ const stories: Meta = {
title: 'infra/Asset Details View/Components/Processes',
decorators: [
decorateWithGlobalStorybookThemeProviders,
- DecorateWithKibanaContext,
DecorateWithAssetDetailsStateContext,
+ DecorateWithKibanaContext,
],
component: Processes,
};
diff --git a/x-pack/plugins/infra/public/hooks/use_http_request.tsx b/x-pack/plugins/infra/public/hooks/use_http_request.tsx
index 7e2b6f03ab916..8196677004714 100644
--- a/x-pack/plugins/infra/public/hooks/use_http_request.tsx
+++ b/x-pack/plugins/infra/public/hooks/use_http_request.tsx
@@ -7,8 +7,7 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { i18n } from '@kbn/i18n';
-import { HttpHandler } from '@kbn/core/public';
-import { ToastInput } from '@kbn/core/public';
+import { HttpHandler, ToastInput } from '@kbn/core/public';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { AbortError } from '@kbn/kibana-utils-plugin/common';
import { useTrackedPromise, CanceledPromiseError } from '../utils/use_tracked_promise';
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/snapshot_container.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/snapshot_container.tsx
index b22bcb59a3c12..40b41ac3a1d5e 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/snapshot_container.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/snapshot_container.tsx
@@ -25,7 +25,7 @@ interface Props {
}
export const SnapshotContainer = ({ render }: Props) => {
const { sourceId } = useSourceContext();
- const { metric, groupBy, nodeType, accountId, region } = useWaffleOptionsContext();
+ const { metric, groupBy, nodeType, accountId, region, view } = useWaffleOptionsContext();
const { currentTime } = useWaffleTimeContext();
const { filterQueryAsJson } = useWaffleFiltersContext();
const {
@@ -33,17 +33,23 @@ export const SnapshotContainer = ({ render }: Props) => {
nodes,
reload,
interval = '60s',
- } = useSnapshot({
- filterQuery: filterQueryAsJson,
- metrics: [metric],
- groupBy,
- nodeType,
- sourceId,
- currentTime,
- accountId,
- region,
- sendRequestImmediately: false,
- });
+ } = useSnapshot(
+ {
+ filterQuery: filterQueryAsJson,
+ metrics: [metric],
+ groupBy,
+ nodeType,
+ sourceId,
+ currentTime,
+ accountId,
+ region,
+ sendRequestImmediately: false,
+ includeTimeseries: view === 'table',
+ },
+ {
+ abortable: true,
+ }
+ );
return render({ loading, nodes, reload, interval });
};
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap
index 02c8f6aa6ed3b..f3368be815f1b 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap
@@ -6,7 +6,7 @@ exports[`ConditionalToolTip renders correctly 1`] = `
style="min-width: 200px;"
>
host-01
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx
index 66b8ff975ba30..f023cc1c5760c 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx
@@ -7,7 +7,6 @@
import React from 'react';
import { mount } from 'enzyme';
-import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { ConditionalToolTip } from './conditional_tooltip';
import { SnapshotNodeResponse } from '../../../../../../common/http_api';
import { InfraWaffleMapNode } from '../../../../../lib/lib';
@@ -98,23 +97,25 @@ describe('ConditionalToolTip', () => {
},
];
const wrapper = mount(
-
-
-
+
);
const tooltip = wrapper.find('[data-test-subj~="conditionalTooltipContent-host-01"]');
expect(tooltip.render()).toMatchSnapshot();
- expect(mockedUseSnapshot).toBeCalledWith({
- filterQuery: expectedQuery,
- metrics: expectedMetrics,
- groupBy: [],
- nodeType: 'host',
- sourceId: 'default',
- currentTime,
- accountId: '',
- region: '',
- } as UseSnapshotRequest);
+ expect(mockedUseSnapshot).toBeCalledWith(
+ {
+ filterQuery: expectedQuery,
+ metrics: expectedMetrics,
+ groupBy: [],
+ includeTimeseries: false,
+ nodeType: 'host',
+ sourceId: 'default',
+ currentTime,
+ accountId: '',
+ region: '',
+ } as UseSnapshotRequest,
+ { abortable: true }
+ );
});
});
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx
index 4d82f7b7a39c8..7bbb696103cd6 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx
@@ -5,10 +5,9 @@
* 2.0.
*/
-import React from 'react';
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import React, { useRef } from 'react';
+import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, useEuiTheme } from '@elastic/eui';
import { first } from 'lodash';
-import { withTheme, EuiTheme } from '@kbn/kibana-react-plugin/common';
import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common';
import {
InventoryItemType,
@@ -29,10 +28,13 @@ export interface Props {
currentTime: number;
node: InfraWaffleMapNode;
nodeType: InventoryItemType;
- theme: EuiTheme | undefined;
}
-export const ConditionalToolTip = withTheme(({ theme, node, nodeType, currentTime }: Props) => {
+
+export const ConditionalToolTip = ({ node, nodeType, currentTime }: Props) => {
+ const { euiTheme } = useEuiTheme();
const { sourceId } = useSourceContext();
+ // prevents auto-refresh from cancelling ongoing requests to fetch the data for the tooltip
+ const requestCurrentTime = useRef(currentTime);
const model = findInventoryModel(nodeType);
const { customMetrics } = useWaffleOptionsContext();
const requestMetrics = model.tooltipMetrics
@@ -50,16 +52,22 @@ export const ConditionalToolTip = withTheme(({ theme, node, nodeType, currentTim
},
},
});
- const { nodes } = useSnapshot({
- filterQuery: query,
- metrics: requestMetrics,
- groupBy: [],
- nodeType,
- sourceId,
- currentTime,
- accountId: '',
- region: '',
- });
+ const { nodes, loading } = useSnapshot(
+ {
+ filterQuery: query,
+ metrics: requestMetrics,
+ groupBy: [],
+ nodeType,
+ sourceId,
+ currentTime: requestCurrentTime.current,
+ accountId: '',
+ region: '',
+ includeTimeseries: false,
+ },
+ {
+ abortable: true,
+ }
+ );
const dataNode = first(nodes);
const metrics = (dataNode && dataNode.metrics) || [];
@@ -67,38 +75,47 @@ export const ConditionalToolTip = withTheme(({ theme, node, nodeType, currentTim
{node.name}
- {metrics.map((metric) => {
- const metricName = SnapshotMetricTypeRT.is(metric.name) ? metric.name : 'custom';
- const name = SNAPSHOT_METRIC_TRANSLATIONS[metricName] || metricName;
- // if custom metric, find field and label from waffleOptionsContext result
- // because useSnapshot does not return it
- const customMetric =
- name === 'custom' ? customMetrics.find((item) => item.id === metric.name) : null;
- const formatter = customMetric
- ? createFormatterForMetric(customMetric)
- : createInventoryMetricFormatter({ type: metricName });
- return (
-
-
- {customMetric ? getCustomMetricLabel(customMetric) : name}
-
-
- {(metric.value && formatter(metric.value)) || '-'}
-
-
- );
- })}
+ {loading ? (
+
+
+
+
+
+ ) : (
+ metrics.map((metric) => {
+ const metricName = SnapshotMetricTypeRT.is(metric.name) ? metric.name : 'custom';
+ const name = SNAPSHOT_METRIC_TRANSLATIONS[metricName] || metricName;
+ // if custom metric, find field and label from waffleOptionsContext result
+ // because useSnapshot does not return it
+ const customMetric =
+ name === 'custom' ? customMetrics.find((item) => item.id === metric.name) : null;
+ const formatter = customMetric
+ ? createFormatterForMetric(customMetric)
+ : createInventoryMetricFormatter({ type: metricName });
+ return (
+
+
+ {customMetric ? getCustomMetricLabel(customMetric) : name}
+
+
+ {(metric.value && formatter(metric.value)) || '-'}
+
+
+ );
+ })
+ )}
);
-});
+};
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_timeline.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_timeline.ts
index d603972743e0a..f949ee5f3a87b 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_timeline.ts
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_timeline.ts
@@ -5,21 +5,12 @@
* 2.0.
*/
-import { fold } from 'fp-ts/lib/Either';
-import { identity } from 'fp-ts/lib/function';
-import { pipe } from 'fp-ts/lib/pipeable';
import { first } from 'lodash';
-import { useEffect, useMemo, useCallback } from 'react';
+import { useEffect, useMemo } from 'react';
import type { InventoryItemType, SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common';
import { getIntervalInSeconds } from '../../../../../common/utils/get_interval_in_seconds';
-import { throwErrors, createPlainError } from '../../../../../common/runtime_types';
-import { useHTTPRequest } from '../../../../hooks/use_http_request';
-import {
- SnapshotNodeResponseRT,
- SnapshotNodeResponse,
- SnapshotRequest,
- InfraTimerangeInput,
-} from '../../../../../common/http_api/snapshot_api';
+import { InfraTimerangeInput } from '../../../../../common/http_api/snapshot_api';
+import { useSnapshot } from './use_snaphot';
const ONE_MINUTE = 60;
const ONE_HOUR = ONE_MINUTE * 60;
@@ -64,13 +55,6 @@ export function useTimeline(
interval: string | undefined,
shouldReload: boolean
) {
- const decodeResponse = (response: any) => {
- return pipe(
- SnapshotNodeResponseRT.decode(response),
- fold(throwErrors(createPlainError), identity)
- );
- };
-
const displayInterval = useMemo(() => getDisplayInterval(interval), [interval]);
const timeLengthResult = useMemo(
@@ -88,12 +72,11 @@ export function useTimeline(
forceInterval: true,
};
- const { error, loading, response, makeRequest } = useHTTPRequest(
- '/api/metrics/snapshot',
- 'POST',
- JSON.stringify({
+ const { nodes, error, loading, reload } = useSnapshot(
+ {
metrics,
groupBy: null,
+ currentTime,
nodeType,
timerange,
filterQuery,
@@ -101,33 +84,27 @@ export function useTimeline(
accountId,
region,
includeTimeseries: true,
- } as SnapshotRequest),
- decodeResponse
+ sendRequestImmediately: false,
+ },
+ {
+ abortable: true,
+ }
);
- const loadData = useCallback(() => {
- if (shouldReload) return makeRequest();
- return Promise.resolve();
- }, [makeRequest, shouldReload]);
-
useEffect(() => {
(async () => {
- if (timeLength) {
- await loadData();
- }
+ if (shouldReload) return reload();
})();
- }, [loadData, timeLength]);
+ }, [reload, shouldReload]);
- const timeseries = response
- ? first(response.nodes.map((node) => first(node.metrics)?.timeseries))
- : null;
+ const timeseries = nodes ? first(nodes.map((node) => first(node.metrics)?.timeseries)) : null;
return {
- error: (error && error.message) || null,
+ error: error || null,
loading: !interval ? true : loading,
timeseries,
startTime,
endTime,
- reload: makeRequest,
+ reload,
};
}
diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts
index 9780a7811b824..9a593af54a010 100644
--- a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts
+++ b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts
@@ -26,6 +26,7 @@ import {
InfraServerPluginStartDeps,
InfraVersionedRouteConfig,
} from './adapter_types';
+import { subscribeToAborted$ } from '../../cancel_request_on_abort';
interface FrozenIndexParams {
ignore_throttled?: boolean;
@@ -115,42 +116,50 @@ export class KibanaFramework {
callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
endpoint: 'search',
- options?: CallWithRequestParams
+ options?: CallWithRequestParams,
+ request?: KibanaRequest
): Promise>;
callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
endpoint: 'msearch',
- options?: CallWithRequestParams
+ options?: CallWithRequestParams,
+ request?: KibanaRequest
): Promise>;
callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
endpoint: 'indices.existsAlias',
- options?: CallWithRequestParams
+ options?: CallWithRequestParams,
+ request?: KibanaRequest
): Promise;
callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
method: 'indices.getAlias',
- options?: object
+ options?: object,
+ request?: KibanaRequest
): Promise;
callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
method: 'indices.get' | 'ml.getBuckets',
- options?: object
+ options?: object,
+ request?: KibanaRequest
): Promise;
callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
method: 'transport.request',
- options?: CallWithRequestParams
+ options?: CallWithRequestParams,
+ request?: KibanaRequest
): Promise;
callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
endpoint: string,
- options?: CallWithRequestParams
+ options?: CallWithRequestParams,
+ request?: KibanaRequest
): Promise;
public async callWithRequest(
requestContext: InfraPluginRequestHandlerContext,
endpoint: string,
- params: CallWithRequestParams
+ params: CallWithRequestParams,
+ request?: KibanaRequest
) {
const { elasticsearch, uiSettings } = await requestContext.core;
@@ -164,6 +173,16 @@ export class KibanaFramework {
}
}
+ function callWrapper({
+ makeRequestWithSignal,
+ }: {
+ makeRequestWithSignal: (signal: AbortSignal) => Promise;
+ }) {
+ const controller = new AbortController();
+ const promise = makeRequestWithSignal(controller.signal);
+ return request ? subscribeToAborted$(promise, request, controller) : promise;
+ }
+
// Only set the "ignore_throttled" value (to false) if the Kibana setting
// for "search:includeFrozen" is true (i.e. don't ignore throttled indices, a triple negative!)
// More information:
@@ -179,41 +198,90 @@ export class KibanaFramework {
let apiResult;
switch (endpoint) {
case 'search':
- apiResult = elasticsearch.client.asCurrentUser.search({
- ...params,
- ...frozenIndicesParams,
+ apiResult = callWrapper({
+ makeRequestWithSignal: (signal) =>
+ elasticsearch.client.asCurrentUser.search(
+ {
+ ...params,
+ ...frozenIndicesParams,
+ } as estypes.MsearchRequest,
+ { signal }
+ ),
});
+
break;
case 'msearch':
- apiResult = elasticsearch.client.asCurrentUser.msearch({
- ...params,
- ...frozenIndicesParams,
- } as estypes.MsearchRequest);
+ apiResult = callWrapper({
+ makeRequestWithSignal: (signal) =>
+ elasticsearch.client.asCurrentUser.msearch(
+ {
+ ...params,
+ ...frozenIndicesParams,
+ } as estypes.MsearchRequest,
+ { signal }
+ ),
+ });
+
break;
case 'indices.existsAlias':
- apiResult = elasticsearch.client.asCurrentUser.indices.existsAlias({
- ...params,
- } as estypes.IndicesExistsAliasRequest);
+ apiResult = callWrapper({
+ makeRequestWithSignal: (signal) =>
+ elasticsearch.client.asCurrentUser.indices.existsAlias(
+ {
+ ...params,
+ } as estypes.IndicesExistsAliasRequest,
+ { signal }
+ ),
+ });
+
break;
case 'indices.getAlias':
- apiResult = elasticsearch.client.asCurrentUser.indices.getAlias({
- ...params,
+ apiResult = callWrapper({
+ makeRequestWithSignal: (signal) =>
+ elasticsearch.client.asCurrentUser.indices.getAlias(
+ {
+ ...params,
+ },
+ { signal }
+ ),
});
+
break;
case 'indices.get':
- apiResult = elasticsearch.client.asCurrentUser.indices.get({
- ...params,
- } as estypes.IndicesGetRequest);
+ apiResult = callWrapper({
+ makeRequestWithSignal: (signal) =>
+ elasticsearch.client.asCurrentUser.indices.get(
+ {
+ ...params,
+ } as estypes.IndicesGetRequest,
+ { signal }
+ ),
+ });
+
break;
case 'transport.request':
- apiResult = elasticsearch.client.asCurrentUser.transport.request({
- ...params,
- } as TransportRequestParams);
+ apiResult = callWrapper({
+ makeRequestWithSignal: (signal) =>
+ elasticsearch.client.asCurrentUser.transport.request(
+ {
+ ...params,
+ } as TransportRequestParams,
+ { signal }
+ ),
+ });
+
break;
case 'ml.getBuckets':
- apiResult = elasticsearch.client.asCurrentUser.ml.getBuckets({
- ...params,
- } as estypes.MlGetBucketsRequest);
+ apiResult = callWrapper({
+ makeRequestWithSignal: (signal) =>
+ elasticsearch.client.asCurrentUser.ml.getBuckets(
+ {
+ ...params,
+ } as estypes.MlGetBucketsRequest,
+ { signal }
+ ),
+ });
+
break;
}
return apiResult ? await apiResult : undefined;
diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts
index 29c4bfe0a159a..bd6350ba59dd0 100644
--- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts
+++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.test.ts
@@ -90,7 +90,9 @@ const mockOptions = {
};
const setEvaluationResults = (response: Record) => {
- jest.requireMock('./evaluate_condition').evaluateCondition.mockImplementation(() => response);
+ return jest
+ .requireMock('./evaluate_condition')
+ .evaluateCondition.mockImplementation(() => response);
};
const createMockStaticConfiguration = (sources: any) => ({
alerting: {
@@ -192,7 +194,7 @@ const baseCriterion = {
describe('The inventory threshold alert type', () => {
describe('querying with Hosts and rule tags', () => {
afterAll(() => clearInstances());
- const execute = (comparator: Comparator, threshold: number[], state?: any) =>
+ const execute = (comparator: Comparator, threshold: number[], options?: any) =>
executor({
...mockOptions,
services,
@@ -206,11 +208,12 @@ describe('The inventory threshold alert type', () => {
},
],
},
- state: state ?? {},
+ state: {},
rule: {
...mockOptions.rule,
tags: ['ruleTag1', 'ruleTag2'],
},
+ ...options,
});
const instanceIdA = 'host-01';
@@ -305,5 +308,39 @@ describe('The inventory threshold alert type', () => {
expect(mostRecentAction(instanceIdA).action.tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
expect(mostRecentAction(instanceIdB).action.tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
});
+
+ test('should call evaluation query with delay', async () => {
+ const mockedStartDate = new Date('2023-11-06T10:04:26.465Z');
+ const mockedEndDate = new Date('2023-11-06T10:05:26.465Z');
+ const options = {
+ getTimeRange: () => {
+ return { dateStart: mockedStartDate, dateEnd: mockedEndDate };
+ },
+ };
+ const evaluateConditionFn = setEvaluationResults({
+ 'host-01': {
+ ...baseCriterion,
+ metric: 'count',
+ timeSize: 1,
+ timeUnit: 'm',
+ threshold: [0.75],
+ comparator: Comparator.GT,
+ shouldFire: true,
+ shouldWarn: false,
+ currentValue: 1.0,
+ isNoData: false,
+ isError: false,
+ context: {
+ cloud: undefined,
+ },
+ },
+ });
+ await execute(Comparator.GT, [0.75], options);
+ expect(evaluateConditionFn).toHaveBeenCalledWith(
+ expect.objectContaining({
+ executionTimestamp: mockedEndDate,
+ })
+ );
+ });
});
});
diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts
index 7e3315510feec..ce2f66645bf1d 100644
--- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts
+++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts
@@ -83,6 +83,7 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
spaceId,
startedAt,
rule: { id: ruleId, tags: ruleTags },
+ getTimeRange,
}) => {
const startTime = Date.now();
@@ -175,13 +176,14 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
);
const compositeSize = libs.configuration.alerting.inventory_threshold.group_by_page_size;
+ const { dateEnd } = getTimeRange();
const results = await Promise.all(
criteria.map((condition) =>
evaluateCondition({
compositeSize,
condition,
esClient,
- executionTimestamp: startedAt,
+ executionTimestamp: new Date(dateEnd),
filterQuery,
logger,
logQueryFields,
diff --git a/x-pack/plugins/infra/server/lib/cancel_request_on_abort.ts b/x-pack/plugins/infra/server/lib/cancel_request_on_abort.ts
new file mode 100644
index 0000000000000..631af6991bd09
--- /dev/null
+++ b/x-pack/plugins/infra/server/lib/cancel_request_on_abort.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 { KibanaRequest } from '@kbn/core/server';
+
+export function subscribeToAborted$>(
+ promise: T,
+ request: KibanaRequest,
+ controller: AbortController
+): T {
+ const subscription = request.events.aborted$.subscribe(() => {
+ controller.abort();
+ });
+
+ return promise.finally(() => {
+ subscription.unsubscribe();
+ }) as T;
+}
diff --git a/x-pack/plugins/infra/server/lib/create_search_client.ts b/x-pack/plugins/infra/server/lib/create_search_client.ts
index 6688ae1af1afc..00f89fb3c8e8b 100644
--- a/x-pack/plugins/infra/server/lib/create_search_client.ts
+++ b/x-pack/plugins/infra/server/lib/create_search_client.ts
@@ -5,13 +5,18 @@
* 2.0.
*/
+import type { KibanaRequest } from '@kbn/core/server';
import type { InfraPluginRequestHandlerContext } from '../types';
import { CallWithRequestParams, InfraDatabaseSearchResponse } from './adapters/framework';
import { KibanaFramework } from './adapters/framework/kibana_framework_adapter';
export const createSearchClient =
- (requestContext: InfraPluginRequestHandlerContext, framework: KibanaFramework) =>
+ (
+ requestContext: InfraPluginRequestHandlerContext,
+ framework: KibanaFramework,
+ request?: KibanaRequest
+ ) =>
(
opts: CallWithRequestParams
): Promise> =>
- framework.callWithRequest(requestContext, 'search', opts);
+ framework.callWithRequest(requestContext, 'search', opts, request);
diff --git a/x-pack/plugins/infra/server/routes/snapshot/index.ts b/x-pack/plugins/infra/server/routes/snapshot/index.ts
index 085be4584e2a7..ae1f02a04ca93 100644
--- a/x-pack/plugins/infra/server/routes/snapshot/index.ts
+++ b/x-pack/plugins/infra/server/routes/snapshot/index.ts
@@ -53,7 +53,7 @@ export const initSnapshotRoute = (libs: InfraBackendLibs) => {
);
UsageCollector.countNode(snapshotRequest.nodeType);
- const client = createSearchClient(requestContext, framework);
+ const client = createSearchClient(requestContext, framework, request);
try {
const snapshotResponse = await getNodes(
diff --git a/x-pack/plugins/kubernetes_security/public/components/count_widget/index.test.tsx b/x-pack/plugins/kubernetes_security/public/components/count_widget/index.test.tsx
index a0fbe2c90c690..d3230a33f203e 100644
--- a/x-pack/plugins/kubernetes_security/public/components/count_widget/index.test.tsx
+++ b/x-pack/plugins/kubernetes_security/public/components/count_widget/index.test.tsx
@@ -10,7 +10,7 @@ import { AppContextTestRender, createAppRootMockRenderer } from '../../test';
import { GlobalFilter } from '../../types';
import { CountWidget, LOADING_TEST_ID, TOOLTIP_TEST_ID, VALUE_TEST_ID } from '.';
import { useFetchCountWidgetData } from './hooks';
-import { fireEvent, waitFor } from '@testing-library/dom';
+import { fireEvent, waitFor } from '@testing-library/react';
const TITLE = 'Count Widget Title';
const GLOBAL_FILTER: GlobalFilter = {
diff --git a/x-pack/plugins/lens/public/app_plugin/app.tsx b/x-pack/plugins/lens/public/app_plugin/app.tsx
index d68476598ad99..39a614b568799 100644
--- a/x-pack/plugins/lens/public/app_plugin/app.tsx
+++ b/x-pack/plugins/lens/public/app_plugin/app.tsx
@@ -17,7 +17,7 @@ import type { LensAppLocatorParams } from '../../common/locator/locator';
import { LensAppProps, LensAppServices } from './types';
import { LensTopNavMenu } from './lens_top_nav';
import { LensByReferenceInput } from '../embeddable';
-import { AddUserMessages, EditorFrameInstance, UserMessage, UserMessagesGetter } from '../types';
+import { AddUserMessages, EditorFrameInstance, UserMessagesGetter } from '../types';
import { Document } from '../persistence/saved_object_store';
import {
@@ -28,9 +28,8 @@ import {
LensAppState,
selectSavedObjectFormat,
updateIndexPatterns,
- updateDatasourceState,
selectActiveDatasourceId,
- selectFrameDatasourceAPI,
+ selectFramePublicAPI,
} from '../state_management';
import { SaveModalContainer, runSaveLensVisualization } from './save_modal_container';
import { LensInspector } from '../lens_inspector_service';
@@ -41,10 +40,7 @@ import {
createIndexPatternService,
} from '../data_views_service/service';
import { replaceIndexpattern } from '../state_management/lens_slice';
-import {
- filterAndSortUserMessages,
- getApplicationUserMessages,
-} from './get_application_user_messages';
+import { useApplicationUserMessages } from './get_application_user_messages';
export type SaveProps = Omit & {
returnToOrigin: boolean;
@@ -509,99 +505,25 @@ export function App({
const activeDatasourceId = useLensSelector(selectActiveDatasourceId);
- const frameDatasourceAPI = useLensSelector((state) =>
- selectFrameDatasourceAPI(state, datasourceMap)
- );
-
- const [userMessages, setUserMessages] = useState([]);
+ const framePublicAPI = useLensSelector((state) => selectFramePublicAPI(state, datasourceMap));
- useEffect(() => {
- setUserMessages([
- ...(activeDatasourceId
- ? datasourceMap[activeDatasourceId].getUserMessages(
- datasourceStates[activeDatasourceId].state,
- {
- frame: frameDatasourceAPI,
- setState: (newStateOrUpdater) => {
- dispatch(
- updateDatasourceState({
- newDatasourceState:
- typeof newStateOrUpdater === 'function'
- ? newStateOrUpdater(datasourceStates[activeDatasourceId].state)
- : newStateOrUpdater,
- datasourceId: activeDatasourceId,
- })
- );
- },
- }
- )
- : []),
- ...(visualization.activeId && visualization.state
- ? visualizationMap[visualization.activeId]?.getUserMessages?.(visualization.state, {
- frame: frameDatasourceAPI,
- }) ?? []
- : []),
- ...getApplicationUserMessages({
- visualizationType: persistedDoc?.visualizationType,
- visualizationMap,
- visualization,
- activeDatasource: activeDatasourceId ? datasourceMap[activeDatasourceId] : null,
- activeDatasourceState: activeDatasourceId ? datasourceStates[activeDatasourceId] : null,
- core: coreStart,
- dataViews: frameDatasourceAPI.dataViews,
- }),
- ]);
- }, [
- activeDatasourceId,
+ const { getUserMessages, addUserMessages } = useApplicationUserMessages({
coreStart,
- datasourceMap,
- datasourceStates,
+ framePublicAPI,
+ activeDatasourceId,
+ datasourceState:
+ activeDatasourceId && datasourceStates[activeDatasourceId]
+ ? datasourceStates[activeDatasourceId]
+ : null,
+ datasource:
+ activeDatasourceId && datasourceMap[activeDatasourceId]
+ ? datasourceMap[activeDatasourceId]
+ : null,
dispatch,
- frameDatasourceAPI,
- persistedDoc?.visualizationType,
- visualization,
- visualizationMap,
- ]);
-
- // these are messages managed from other parts of Lens
- const [additionalUserMessages, setAdditionalUserMessages] = useState>(
- {}
- );
-
- const getUserMessages: UserMessagesGetter = (locationId, filterArgs) =>
- filterAndSortUserMessages(
- [...userMessages, ...Object.values(additionalUserMessages)],
- locationId,
- filterArgs ?? {}
- );
-
- const addUserMessages: AddUserMessages = (messages) => {
- const newMessageMap = {
- ...additionalUserMessages,
- };
-
- const addedMessageIds: string[] = [];
- messages.forEach((message) => {
- if (!newMessageMap[message.uniqueId]) {
- addedMessageIds.push(message.uniqueId);
- newMessageMap[message.uniqueId] = message;
- }
- });
-
- if (addedMessageIds.length) {
- setAdditionalUserMessages(newMessageMap);
- }
-
- return () => {
- const withMessagesRemoved = {
- ...additionalUserMessages,
- };
-
- addedMessageIds.forEach((id) => delete withMessagesRemoved[id]);
-
- setAdditionalUserMessages(withMessagesRemoved);
- };
- };
+ visualization: visualization.activeId ? visualizationMap[visualization.activeId] : undefined,
+ visualizationType: visualization.activeId,
+ visualizationState: visualization,
+ });
return (
<>
diff --git a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx
index fa0ed4e21a668..f511e7e59112a 100644
--- a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx
+++ b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx
@@ -25,8 +25,8 @@ describe('application-level user messages', () => {
getApplicationUserMessages({
visualizationType: undefined,
- visualizationMap: {},
- visualization: { activeId: '', state: {} },
+ visualization: undefined,
+ visualizationState: { activeId: '', state: {} },
activeDatasource: {} as Datasource,
activeDatasourceState: null,
dataViews: {} as DataViewsState,
@@ -53,8 +53,8 @@ describe('application-level user messages', () => {
expect(
getApplicationUserMessages({
visualizationType: '123',
- visualizationMap: {},
- visualization: { activeId: 'id_for_type_that_doesnt_exist', state: {} },
+ visualization: undefined,
+ visualizationState: { activeId: 'id_for_type_that_doesnt_exist', state: {} },
activeDatasource: {} as Datasource,
activeDatasourceState: null,
@@ -84,8 +84,8 @@ describe('application-level user messages', () => {
activeDatasource: null,
visualizationType: '123',
- visualizationMap: { 'some-id': {} as Visualization },
- visualization: { activeId: 'some-id', state: {} },
+ visualization: {} as Visualization,
+ visualizationState: { activeId: 'some-id', state: {} },
activeDatasourceState: null,
dataViews: {} as DataViewsState,
core: {} as CoreStart,
@@ -138,8 +138,8 @@ describe('application-level user messages', () => {
const irrelevantProps = {
dataViews: {} as DataViewsState,
- visualizationMap: { foo: {} as Visualization },
- visualization: { activeId: 'foo', state: {} },
+ visualization: {} as Visualization,
+ visualizationState: { activeId: 'foo', state: {} },
};
it('generates error if missing an index pattern', () => {
diff --git a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx
index b5a2e0fe24def..4041fce3bbd0a 100644
--- a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx
+++ b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx
@@ -5,18 +5,27 @@
* 2.0.
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { FormattedMessage } from '@kbn/i18n-react';
import type { CoreStart } from '@kbn/core/public';
-import type { DataViewsState, VisualizationState } from '../state_management';
+import { Dispatch } from '@reduxjs/toolkit';
+import {
+ updateDatasourceState,
+ type DataViewsState,
+ type VisualizationState,
+ DatasourceState,
+} from '../state_management';
import type {
+ AddUserMessages,
Datasource,
+ FramePublicAPI,
UserMessage,
UserMessageFilters,
UserMessagesDisplayLocationId,
- VisualizationMap,
+ UserMessagesGetter,
+ Visualization,
} from '../types';
import { getMissingIndexPattern } from '../editor_frame_service/editor_frame/state_helpers';
@@ -26,15 +35,15 @@ import { getMissingIndexPattern } from '../editor_frame_service/editor_frame/sta
export const getApplicationUserMessages = ({
visualizationType,
visualization,
- visualizationMap,
+ visualizationState,
activeDatasource,
activeDatasourceState,
dataViews,
core,
}: {
visualizationType: string | null | undefined;
- visualization: VisualizationState | undefined;
- visualizationMap: VisualizationMap;
+ visualization: Visualization | undefined;
+ visualizationState: VisualizationState | undefined;
activeDatasource: Datasource | null | undefined;
activeDatasourceState: { isLoading: boolean; state: unknown } | null;
dataViews: DataViewsState;
@@ -46,8 +55,8 @@ export const getApplicationUserMessages = ({
messages.push(getMissingVisTypeError());
}
- if (visualization?.activeId && !visualizationMap[visualization.activeId]) {
- messages.push(getUnknownVisualizationTypeError(visualization.activeId));
+ if (visualizationState?.activeId && !visualization) {
+ messages.push(getUnknownVisualizationTypeError(visualizationState.activeId));
}
if (!activeDatasource) {
@@ -182,8 +191,8 @@ function getMissingIndexPatternsErrors(
export const filterAndSortUserMessages = (
userMessages: UserMessage[],
- locationId: UserMessagesDisplayLocationId | UserMessagesDisplayLocationId[] | undefined,
- { dimensionId, severity }: UserMessageFilters
+ locationId?: UserMessagesDisplayLocationId | UserMessagesDisplayLocationId[],
+ { dimensionId, severity }: UserMessageFilters = {}
) => {
const locationIds = Array.isArray(locationId)
? locationId
@@ -231,3 +240,112 @@ function bySeverity(a: UserMessage, b: UserMessage) {
}
return 1;
}
+
+export const useApplicationUserMessages = ({
+ coreStart,
+ dispatch,
+ activeDatasourceId,
+ datasource,
+ datasourceState,
+ framePublicAPI,
+ visualizationType,
+ visualization,
+ visualizationState,
+}: {
+ activeDatasourceId: string | null;
+ coreStart: CoreStart;
+ datasource: Datasource | null;
+ datasourceState: DatasourceState | null;
+ dispatch: Dispatch;
+ framePublicAPI: FramePublicAPI;
+ visualizationType: string | null;
+ visualizationState?: VisualizationState;
+ visualization?: Visualization;
+}) => {
+ const [userMessages, setUserMessages] = useState([]);
+ // these are messages managed from other parts of Lens
+ const [additionalUserMessages, setAdditionalUserMessages] = useState>(
+ {}
+ );
+
+ useEffect(() => {
+ setUserMessages([
+ ...(datasourceState && datasourceState.state && datasource && activeDatasourceId
+ ? datasource.getUserMessages(datasourceState.state, {
+ frame: framePublicAPI,
+ setState: (newStateOrUpdater) => {
+ dispatch(
+ updateDatasourceState({
+ newDatasourceState:
+ typeof newStateOrUpdater === 'function'
+ ? newStateOrUpdater(datasourceState.state)
+ : newStateOrUpdater,
+ datasourceId: activeDatasourceId,
+ })
+ );
+ },
+ })
+ : []),
+ ...(visualizationState?.activeId && visualizationState.state
+ ? visualization?.getUserMessages?.(visualizationState.state, {
+ frame: framePublicAPI,
+ }) ?? []
+ : []),
+ ...getApplicationUserMessages({
+ visualizationType,
+ visualization,
+ visualizationState,
+ activeDatasource: datasource,
+ activeDatasourceState: datasourceState,
+ core: coreStart,
+ dataViews: framePublicAPI.dataViews,
+ }),
+ ]);
+ }, [
+ activeDatasourceId,
+ datasource,
+ datasourceState,
+ dispatch,
+ framePublicAPI,
+ visualization,
+ visualizationState,
+ visualizationType,
+ coreStart,
+ ]);
+
+ const getUserMessages: UserMessagesGetter = (locationId, filterArgs) =>
+ filterAndSortUserMessages(
+ [...userMessages, ...Object.values(additionalUserMessages)],
+ locationId,
+ filterArgs ?? {}
+ );
+
+ const addUserMessages: AddUserMessages = (messages) => {
+ const newMessageMap = {
+ ...additionalUserMessages,
+ };
+
+ const addedMessageIds: string[] = [];
+ messages.forEach((message) => {
+ if (!newMessageMap[message.uniqueId]) {
+ addedMessageIds.push(message.uniqueId);
+ newMessageMap[message.uniqueId] = message;
+ }
+ });
+
+ if (addedMessageIds.length) {
+ setAdditionalUserMessages(newMessageMap);
+ }
+
+ return () => {
+ const withMessagesRemoved = {
+ ...additionalUserMessages,
+ };
+
+ addedMessageIds.forEach((id) => delete withMessagesRemoved[id]);
+
+ setAdditionalUserMessages(withMessagesRemoved);
+ };
+ };
+ return { getUserMessages, addUserMessages };
+};
diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts
index 591cfc322a8a0..acc77bd34c39c 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts
+++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts
@@ -26,7 +26,6 @@ import {
Datasource,
FramePublicAPI,
OperationDescriptor,
- FrameDatasourceAPI,
UserMessage,
} from '../../types';
import { getFieldByNameFactory } from './pure_helpers';
@@ -49,8 +48,9 @@ import {
import { createMockedFullReference } from './operations/mocks';
import { cloneDeep } from 'lodash';
import { Datatable, DatatableColumn } from '@kbn/expressions-plugin/common';
-import { createMockFramePublicAPI } from '../../mocks';
import { filterAndSortUserMessages } from '../../app_plugin/get_application_user_messages';
+import { createMockFramePublicAPI } from '../../mocks';
+import { createMockDataViewsState } from '../../data_views_service/mocks';
jest.mock('./loader');
jest.mock('../../id_generator');
@@ -3062,22 +3062,6 @@ describe('IndexPattern Data Source', () => {
});
describe('#getUserMessages', () => {
- function createMockFrameDatasourceAPI({
- activeData,
- dataViews,
- }: Partial> & {
- dataViews?: Partial;
- }): FrameDatasourceAPI {
- return {
- ...createMockFramePublicAPI({
- activeData,
- dataViews,
- }),
- query: { query: '', language: 'kuery' },
- filters: [],
- };
- }
-
describe('error messages', () => {
it('should generate error messages for a single layer', () => {
(getErrorMessages as jest.Mock).mockClear();
@@ -3094,7 +3078,9 @@ describe('IndexPattern Data Source', () => {
};
expect(
FormBasedDatasource.getUserMessages(state, {
- frame: createMockFrameDatasourceAPI({ dataViews: { indexPatterns } }),
+ frame: createMockFramePublicAPI({
+ dataViews: createMockDataViewsState({ indexPatterns }),
+ }),
setState: () => {},
})
).toMatchInlineSnapshot(`
@@ -3146,7 +3132,9 @@ describe('IndexPattern Data Source', () => {
};
expect(
FormBasedDatasource.getUserMessages(state, {
- frame: createMockFrameDatasourceAPI({ dataViews: { indexPatterns } }),
+ frame: createMockFramePublicAPI({
+ dataViews: createMockDataViewsState({ indexPatterns }),
+ }),
setState: () => {},
})
).toMatchInlineSnapshot(`
@@ -3235,7 +3223,9 @@ describe('IndexPattern Data Source', () => {
(getErrorMessages as jest.Mock).mockReturnValueOnce([]);
const messages = FormBasedDatasource.getUserMessages(state, {
- frame: createMockFrameDatasourceAPI({ dataViews: { indexPatterns } }),
+ frame: createMockFramePublicAPI({
+ dataViews: createMockDataViewsState({ indexPatterns }),
+ }),
setState: () => {},
});
@@ -3273,7 +3263,9 @@ describe('IndexPattern Data Source', () => {
] as ReturnType);
const messages = FormBasedDatasource.getUserMessages(state, {
- frame: createMockFrameDatasourceAPI({ dataViews: { indexPatterns } }),
+ frame: createMockFramePublicAPI({
+ dataViews: createMockDataViewsState({ indexPatterns }),
+ }),
setState: () => {},
});
@@ -3303,7 +3295,7 @@ describe('IndexPattern Data Source', () => {
describe('warning messages', () => {
let state: FormBasedPrivateState;
- let framePublicAPI: FrameDatasourceAPI;
+ let framePublicAPI: FramePublicAPI;
beforeEach(() => {
(getErrorMessages as jest.Mock).mockReturnValueOnce([]);
@@ -3385,7 +3377,7 @@ describe('IndexPattern Data Source', () => {
currentIndexPatternId: '1',
};
- framePublicAPI = createMockFrameDatasourceAPI({
+ framePublicAPI = createMockFramePublicAPI({
activeData: {
first: {
type: 'datatable',
@@ -3419,9 +3411,9 @@ describe('IndexPattern Data Source', () => {
],
},
},
- dataViews: {
+ dataViews: createMockDataViewsState({
indexPatterns: expectedIndexPatterns,
- },
+ }),
});
});
@@ -3549,13 +3541,13 @@ describe('IndexPattern Data Source', () => {
currentIndexPatternId: '1',
},
{
- frame: createMockFrameDatasourceAPI({
+ frame: createMockFramePublicAPI({
activeData: {
first: createDatatableForLayer(0),
},
- dataViews: {
+ dataViews: createMockDataViewsState({
indexPatterns: expectedIndexPatterns,
- },
+ }),
}),
setState: () => {},
visualizationInfo: { layers: [] },
@@ -3574,14 +3566,14 @@ describe('IndexPattern Data Source', () => {
currentIndexPatternId: '1',
};
const messages = FormBasedDatasource.getUserMessages!(state, {
- frame: createMockFrameDatasourceAPI({
+ frame: createMockFramePublicAPI({
activeData: {
first: createDatatableForLayer(0),
second: createDatatableForLayer(1),
},
- dataViews: {
+ dataViews: createMockDataViewsState({
indexPatterns: expectedIndexPatterns,
- },
+ }),
}),
setState: () => {},
visualizationInfo: { layers: [] },
diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx
index a458c6f804da4..8099a787437ba 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx
+++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx
@@ -38,7 +38,6 @@ import type {
IndexPatternRef,
DataSourceInfo,
UserMessage,
- FrameDatasourceAPI,
StateSetter,
IndexPatternMap,
} from '../../types';
@@ -749,18 +748,12 @@ export function getFormBasedDatasource({
getDatasourceSuggestionsForVisualizeField,
getDatasourceSuggestionsForVisualizeCharts,
- getUserMessages(state, { frame: frameDatasourceAPI, setState, visualizationInfo }) {
+ getUserMessages(state, { frame: framePublicAPI, setState, visualizationInfo }) {
if (!state) {
return [];
}
- const layerErrorMessages = getLayerErrorMessages(
- state,
- frameDatasourceAPI,
- setState,
- core,
- data
- );
+ const layerErrorMessages = getLayerErrorMessages(state, framePublicAPI, setState, core, data);
const dimensionErrorMessages = getInvalidDimensionErrorMessages(
state,
@@ -770,8 +763,8 @@ export function getFormBasedDatasource({
return !isColumnInvalid(
layer,
columnId,
- frameDatasourceAPI.dataViews.indexPatterns[layer.indexPatternId],
- frameDatasourceAPI.dateRange,
+ framePublicAPI.dataViews.indexPatterns[layer.indexPatternId],
+ framePublicAPI.dateRange,
uiSettings.get(UI_SETTINGS.HISTOGRAM_BAR_TARGET)
);
}
@@ -779,11 +772,8 @@ export function getFormBasedDatasource({
const warningMessages = [
...[
- ...(getStateTimeShiftWarningMessages(
- data.datatableUtilities,
- state,
- frameDatasourceAPI
- ) || []),
+ ...(getStateTimeShiftWarningMessages(data.datatableUtilities, state, framePublicAPI) ||
+ []),
].map((longMessage) => {
const message: UserMessage = {
severity: 'warning',
@@ -798,14 +788,14 @@ export function getFormBasedDatasource({
...getPrecisionErrorWarningMessages(
data.datatableUtilities,
state,
- frameDatasourceAPI,
+ framePublicAPI,
core.docLinks,
setState
),
- ...getUnsupportedOperationsWarningMessage(state, frameDatasourceAPI, core.docLinks),
+ ...getUnsupportedOperationsWarningMessage(state, framePublicAPI, core.docLinks),
];
- const infoMessages = getNotifiableFeatures(state, frameDatasourceAPI, visualizationInfo);
+ const infoMessages = getNotifiableFeatures(state, framePublicAPI, visualizationInfo);
return layerErrorMessages.concat(dimensionErrorMessages, warningMessages, infoMessages);
},
@@ -922,12 +912,12 @@ function blankLayer(indexPatternId: string, linkToLayers?: string[]): FormBasedL
function getLayerErrorMessages(
state: FormBasedPrivateState,
- frameDatasourceAPI: FrameDatasourceAPI,
+ framePublicAPI: FramePublicAPI,
setState: StateSetter,
core: CoreStart,
data: DataPublicPluginStart
) {
- const indexPatterns = frameDatasourceAPI.dataViews.indexPatterns;
+ const indexPatterns = framePublicAPI.dataViews.indexPatterns;
const layerErrors: UserMessage[][] = Object.entries(state.layers)
.filter(([_, layer]) => !!indexPatterns[layer.indexPatternId])
@@ -954,7 +944,7 @@ function getLayerErrorMessages(
{
- const newState = await error.fixAction?.newState(frameDatasourceAPI);
+ const newState = await error.fixAction?.newState(framePublicAPI);
if (newState) {
setState(newState);
}
diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/index.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/index.ts
index a5ac36a5b4ad1..3c62f34cbc1f2 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/index.ts
+++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/index.ts
@@ -51,7 +51,7 @@ import {
import { staticValueOperation } from './static_value';
import { lastValueOperation } from './last_value';
import type {
- FrameDatasourceAPI,
+ FramePublicAPI,
IndexPattern,
IndexPatternField,
OperationMetadata,
@@ -477,7 +477,7 @@ export type FieldBasedOperationErrorMessage =
newState: (
data: DataPublicPluginStart,
core: CoreStart,
- frame: FrameDatasourceAPI,
+ frame: FramePublicAPI,
layerId: string
) => Promise;
};
diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.test.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.test.ts
index 6be9e8a76fa3e..583f3ff5015c2 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.test.ts
+++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.test.ts
@@ -7,7 +7,7 @@
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { coreMock as corePluginMock } from '@kbn/core/public/mocks';
-import type { FrameDatasourceAPI } from '../../../../../types';
+import type { FramePublicAPI } from '../../../../../types';
import type { CountIndexPatternColumn } from '..';
import type { TermsIndexPatternColumn } from './types';
import type { GenericIndexPatternColumn } from '../../../form_based';
@@ -245,7 +245,7 @@ describe('getDisallowedTermsMessage()', () => {
fromDate: '2020',
toDate: '2021',
},
- } as unknown as FrameDatasourceAPI,
+ } as unknown as FramePublicAPI,
'first'
);
@@ -299,7 +299,7 @@ describe('getDisallowedTermsMessage()', () => {
rows: [{ col1: 'myTerm' }, { col1: 'myOtherTerm' }],
},
},
- } as unknown as FrameDatasourceAPI,
+ } as unknown as FramePublicAPI,
'first'
);
@@ -335,7 +335,7 @@ describe('getDisallowedTermsMessage()', () => {
fromDate: '2020',
toDate: '2021',
},
- } as unknown as FrameDatasourceAPI,
+ } as unknown as FramePublicAPI,
'first'
);
@@ -385,7 +385,7 @@ describe('getDisallowedTermsMessage()', () => {
],
},
},
- } as unknown as FrameDatasourceAPI,
+ } as unknown as FramePublicAPI,
'first'
);
diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.ts
index a1b528f2d0f7f..cb3ed583d7cda 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.ts
+++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/helpers.ts
@@ -17,7 +17,7 @@ import { GenericIndexPatternColumn, operationDefinitionMap } from '..';
import { defaultLabel } from '../filters';
import { isReferenced } from '../../layer_helpers';
-import type { FrameDatasourceAPI, IndexPattern, IndexPatternField } from '../../../../../types';
+import type { FramePublicAPI, IndexPattern, IndexPatternField } from '../../../../../types';
import type { FiltersIndexPatternColumn } from '..';
import type { TermsIndexPatternColumn } from './types';
import type { LastValueIndexPatternColumn } from '../last_value';
@@ -126,7 +126,7 @@ export function getDisallowedTermsMessage(
newState: async (
data: DataPublicPluginStart,
core: CoreStart,
- frame: FrameDatasourceAPI,
+ frame: FramePublicAPI,
layerId: string
) => {
const currentColumn = layer.columns[columnId] as TermsIndexPatternColumn;
diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/terms.test.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/terms.test.tsx
index c5af3b5b40e2f..a74872a46f907 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/terms.test.tsx
+++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/terms.test.tsx
@@ -33,7 +33,7 @@ import {
operationDefinitionMap,
} from '..';
import { FormBasedLayer, FormBasedPrivateState } from '../../../types';
-import { FrameDatasourceAPI } from '../../../../../types';
+import { FramePublicAPI } from '../../../../../types';
import { DateHistogramIndexPatternColumn } from '../date_histogram';
import { getOperationSupportMatrix } from '../../../dimension_panel/operation_support';
import { FieldSelect } from '../../../dimension_panel/field_select';
@@ -2867,7 +2867,7 @@ describe('terms', () => {
fromDate: '2020',
toDate: '2021',
},
- } as unknown as FrameDatasourceAPI,
+ } as unknown as FramePublicAPI,
'first'
);
expect(newLayer.columns.col1).toEqual(
diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/layer_helpers.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/layer_helpers.ts
index 37a742b426edb..6ab10a097010d 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/operations/layer_helpers.ts
+++ b/x-pack/plugins/lens/public/datasources/form_based/operations/layer_helpers.ts
@@ -13,7 +13,7 @@ import { DataPublicPluginStart, UI_SETTINGS } from '@kbn/data-plugin/public';
import type { DateRange } from '../../../../common/types';
import type {
DatasourceFixAction,
- FrameDatasourceAPI,
+ FramePublicAPI,
IndexPattern,
IndexPatternField,
OperationMetadata,
@@ -1594,7 +1594,7 @@ export function getErrorMessages(
fixAction: errorMessage.fixAction
? {
...errorMessage.fixAction,
- newState: async (frame: FrameDatasourceAPI) => ({
+ newState: async (frame: FramePublicAPI) => ({
...state,
layers: {
...state.layers,
diff --git a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts
index 0b0437cc96c0b..8aab2f3670959 100644
--- a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts
+++ b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.test.ts
@@ -13,7 +13,7 @@ import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { getTextBasedDatasource } from './text_based_languages';
import { generateId } from '../../id_generator';
-import { DatasourcePublicAPI, Datasource, FrameDatasourceAPI } from '../../types';
+import { DatasourcePublicAPI, Datasource, FramePublicAPI } from '../../types';
jest.mock('../../id_generator');
@@ -551,7 +551,7 @@ describe('Textbased Data Source', () => {
} as unknown as TextBasedPrivateState;
expect(
TextBasedDatasource.getUserMessages(state, {
- frame: { dataViews: indexPatterns } as unknown as FrameDatasourceAPI,
+ frame: { dataViews: indexPatterns } as unknown as FramePublicAPI,
setState: () => {},
})
).toMatchInlineSnapshot(`
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx
index c5ec748aa9bf0..b0729cb489ba7 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx
@@ -477,12 +477,14 @@ describe('ConfigPanel', () => {
expect(visualizationMap.testVis.setDimension).toHaveBeenCalledWith({
columnId: 'newId',
frame: {
+ dataViews: expect.anything(),
activeData: undefined,
datasourceLayers: {
a: expect.anything(),
},
dateRange: expect.anything(),
- dataViews: expect.anything(),
+ filters: [],
+ query: undefined,
},
groupId: 'a',
layerId: 'newId',
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx
index 3d90273ef0d14..0362f130be87d 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx
@@ -38,6 +38,7 @@ import {
DatasourceMock,
createExpressionRendererMock,
mockStoreDeps,
+ renderWithReduxStore,
} from '../../mocks';
import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks';
import { ReactExpressionRendererType } from '@kbn/expressions-plugin/public';
@@ -283,7 +284,7 @@ describe('editor_frame', () => {
const props = {
...getDefaultProps(),
visualizationMap: {
- testVis: mockVisualization,
+ testVis: { ...mockVisualization, toExpression: () => null },
},
datasourceMap: {
testDatasource: mockDatasource,
@@ -291,18 +292,23 @@ describe('editor_frame', () => {
ExpressionRenderer: expressionRendererMock,
};
- await mountWithProvider(, {
- preloadedState: {
- activeDatasourceId: 'testDatasource',
- visualization: { activeId: mockVisualization.id, state: {} },
- datasourceStates: {
- testDatasource: {
- isLoading: false,
- state: '',
+ renderWithReduxStore(
+ ,
+ {},
+ {
+ preloadedState: {
+ activeDatasourceId: 'testDatasource',
+ visualization: { activeId: mockVisualization.id, state: {} },
+ datasourceStates: {
+ testDatasource: {
+ isLoading: false,
+ state: '',
+ },
},
},
- },
- });
+ }
+ );
+
const updatedState = {};
const setDatasourceState = (mockDatasource.DataPanelComponent as jest.Mock).mock.calls[0][0]
.setState;
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts
index e12182cd07bff..466773ec1c6b2 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts
@@ -35,7 +35,7 @@ import type {
import { buildExpression } from './expression_helpers';
import { Document } from '../../persistence/saved_object_store';
import { getActiveDatasourceIdFromDoc, sortDataViewRefs } from '../../utils';
-import type { DatasourceStates, VisualizationState } from '../../state_management';
+import type { DatasourceState, DatasourceStates, VisualizationState } from '../../state_management';
import { readFromStorage } from '../../settings_storage';
import { loadIndexPatternRefs, loadIndexPatterns } from '../../data_views_service/loader';
import { getDatasourceLayers } from '../../state_management/utils';
@@ -461,7 +461,7 @@ export async function persistedStateToExpression(
export function getMissingIndexPattern(
currentDatasource: Datasource | null | undefined,
- currentDatasourceState: { isLoading: boolean; state: unknown } | null,
+ currentDatasourceState: DatasourceState | null,
indexPatterns: IndexPatternMap
) {
if (
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx
index 09e5c6406e793..24fe5c971558c 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.test.tsx
@@ -381,8 +381,9 @@ describe('suggestion_panel', () => {
},
] as Suggestion[]);
- (mockVisualization.toPreviewExpression as jest.Mock).mockReturnValueOnce(undefined);
- (mockVisualization.toPreviewExpression as jest.Mock).mockReturnValueOnce('test | expression');
+ (mockVisualization.toPreviewExpression as jest.Mock)
+ .mockReturnValue(undefined)
+ .mockReturnValueOnce('test | expression');
mockDatasource.toExpression.mockReturnValue('datasource_expression');
mountWithProvider();
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
index 51f0e3310ccdb..a4e65b280d203 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx
@@ -41,7 +41,6 @@ import {
VisualizationMap,
DatasourceLayers,
UserMessagesGetter,
- FrameDatasourceAPI,
} from '../../types';
import { getSuggestions, switchToSuggestion } from './suggestion_helpers';
import { getDatasourceExpressionsByLayers } from './expression_helpers';
@@ -63,7 +62,7 @@ import {
selectChangesApplied,
applyChanges,
selectStagedActiveData,
- selectFrameDatasourceAPI,
+ selectFramePublicAPI,
} from '../../state_management';
import { filterAndSortUserMessages } from '../../app_plugin/get_application_user_messages';
const MAX_SUGGESTIONS_DISPLAYED = 5;
@@ -74,7 +73,7 @@ const configurationsValid = (
currentDatasourceState: unknown,
currentVisualization: Visualization,
currentVisualizationState: unknown,
- frame: FrameDatasourceAPI
+ frame: FramePublicAPI
): boolean => {
try {
return (
@@ -241,9 +240,7 @@ export function SuggestionPanel({
const currentVisualization = useLensSelector(selectCurrentVisualization);
const currentDatasourceStates = useLensSelector(selectCurrentDatasourceStates);
- const frameDatasourceAPI = useLensSelector((state) =>
- selectFrameDatasourceAPI(state, datasourceMap)
- );
+ const framePublicAPI = useLensSelector((state) => selectFramePublicAPI(state, datasourceMap));
const changesApplied = useLensSelector(selectChangesApplied);
// get user's selection from localStorage, this key defines if the suggestions panel will be hidden or not
const [hideSuggestions, setHideSuggestions] = useLocalStorage(
@@ -289,7 +286,7 @@ export function SuggestionPanel({
suggestionDatasourceState,
visualizationMap[visualizationId],
suggestionVisualizationState,
- frameDatasourceAPI
+ framePublicAPI
)
);
}
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx
index 6323dbf5c96f4..a8e834e43881c 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx
@@ -380,7 +380,7 @@ describe('workspace_panel', () => {
}}
framePublicAPI={framePublicAPI}
visualizationMap={{
- testVis: mockVisualization,
+ testVis: { ...mockVisualization, toExpression: () => null },
}}
ExpressionRenderer={expressionRendererMock}
/>,
diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx
index a0a2faec5294d..b9d0bae197909 100644
--- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx
+++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx
@@ -97,7 +97,7 @@ import {
GetCompatibleCellValueActions,
UserMessage,
IndexPatternRef,
- FrameDatasourceAPI,
+ FramePublicAPI,
AddUserMessages,
isMessageRemovable,
UserMessagesGetter,
@@ -608,11 +608,14 @@ export class Embeddable
userMessages.push(
...getApplicationUserMessages({
visualizationType: this.savedVis?.visualizationType,
- visualization: {
+ visualizationState: {
state: this.activeVisualizationState,
activeId: this.activeVisualizationId,
},
- visualizationMap: this.deps.visualizationMap,
+ visualization:
+ this.activeVisualizationId && this.deps.visualizationMap[this.activeVisualizationId]
+ ? this.deps.visualizationMap[this.activeVisualizationId]
+ : undefined,
activeDatasource: this.activeDatasource,
activeDatasourceState: {
isLoading: !this.activeDatasourceState,
@@ -631,7 +634,7 @@ export class Embeddable
}
const mergedSearchContext = this.getMergedSearchContext();
- const frameDatasourceAPI: FrameDatasourceAPI = {
+ const framePublicAPI: FramePublicAPI = {
dataViews: {
indexPatterns: this.indexPatterns,
indexPatternRefs: this.indexPatternRefs,
@@ -658,14 +661,14 @@ export class Embeddable
userMessages.push(
...(this.activeDatasource?.getUserMessages(this.activeDatasourceState, {
setState: () => {},
- frame: frameDatasourceAPI,
+ frame: framePublicAPI,
visualizationInfo: this.activeVisualization?.getVisualizationInfo?.(
this.activeVisualizationState,
- frameDatasourceAPI
+ framePublicAPI
),
}) ?? []),
...(this.activeVisualization?.getUserMessages?.(this.activeVisualizationState, {
- frame: frameDatasourceAPI,
+ frame: framePublicAPI,
}) ?? [])
);
diff --git a/x-pack/plugins/lens/public/mocks/datasource_mock.tsx b/x-pack/plugins/lens/public/mocks/datasource_mock.tsx
index e4f9f5c88fdc1..c92c3007a800a 100644
--- a/x-pack/plugins/lens/public/mocks/datasource_mock.tsx
+++ b/x-pack/plugins/lens/public/mocks/datasource_mock.tsx
@@ -44,7 +44,9 @@ export function createMockDatasource(
getRenderEventCounters: jest.fn((_state) => []),
getPublicAPI: jest.fn().mockReturnValue(publicAPIMock),
initialize: jest.fn((_state?) => {}),
- toExpression: jest.fn((_frame, _state, _indexPatterns, dateRange, nowInstant) => null),
+ toExpression: jest.fn(
+ (_frame, _state, _indexPatterns, dateRange, nowInstant) => 'datasource_expression'
+ ),
insertLayer: jest.fn((_state, _newLayerId) => ({})),
removeLayer: jest.fn((state, layerId) => ({ newState: state, removedLayerIds: [layerId] })),
cloneLayer: jest.fn((_state, _layerId, _newLayerId, getNewId) => {}),
@@ -62,7 +64,7 @@ export function createMockDatasource(
getUserMessages: jest.fn((_state, _deps) => []),
checkIntegrity: jest.fn((_state, _indexPatterns) => []),
isTimeBased: jest.fn(),
- isEqual: jest.fn(),
+ isEqual: jest.fn((a, b, c, d) => a === c),
getUsedDataView: jest.fn((state, layer) => 'mockip'),
getUsedDataViews: jest.fn(),
onRefreshIndexPattern: jest.fn(),
diff --git a/x-pack/plugins/lens/public/mocks/index.ts b/x-pack/plugins/lens/public/mocks/index.ts
index 74fbe267d635a..6cc3ff02ff92e 100644
--- a/x-pack/plugins/lens/public/mocks/index.ts
+++ b/x-pack/plugins/lens/public/mocks/index.ts
@@ -8,7 +8,7 @@
import { DragContextState, DragContextValue } from '@kbn/dom-drag-drop';
import { DatatableColumnType } from '@kbn/expressions-plugin/common';
import { createMockDataViewsState } from '../data_views_service/mocks';
-import { FramePublicAPI, FrameDatasourceAPI } from '../types';
+import { FramePublicAPI } from '../types';
export { mockDataPlugin } from './data_plugin_mock';
export {
visualizationMap,
@@ -32,40 +32,16 @@ export { lensPluginMock } from './lens_plugin_mock';
export type FrameMock = jest.Mocked;
-export const createMockFramePublicAPI = ({
- datasourceLayers,
- dateRange,
- dataViews,
- activeData,
-}: Partial> & {
- dataViews?: Partial;
-} = {}): FrameMock => ({
- datasourceLayers: datasourceLayers ?? {},
- dateRange: dateRange ?? {
+export const createMockFramePublicAPI = (overrides: Partial = {}): FrameMock => ({
+ datasourceLayers: {},
+ dateRange: {
fromDate: '2022-03-17T08:25:00.000Z',
toDate: '2022-04-17T08:25:00.000Z',
},
- dataViews: createMockDataViewsState(dataViews),
- activeData,
-});
-
-export type FrameDatasourceMock = jest.Mocked;
-
-export const createMockFrameDatasourceAPI = ({
- datasourceLayers,
- dateRange,
- dataViews,
- query,
- filters,
-}: Partial = {}): FrameDatasourceMock => ({
- datasourceLayers: datasourceLayers ?? {},
- dateRange: dateRange ?? {
- fromDate: '2022-03-17T08:25:00.000Z',
- toDate: '2022-04-17T08:25:00.000Z',
- },
- query: query ?? { query: '', language: 'lucene' },
- filters: filters ?? [],
- dataViews: createMockDataViewsState(dataViews),
+ dataViews: createMockDataViewsState(),
+ query: { query: '', language: 'lucene' },
+ filters: [],
+ ...overrides,
});
export function createMockedDragDropContext(
diff --git a/x-pack/plugins/lens/public/mocks/store_mocks.tsx b/x-pack/plugins/lens/public/mocks/store_mocks.tsx
index cafb7796969c8..9a3d33afa1aa7 100644
--- a/x-pack/plugins/lens/public/mocks/store_mocks.tsx
+++ b/x-pack/plugins/lens/public/mocks/store_mocks.tsx
@@ -13,26 +13,14 @@ import { act } from 'react-dom/test-utils';
import { PreloadedState } from '@reduxjs/toolkit';
import { RenderOptions, render } from '@testing-library/react';
import { I18nProvider } from '@kbn/i18n-react';
-// imported to prevent a type error from testing library https://github.com/testing-library/react-testing-library/issues/587
-import * as ___ from '@testing-library/dom';
-
import { LensAppServices } from '../app_plugin/types';
-import {
- makeConfigureStore,
- LensAppState,
- LensState,
- LensStoreDeps,
- LensRootStore,
-} from '../state_management';
+import { makeConfigureStore, LensAppState, LensState, LensStoreDeps } from '../state_management';
import { getResolvedDateRange } from '../utils';
import { DatasourceMap, VisualizationMap } from '../types';
import { mockVisualizationMap } from './visualization_mock';
import { mockDatasourceMap } from './datasource_mock';
import { makeDefaultServices } from './services_mock';
-// preventing a type error from testing library https://github.com/testing-library/react-testing-library/issues/587
-export const unusedFn = () => ___;
-
export const mockStoreDeps = (deps?: {
lensServices?: LensAppServices;
datasourceMap?: DatasourceMap;
@@ -85,7 +73,8 @@ export const renderWithReduxStore = (
preloadedState: {},
storeDeps: mockStoreDeps(),
}
-): ReturnType & { store: LensRootStore } => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+): any => {
const { store } = makeLensStore({ preloadedState, storeDeps });
const Wrapper: React.FC<{
diff --git a/x-pack/plugins/lens/public/mocks/visualization_mock.tsx b/x-pack/plugins/lens/public/mocks/visualization_mock.tsx
index 80f20e8c3af4e..3d25f7e29864b 100644
--- a/x-pack/plugins/lens/public/mocks/visualization_mock.tsx
+++ b/x-pack/plugins/lens/public/mocks/visualization_mock.tsx
@@ -44,9 +44,9 @@ export function createMockVisualization(id = 'testVis'): jest.Mocked null),
- toPreviewExpression: jest.fn((_state, _frame) => null),
-
+ toExpression: jest.fn((_state, _frame) => 'expression'),
+ toPreviewExpression: jest.fn((_state, _frame) => 'expression'),
+ getUserMessages: jest.fn((_state) => []),
setDimension: jest.fn(),
removeDimension: jest.fn(),
DimensionEditorComponent: jest.fn(() => ),
diff --git a/x-pack/plugins/lens/public/state_management/selectors.ts b/x-pack/plugins/lens/public/state_management/selectors.ts
index 6bf40638554f9..7572c31287297 100644
--- a/x-pack/plugins/lens/public/state_management/selectors.ts
+++ b/x-pack/plugins/lens/public/state_management/selectors.ts
@@ -220,10 +220,10 @@ export const selectFramePublicAPI = createSelector(
selectCurrentDatasourceStates,
selectActiveData,
selectInjectedDependencies as SelectInjectedDependenciesFunction,
- selectResolvedDateRange,
selectDataViews,
+ selectExecutionContext,
],
- (datasourceStates, activeData, datasourceMap, dateRange, dataViews) => {
+ (datasourceStates, activeData, datasourceMap, dataViews, context) => {
return {
datasourceLayers: getDatasourceLayers(
datasourceStates,
@@ -231,13 +231,8 @@ export const selectFramePublicAPI = createSelector(
dataViews.indexPatterns
),
activeData,
- dateRange,
dataViews,
+ ...context,
};
}
);
-
-export const selectFrameDatasourceAPI = createSelector(
- [selectFramePublicAPI, selectExecutionContext],
- (framePublicAPI, context) => ({ ...context, ...framePublicAPI })
-);
diff --git a/x-pack/plugins/lens/public/state_management/types.ts b/x-pack/plugins/lens/public/state_management/types.ts
index c2d0e1ef2e386..85e7dae2f92ce 100644
--- a/x-pack/plugins/lens/public/state_management/types.ts
+++ b/x-pack/plugins/lens/public/state_management/types.ts
@@ -34,7 +34,12 @@ export interface DataViewsState {
indexPatterns: Record;
}
-export type DatasourceStates = Record;
+export interface DatasourceState {
+ isLoading: boolean;
+ state: unknown;
+}
+
+export type DatasourceStates = Record;
export interface PreviewState {
visualization: VisualizationState;
datasourceStates: DatasourceStates;
diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts
index 70ee578c47cc2..6ac2b98569d7f 100644
--- a/x-pack/plugins/lens/public/types.ts
+++ b/x-pack/plugins/lens/public/types.ts
@@ -460,7 +460,7 @@ export interface Datasource {
getUserMessages: (
state: T,
deps: {
- frame: FrameDatasourceAPI;
+ frame: FramePublicAPI;
setState: StateSetter;
visualizationInfo?: VisualizationInfo;
}
@@ -513,7 +513,7 @@ export interface Datasource {
export interface DatasourceFixAction {
label: string;
- newState: (frame: FrameDatasourceAPI) => Promise;
+ newState: (frame: FramePublicAPI) => Promise;
}
/**
@@ -925,6 +925,8 @@ export interface VisualizationSuggestion {
export type DatasourceLayers = Partial>;
export interface FramePublicAPI {
+ query: Query;
+ filters: Filter[];
datasourceLayers: DatasourceLayers;
dateRange: DateRange;
/**
@@ -936,11 +938,6 @@ export interface FramePublicAPI {
dataViews: DataViewsState;
}
-export interface FrameDatasourceAPI extends FramePublicAPI {
- query: Query;
- filters: Filter[];
-}
-
/**
* A visualization type advertised to the user in the chart switcher
*/
diff --git a/x-pack/plugins/lens/public/visualizations/xy/__snapshots__/to_expression.test.ts.snap b/x-pack/plugins/lens/public/visualizations/xy/__snapshots__/to_expression.test.ts.snap
index 0cb3d014853fe..7dfe39667fd22 100644
--- a/x-pack/plugins/lens/public/visualizations/xy/__snapshots__/to_expression.test.ts.snap
+++ b/x-pack/plugins/lens/public/visualizations/xy/__snapshots__/to_expression.test.ts.snap
@@ -27,6 +27,11 @@ Object {
"layers": Array [
Object {
"chain": Array [
+ Object {
+ "arguments": Object {},
+ "function": "datasource_expression",
+ "type": "function",
+ },
Object {
"arguments": Object {
"accessors": Array [
diff --git a/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts b/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts
index 9cdf33c134c8c..2e63f26413c5e 100644
--- a/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts
+++ b/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts
@@ -265,7 +265,7 @@ describe('#toExpression', () => {
expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('c');
expect(mockDatasource.publicAPIMock.getOperationForColumnId).toHaveBeenCalledWith('d');
expect(
- (expression.chain[0].arguments.layers[0] as Ast).chain[0].arguments.columnToLabel
+ (expression.chain[0].arguments.layers[0] as Ast).chain[1].arguments.columnToLabel
).toEqual([
JSON.stringify({
b: 'col_b',
@@ -536,13 +536,18 @@ describe('#toExpression', () => {
datasourceExpressionsByLayers
) as Ast;
- function getYConfigColorForLayer(ast: Ast, index: number) {
+ function getYConfigColorForDataLayer(ast: Ast, index: number) {
+ return (
+ (ast.chain[0].arguments.layers[index] as Ast).chain[1].arguments.decorations[0] as Ast
+ ).chain[0].arguments?.color;
+ }
+ function getYConfigColorForReferenceLayer(ast: Ast, index: number) {
return (
(ast.chain[0].arguments.layers[index] as Ast).chain[0].arguments.decorations[0] as Ast
- ).chain[0].arguments.color;
+ ).chain[0].arguments?.color;
}
- expect(getYConfigColorForLayer(expression, 0)).toBeUndefined();
- expect(getYConfigColorForLayer(expression, 1)).toEqual([defaultReferenceLineColor]);
+ expect(getYConfigColorForDataLayer(expression, 0)).toBeUndefined();
+ expect(getYConfigColorForReferenceLayer(expression, 1)).toEqual([defaultReferenceLineColor]);
});
it('should ignore annotation layers with no event configured', () => {
diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx
index b73379acd1518..7edcf5b53f724 100644
--- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx
+++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx
@@ -25,7 +25,7 @@ import { useFindListsBySize } from '@kbn/securitysolution-list-hooks';
import type { FieldSpec } from '@kbn/data-plugin/common';
import { fields, getField } from '@kbn/data-plugin/common/mocks';
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { ReactWrapper, mount } from 'enzyme';
import { getFoundListsBySizeSchemaMock } from '../../../../common/schemas/response/found_lists_by_size_schema.mock';
diff --git a/x-pack/plugins/lists/server/routes/utils/build_siem_response.ts b/x-pack/plugins/lists/server/routes/utils/build_siem_response.ts
index 4a5ed5cc4b0e0..d61a02a869d28 100644
--- a/x-pack/plugins/lists/server/routes/utils/build_siem_response.ts
+++ b/x-pack/plugins/lists/server/routes/utils/build_siem_response.ts
@@ -49,7 +49,7 @@ export class SiemResponseFactory {
constructor(private response: KibanaResponseFactory) {}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
- error({ statusCode, body, headers }: CustomHttpResponseOptions) {
+ error({ statusCode, body, headers, bypassErrorFormat }: CustomHttpResponseOptions) {
// KibanaResponse is not exported so we cannot use a return type here and that is why the linter is turned off above
const contentType: CustomHttpResponseOptions['headers'] = {
'content-type': 'application/json',
@@ -59,10 +59,14 @@ export class SiemResponseFactory {
...(headers ?? {}),
};
+ const formattedBody = bypassErrorFormat
+ ? body
+ : { message: body ?? statusToErrorMessage(statusCode) };
+
return this.response.custom({
body: Buffer.from(
JSON.stringify({
- message: body ?? statusToErrorMessage(statusCode),
+ ...formattedBody,
status_code: statusCode,
})
),
diff --git a/x-pack/plugins/log_explorer/kibana.jsonc b/x-pack/plugins/log_explorer/kibana.jsonc
index 76eb47e4a5915..71781ca9cada3 100644
--- a/x-pack/plugins/log_explorer/kibana.jsonc
+++ b/x-pack/plugins/log_explorer/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/log-explorer-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-ux-logs-team",
"description": "This plugin provides a LogExplorer component using the Discover customization framework, offering several affordances specifically designed for log consumption.",
"plugin": {
"id": "logExplorer",
diff --git a/x-pack/plugins/log_explorer/public/components/log_explorer/log_explorer.tsx b/x-pack/plugins/log_explorer/public/components/log_explorer/log_explorer.tsx
index 0612713085224..57736dd4b96dd 100644
--- a/x-pack/plugins/log_explorer/public/components/log_explorer/log_explorer.tsx
+++ b/x-pack/plugins/log_explorer/public/components/log_explorer/log_explorer.tsx
@@ -17,6 +17,7 @@ import { createLogExplorerProfileCustomizations } from '../../customizations/log
import { createPropertyGetProxy } from '../../utils/proxies';
import { LogExplorerProfileContext } from '../../state_machines/log_explorer_profile';
import { LogExplorerStartDeps } from '../../types';
+import { LogExplorerCustomizations } from './types';
export interface CreateLogExplorerArgs {
core: CoreStart;
@@ -29,6 +30,7 @@ export interface LogExplorerStateContainer {
}
export interface LogExplorerProps {
+ customizations?: LogExplorerCustomizations;
scopedHistory: ScopedHistory;
state$?: BehaviorSubject;
}
@@ -44,10 +46,10 @@ export const createLogExplorer = ({ core, plugins }: CreateLogExplorerArgs) => {
uiSettings: createUiSettingsServiceProxy(core.uiSettings),
};
- return ({ scopedHistory, state$ }: LogExplorerProps) => {
+ return ({ customizations = {}, scopedHistory, state$ }: LogExplorerProps) => {
const logExplorerCustomizations = useMemo(
- () => [createLogExplorerProfileCustomizations({ core, plugins, state$ })],
- [state$]
+ () => [createLogExplorerProfileCustomizations({ core, customizations, plugins, state$ })],
+ [customizations, state$]
);
return (
diff --git a/x-pack/plugins/log_explorer/public/components/log_explorer/types.ts b/x-pack/plugins/log_explorer/public/components/log_explorer/types.ts
new file mode 100644
index 0000000000000..2b366cce7c55c
--- /dev/null
+++ b/x-pack/plugins/log_explorer/public/components/log_explorer/types.ts
@@ -0,0 +1,25 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { DataTableRecord } from '@kbn/discover-utils/types';
+
+export type RenderPreviousContent = () => React.ReactNode;
+
+export interface LogExplorerFlyoutContentProps {
+ doc: DataTableRecord;
+}
+
+export type FlyoutRenderContent = (
+ renderPreviousContent: RenderPreviousContent,
+ props: LogExplorerFlyoutContentProps
+) => React.ReactNode;
+
+export interface LogExplorerCustomizations {
+ flyout?: {
+ renderContent?: FlyoutRenderContent;
+ };
+}
diff --git a/x-pack/plugins/log_explorer/public/customizations/custom_flyout_content.tsx b/x-pack/plugins/log_explorer/public/customizations/custom_flyout_content.tsx
index a4b473119744a..e7a5b7ed35915 100644
--- a/x-pack/plugins/log_explorer/public/customizations/custom_flyout_content.tsx
+++ b/x-pack/plugins/log_explorer/public/customizations/custom_flyout_content.tsx
@@ -5,10 +5,11 @@
* 2.0.
*/
-import React from 'react';
+import React, { useCallback } from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { FlyoutDetail } from '../components/flyout_detail/flyout_detail';
import { FlyoutProps } from '../components/flyout_detail';
+import { useLogExplorerCustomizationsContext } from '../hooks/use_log_explorer_customizations';
export const CustomFlyoutContent = ({
actions,
@@ -16,12 +17,28 @@ export const CustomFlyoutContent = ({
doc,
renderDefaultContent,
}: FlyoutProps) => {
+ const { flyout } = useLogExplorerCustomizationsContext();
+
+ const renderPreviousContent = useCallback(
+ () => (
+ <>
+ {/* Apply custom Log Explorer detail */}
+
+
+
+ >
+ ),
+ [actions, dataView, doc]
+ );
+
+ const content = flyout?.renderContent
+ ? flyout?.renderContent(renderPreviousContent, { doc })
+ : renderPreviousContent();
+
return (
{/* Apply custom Log Explorer detail */}
-
-
-
+ {content}
{/* Restore default content */}
{renderDefaultContent()}
diff --git a/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx b/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx
index 85d1284752977..628ff40babc22 100644
--- a/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx
+++ b/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx
@@ -14,6 +14,8 @@ import { LogExplorerProfileStateService } from '../state_machines/log_explorer_p
import { LogExplorerStateContainer } from '../components/log_explorer';
import { LogExplorerStartDeps } from '../types';
import { useKibanaContextForPluginProvider } from '../utils/use_kibana';
+import { LogExplorerCustomizations } from '../components/log_explorer/types';
+import { LogExplorerCustomizationsProvider } from '../hooks/use_log_explorer_customizations';
const LazyCustomDatasetFilters = dynamic(() => import('./custom_dataset_filters'));
const LazyCustomDatasetSelector = dynamic(() => import('./custom_dataset_selector'));
@@ -21,12 +23,18 @@ const LazyCustomFlyoutContent = dynamic(() => import('./custom_flyout_content'))
export interface CreateLogExplorerProfileCustomizationsDeps {
core: CoreStart;
+ customizations: LogExplorerCustomizations;
plugins: LogExplorerStartDeps;
state$?: BehaviorSubject;
}
export const createLogExplorerProfileCustomizations =
- ({ core, plugins, state$ }: CreateLogExplorerProfileCustomizationsDeps): CustomizationCallback =>
+ ({
+ core,
+ customizations: logExplorerCustomizations,
+ plugins,
+ state$,
+ }: CreateLogExplorerProfileCustomizationsDeps): CustomizationCallback =>
async ({ customizations, stateContainer }) => {
const { data, dataViews, discover } = plugins;
// Lazy load dependencies
@@ -127,7 +135,9 @@ export const createLogExplorerProfileCustomizations =
return (
-
+
+
+
);
},
diff --git a/x-pack/plugins/log_explorer/public/hooks/use_log_explorer_customizations.ts b/x-pack/plugins/log_explorer/public/hooks/use_log_explorer_customizations.ts
new file mode 100644
index 0000000000000..0557e17761cb4
--- /dev/null
+++ b/x-pack/plugins/log_explorer/public/hooks/use_log_explorer_customizations.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import createContainer from 'constate';
+import { LogExplorerCustomizations } from '../components/log_explorer/types';
+
+interface UseLogExplorerCustomizationsDeps {
+ value: LogExplorerCustomizations;
+}
+
+const useLogExplorerCustomizations = ({ value }: UseLogExplorerCustomizationsDeps) => value;
+
+export const [LogExplorerCustomizationsProvider, useLogExplorerCustomizationsContext] =
+ createContainer(useLogExplorerCustomizations);
diff --git a/x-pack/plugins/log_explorer/public/index.ts b/x-pack/plugins/log_explorer/public/index.ts
index 00750926517e6..1ca7f37aa4c9b 100644
--- a/x-pack/plugins/log_explorer/public/index.ts
+++ b/x-pack/plugins/log_explorer/public/index.ts
@@ -10,6 +10,10 @@ import type { LogExplorerConfig } from '../common/plugin_config';
import { LogExplorerPlugin } from './plugin';
export type { LogExplorerPluginSetup, LogExplorerPluginStart } from './types';
export type { LogExplorerStateContainer } from './components/log_explorer';
+export type {
+ LogExplorerCustomizations,
+ LogExplorerFlyoutContentProps,
+} from './components/log_explorer/types';
export function plugin(context: PluginInitializerContext) {
return new LogExplorerPlugin(context);
diff --git a/x-pack/plugins/logs_shared/kibana.jsonc b/x-pack/plugins/logs_shared/kibana.jsonc
index 051d1a452740e..b78503b140a71 100644
--- a/x-pack/plugins/logs_shared/kibana.jsonc
+++ b/x-pack/plugins/logs_shared/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/logs-shared-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-ux-logs-team",
"description": "Exposes the shared components and APIs to access and visualize logs.",
"plugin": {
"id": "logsShared",
diff --git a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx
index a4df6c50cbafd..8cf9b2da45c06 100644
--- a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx
+++ b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx
@@ -4,22 +4,25 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-import React from 'react';
+import React, { ComponentType } from 'react';
import { Optional } from '@kbn/utility-types';
import { dynamic } from '../../../common/dynamic';
-import type { LogAIAssistantProps } from './log_ai_assistant';
+import type { LogAIAssistantDeps } from './log_ai_assistant';
export const LogAIAssistant = dynamic(() => import('./log_ai_assistant'));
interface LogAIAssistantFactoryDeps {
- observabilityAIAssistant: LogAIAssistantProps['aiAssistant'];
+ observabilityAIAssistant: LogAIAssistantDeps['observabilityAIAssistant'];
}
-export function createLogAIAssistant({ observabilityAIAssistant }: LogAIAssistantFactoryDeps) {
- return ({
- aiAssistant = observabilityAIAssistant,
- ...props
- }: Optional) => (
-
+export type LogAIAssistantComponent = ComponentType<
+ Optional
+>;
+
+export function createLogAIAssistant({
+ observabilityAIAssistant: aiAssistant,
+}: LogAIAssistantFactoryDeps): LogAIAssistantComponent {
+ return ({ observabilityAIAssistant = aiAssistant, ...props }) => (
+
);
}
diff --git a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.mock.tsx b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.mock.tsx
new file mode 100644
index 0000000000000..9ece10dff8188
--- /dev/null
+++ b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.mock.tsx
@@ -0,0 +1,10 @@
+/*
+ * 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';
+
+export const createLogAIAssistantMock = () => jest.fn().mockReturnValue();
diff --git a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx
index bce36a6d28dc6..335a02ab3a05e 100644
--- a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx
+++ b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx
@@ -12,6 +12,8 @@ import {
type Message,
ObservabilityAIAssistantPluginStart,
MessageRole,
+ ObservabilityAIAssistantProvider,
+ useObservabilityAIAssistant,
} from '@kbn/observability-ai-assistant-plugin/public';
import { LogEntryField } from '../../../common';
import { explainLogMessageTitle, similarLogMessagesTitle } from './translations';
@@ -21,11 +23,16 @@ export interface LogAIAssistantDocument {
}
export interface LogAIAssistantProps {
- aiAssistant: ObservabilityAIAssistantPluginStart;
doc: LogAIAssistantDocument | undefined;
}
-export function LogAIAssistant({ aiAssistant, doc }: LogAIAssistantProps) {
+export interface LogAIAssistantDeps extends LogAIAssistantProps {
+ observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
+}
+
+export const LogAIAssistant = withProviders(({ doc }: LogAIAssistantProps) => {
+ const aiAssistant = useObservabilityAIAssistant();
+
const explainLogMessageMessages = useMemo(() => {
if (!doc) {
return undefined;
@@ -80,7 +87,20 @@ export function LogAIAssistant({ aiAssistant, doc }: LogAIAssistantProps) {
) : null}
);
-}
+});
// eslint-disable-next-line import/no-default-export
export default LogAIAssistant;
+
+function withProviders(Component: React.FunctionComponent) {
+ return function ComponentWithProviders({
+ observabilityAIAssistant,
+ ...props
+ }: LogAIAssistantDeps) {
+ return (
+
+
+
+ );
+ };
+}
diff --git a/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx b/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx
index 62634f2aeba13..b66e864c2a499 100644
--- a/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx
+++ b/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx
@@ -184,7 +184,7 @@ export const LogEntryFlyout = ({
>
-
+
diff --git a/x-pack/plugins/logs_shared/public/index.ts b/x-pack/plugins/logs_shared/public/index.ts
index 873d202b1af7d..58f22fe48bccb 100644
--- a/x-pack/plugins/logs_shared/public/index.ts
+++ b/x-pack/plugins/logs_shared/public/index.ts
@@ -37,6 +37,7 @@ export { useLogSummary, WithSummary } from './containers/logs/log_summary';
export { useLogEntryFlyout } from './components/logging/log_entry_flyout';
// Shared components
+export type { LogAIAssistantDocument } from './components/log_ai_assistant/log_ai_assistant';
export type {
LogEntryStreamItem,
LogEntryColumnWidths,
diff --git a/x-pack/plugins/logs_shared/public/mocks.tsx b/x-pack/plugins/logs_shared/public/mocks.tsx
index 963480d8fd90f..a9b0ebd6a6aa3 100644
--- a/x-pack/plugins/logs_shared/public/mocks.tsx
+++ b/x-pack/plugins/logs_shared/public/mocks.tsx
@@ -5,11 +5,13 @@
* 2.0.
*/
+import { createLogAIAssistantMock } from './components/log_ai_assistant/log_ai_assistant.mock';
import { createLogViewsServiceStartMock } from './services/log_views/log_views_service.mock';
import { LogsSharedClientStartExports } from './types';
export const createLogsSharedPluginStartMock = (): jest.Mocked => ({
logViews: createLogViewsServiceStartMock(),
+ LogAIAssistant: createLogAIAssistantMock(),
});
export const _ensureTypeCompatibility = (): LogsSharedClientStartExports =>
diff --git a/x-pack/plugins/logs_shared/public/types.ts b/x-pack/plugins/logs_shared/public/types.ts
index e67f83e4becc0..c0379c6fc21fb 100644
--- a/x-pack/plugins/logs_shared/public/types.ts
+++ b/x-pack/plugins/logs_shared/public/types.ts
@@ -17,6 +17,7 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
+import { LogAIAssistantComponent } from './components/log_ai_assistant';
// import type { OsqueryPluginStart } from '../../osquery/public';
import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views';
@@ -27,6 +28,7 @@ export interface LogsSharedClientSetupExports {
export interface LogsSharedClientStartExports {
logViews: LogViewsServiceStart;
+ LogAIAssistant: LogAIAssistantComponent;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
diff --git a/x-pack/plugins/metrics_data_access/kibana.jsonc b/x-pack/plugins/metrics_data_access/kibana.jsonc
index 6842ec7d4a724..10ddf6c04e21e 100644
--- a/x-pack/plugins/metrics_data_access/kibana.jsonc
+++ b/x-pack/plugins/metrics_data_access/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/metrics-data-access-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-knowledge-team",
"description": "Exposes utilities for accessing metrics data",
"plugin": {
"id": "metricsDataAccess",
diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/utils.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/utils.ts
index e060017bc7fa0..88e66aab91933 100644
--- a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/utils.ts
+++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/utils.ts
@@ -186,6 +186,8 @@ export async function getVisTypeFactory(lens: LensPublicStart) {
export async function isCompatibleVisualizationType(chartInfo: ChartInfo) {
return (
chartInfo.visualizationType === COMPATIBLE_VISUALIZATION &&
+ // @ts-expect-error esql is missing in the type
+ chartInfo.query.esql === undefined &&
chartInfo.layers.some((l) => l.layerType === layerTypes.DATA && l.dataView !== undefined)
);
}
diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts
index ba08ab5066701..e55f2dfc46d83 100644
--- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts
+++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts
@@ -23,7 +23,9 @@ export const setupCapabilitiesSwitcher = (
enabledFeatures: MlFeatures,
logger: Logger
) => {
- coreSetup.capabilities.registerSwitcher(getSwitcher(license$, logger, enabledFeatures));
+ coreSetup.capabilities.registerSwitcher(getSwitcher(license$, logger, enabledFeatures), {
+ capabilityPath: 'ml.*',
+ });
};
function getSwitcher(
diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts
index d148fc8f148d9..c268cd3383211 100644
--- a/x-pack/plugins/ml/server/plugin.ts
+++ b/x-pack/plugins/ml/server/plugin.ts
@@ -195,7 +195,9 @@ export class MlServerPlugin
if (this.capabilities === null) {
return null;
}
- const capabilities = await this.capabilities.resolveCapabilities(request);
+ const capabilities = await this.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'ml.*',
+ });
return capabilities.ml as MlCapabilities;
};
diff --git a/x-pack/plugins/monitoring/kibana.jsonc b/x-pack/plugins/monitoring/kibana.jsonc
index 8da632c4b7d6f..4992da373a73d 100644
--- a/x-pack/plugins/monitoring/kibana.jsonc
+++ b/x-pack/plugins/monitoring/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/monitoring-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "monitoring",
"server": true,
diff --git a/x-pack/plugins/monitoring_collection/kibana.jsonc b/x-pack/plugins/monitoring_collection/kibana.jsonc
index 1c84d9ee4f84c..246dcce086a07 100644
--- a/x-pack/plugins/monitoring_collection/kibana.jsonc
+++ b/x-pack/plugins/monitoring_collection/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/monitoring-collection-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "monitoringCollection",
"server": true,
diff --git a/x-pack/plugins/observability/kibana.jsonc b/x-pack/plugins/observability/kibana.jsonc
index 86db25972fb1b..c03e0b499d424 100644
--- a/x-pack/plugins/observability/kibana.jsonc
+++ b/x-pack/plugins/observability/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/observability-plugin",
- "owner": "@elastic/actionable-observability",
+ "owner": "@elastic/obs-ux-management-team",
"plugin": {
"id": "observability",
"server": true,
diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx
index c835f636eaa2d..d0871dbfb75b2 100644
--- a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx
+++ b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/custom_equation_editor.tsx
@@ -167,7 +167,6 @@ export function CustomEquationEditor({
{ defaultMessage: 'Equation and threshold' }
)}
error={[errors.equation]}
- isInvalid={errors.equation != null}
>
<>
@@ -182,6 +181,7 @@ export function CustomEquationEditor({
onClick={() => {
setCustomEqPopoverOpen(true);
}}
+ isInvalid={errors.equation != null}
/>
>
diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx
index 80a379134806c..891c0ceaabbb5 100644
--- a/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx
+++ b/x-pack/plugins/observability/public/components/custom_threshold/components/custom_equation/metric_row_with_agg.tsx
@@ -38,6 +38,11 @@ interface MetricRowWithAggProps extends MetricRowBaseProps {
fields: NormalizedFields;
}
+const DEFAULT_COUNT_FILTER_TITLE = i18n.translate(
+ 'xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.defaultCountFilterTitle',
+ { defaultMessage: 'all documents' }
+);
+
export function MetricRowWithAgg({
name,
aggType = Aggregators.COUNT,
@@ -121,17 +126,19 @@ export function MetricRowWithAgg({
'xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.aggregationLabel',
{ defaultMessage: 'Aggregation {name}', values: { name } }
)}
- isInvalid={aggType !== Aggregators.COUNT && !field}
>
{
setAggTypePopoverOpen(true);
}}
+ isInvalid={aggType !== Aggregators.COUNT && !field}
/>
}
@@ -160,7 +167,6 @@ export function MetricRowWithAgg({
'xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.aggregationType',
{ defaultMessage: 'Aggregation type' }
)}
- isInvalid={isAggInvalid}
>
@@ -201,7 +208,6 @@ export function MetricRowWithAgg({
'xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.fieldLabel',
{ defaultMessage: 'Field name' }
)}
- isInvalid={isFieldInvalid}
>
+{
public readonly type = SLO_EMBEDDABLE;
constructor(
@@ -42,6 +45,15 @@ export class SloOverviewEmbeddableFactoryDefinition implements EmbeddableFactory
}
}
+ public getPanelPlacementSettings: IProvidesPanelPlacementSettings<
+ SloEmbeddableInput,
+ unknown
+ >['getPanelPlacementSettings'] = () => {
+ const width = 8;
+ const height = 7;
+ return { width, height, strategy: 'placeAtTop' };
+ };
+
public async create(initialInput: SloEmbeddableInput, parent?: IContainer) {
try {
const [{ uiSettings, application, http, i18n: i18nService }] = await this.getStartServices();
diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts
index 31cf30ca03a1d..2d234b57ab8ed 100644
--- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts
+++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts
@@ -49,6 +49,7 @@ type SloIdAndInstanceId = [string, string];
interface Params {
sloIdsAndInstanceIds: SloIdAndInstanceId[];
+ shouldRefetch?: boolean;
}
export interface UseFetchActiveAlerts {
@@ -70,9 +71,13 @@ interface FindApiResponse {
};
}
+const LONG_REFETCH_INTERVAL = 1000 * 60; // 1 minute
const EMPTY_ACTIVE_ALERTS_MAP = new ActiveAlerts();
-export function useFetchActiveAlerts({ sloIdsAndInstanceIds = [] }: Params): UseFetchActiveAlerts {
+export function useFetchActiveAlerts({
+ sloIdsAndInstanceIds = [],
+ shouldRefetch = false,
+}: Params): UseFetchActiveAlerts {
const { http } = useKibana().services;
const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({
@@ -136,6 +141,7 @@ export function useFetchActiveAlerts({ sloIdsAndInstanceIds = [] }: Params): Use
}
},
refetchOnWindowFocus: false,
+ refetchInterval: shouldRefetch ? LONG_REFETCH_INTERVAL : undefined,
enabled: Boolean(sloIdsAndInstanceIds.length),
});
diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx
index d70a4cbbfcbe3..e05c9c7403dd6 100644
--- a/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_details/components/slo_details.tsx
@@ -42,6 +42,7 @@ export function SloDetails({ slo, isAutoRefreshing }: Props) {
const { search } = useLocation();
const { data: activeAlerts } = useFetchActiveAlerts({
sloIdsAndInstanceIds: [[slo.id, slo.instanceId ?? ALL_VALUE]],
+ shouldRefetch: isAutoRefreshing,
});
const { isLoading: historicalSummaryLoading, data: historicalSummaries = [] } =
useFetchHistoricalSummary({
diff --git a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx
index 21972da276691..8d4d45a08d709 100644
--- a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx
@@ -5,8 +5,7 @@
* 2.0.
*/
-import { fireEvent, waitFor } from '@testing-library/dom';
-import { cleanup } from '@testing-library/react';
+import { fireEvent, waitFor, cleanup } from '@testing-library/react';
import { createBrowserHistory } from 'history';
import React from 'react';
import Router from 'react-router-dom';
diff --git a/x-pack/plugins/observability/server/plugin.ts b/x-pack/plugins/observability/server/plugin.ts
index 4e2c7a57ead13..17476d335f48f 100644
--- a/x-pack/plugins/observability/server/plugin.ts
+++ b/x-pack/plugins/observability/server/plugin.ts
@@ -29,6 +29,7 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
import {
ApmRuleType,
ES_QUERY_ID,
+ METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID,
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
} from '@kbn/rule-data-utils';
import { ObservabilityConfig } from '.';
@@ -81,6 +82,7 @@ const o11yRuleTypes = [
SLO_BURN_RATE_RULE_TYPE_ID,
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
ES_QUERY_ID,
+ METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID,
...Object.values(ApmRuleType),
];
diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json
index d0d4114fe4612..4e2f8ef70482c 100644
--- a/x-pack/plugins/observability/tsconfig.json
+++ b/x-pack/plugins/observability/tsconfig.json
@@ -93,7 +93,8 @@
"@kbn/react-kibana-context-theme",
"@kbn/shared-ux-link-redirect-app",
"@kbn/core-chrome-browser",
- "@kbn/serverless"
+ "@kbn/serverless",
+ "@kbn/dashboard-plugin"
],
"exclude": [
"target/**/*"
diff --git a/x-pack/plugins/observability_ai_assistant/kibana.jsonc b/x-pack/plugins/observability_ai_assistant/kibana.jsonc
index 3af934a10fcfa..291c7e658de18 100644
--- a/x-pack/plugins/observability_ai_assistant/kibana.jsonc
+++ b/x-pack/plugins/observability_ai_assistant/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/observability-ai-assistant-plugin",
- "owner": "@elastic/obs-ai-assistant",
+ "owner": "@elastic/obs-knowledge-team",
"plugin": {
"id": "observabilityAIAssistant",
"server": true,
diff --git a/x-pack/plugins/observability_log_explorer/kibana.jsonc b/x-pack/plugins/observability_log_explorer/kibana.jsonc
index 7ac940de86dd4..72d03b82d3386 100644
--- a/x-pack/plugins/observability_log_explorer/kibana.jsonc
+++ b/x-pack/plugins/observability_log_explorer/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/observability-log-explorer-plugin",
- "owner": "@elastic/infra-monitoring-ui",
+ "owner": "@elastic/obs-ux-logs-team",
"description": "This plugin exposes and registers observability log consumption features.",
"plugin": {
"id": "observabilityLogExplorer",
@@ -15,6 +15,7 @@
"data",
"discover",
"logExplorer",
+ "logsShared",
"observabilityShared",
"share",
"kibanaUtils",
diff --git a/x-pack/plugins/observability_log_explorer/public/log_explorer_customizations/flyout_content.tsx b/x-pack/plugins/observability_log_explorer/public/log_explorer_customizations/flyout_content.tsx
new file mode 100644
index 0000000000000..53d34a71a7237
--- /dev/null
+++ b/x-pack/plugins/observability_log_explorer/public/log_explorer_customizations/flyout_content.tsx
@@ -0,0 +1,51 @@
+/*
+ * 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 { EuiFlexItem } from '@elastic/eui';
+import {
+ LogExplorerCustomizations,
+ LogExplorerFlyoutContentProps,
+} from '@kbn/log-explorer-plugin/public';
+import type { LogAIAssistantDocument } from '@kbn/logs-shared-plugin/public';
+import React, { useMemo } from 'react';
+import { useKibanaContextForPlugin } from '../utils/use_kibana';
+
+const ObservabilityLogAIAssistant = ({ doc }: LogExplorerFlyoutContentProps) => {
+ const { services } = useKibanaContextForPlugin();
+ const { LogAIAssistant } = services.logsShared;
+
+ const mappedDoc = useMemo(() => mapDocToAIAssistantFormat(doc), [doc]);
+
+ return ;
+};
+
+export const renderFlyoutContent: Required['flyout']['renderContent'] = (
+ renderPreviousContent,
+ props
+) => {
+ return (
+ <>
+ {renderPreviousContent()}
+
+
+
+ >
+ );
+};
+
+/**
+ * Utils
+ */
+const mapDocToAIAssistantFormat = (doc: LogExplorerFlyoutContentProps['doc']) => {
+ if (!doc) return;
+
+ return {
+ fields: Object.entries(doc.flattened).map(([field, value]) => ({
+ field,
+ value,
+ })) as LogAIAssistantDocument['fields'],
+ };
+};
diff --git a/x-pack/plugins/observability_log_explorer/public/log_explorer_customizations/index.ts b/x-pack/plugins/observability_log_explorer/public/log_explorer_customizations/index.ts
new file mode 100644
index 0000000000000..a86b47e92cf01
--- /dev/null
+++ b/x-pack/plugins/observability_log_explorer/public/log_explorer_customizations/index.ts
@@ -0,0 +1,15 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { LogExplorerCustomizations } from '@kbn/log-explorer-plugin/public';
+import { renderFlyoutContent } from './flyout_content';
+
+export const createLogExplorerCustomizations = (): LogExplorerCustomizations => ({
+ flyout: {
+ renderContent: renderFlyoutContent,
+ },
+});
diff --git a/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx b/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx
index aece8474f0390..e17f92a46c23b 100644
--- a/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx
+++ b/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx
@@ -6,7 +6,7 @@
*/
import { CoreStart } from '@kbn/core/public';
-import React, { useState } from 'react';
+import React, { useMemo, useState } from 'react';
import { BehaviorSubject } from 'rxjs';
import { LogExplorerTopNavMenu } from '../../components/log_explorer_top_nav_menu';
import { ObservabilityLogExplorerPageTemplate } from '../../components/page_template';
@@ -14,6 +14,7 @@ import { noBreadcrumbs, useBreadcrumbs } from '../../utils/breadcrumbs';
import { useKibanaContextForPlugin } from '../../utils/use_kibana';
import { ObservabilityLogExplorerAppMountParameters } from '../../types';
import { LazyOriginInterpreter } from '../../state_machines/origin_interpreter/src/lazy_component';
+import { createLogExplorerCustomizations } from '../../log_explorer_customizations';
export interface ObservablityLogExplorerMainRouteProps {
appParams: ObservabilityLogExplorerAppMountParameters;
core: CoreStart;
@@ -31,6 +32,8 @@ export const ObservablityLogExplorerMainRoute = ({
const [state$] = useState(() => new BehaviorSubject({}));
+ const customizations = useMemo(() => createLogExplorerCustomizations(), []);
+
return (
<>
-
+
>
);
diff --git a/x-pack/plugins/observability_log_explorer/public/types.ts b/x-pack/plugins/observability_log_explorer/public/types.ts
index 82045faea76e8..8b315ad206ce4 100644
--- a/x-pack/plugins/observability_log_explorer/public/types.ts
+++ b/x-pack/plugins/observability_log_explorer/public/types.ts
@@ -12,6 +12,7 @@ import { ObservabilitySharedPluginStart } from '@kbn/observability-shared-plugin
import { ServerlessPluginStart } from '@kbn/serverless/public';
import { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public';
import { AppMountParameters, ScopedHistory } from '@kbn/core/public';
+import { LogsSharedClientStartExports } from '@kbn/logs-shared-plugin/public';
import {
ObservabilityLogExplorerLocators,
ObservabilityLogExplorerLocationState,
@@ -33,6 +34,7 @@ export interface ObservabilityLogExplorerStartDeps {
data: DataPublicPluginStart;
discover: DiscoverStart;
logExplorer: LogExplorerPluginStart;
+ logsShared: LogsSharedClientStartExports;
observabilityShared: ObservabilitySharedPluginStart;
serverless?: ServerlessPluginStart;
share: SharePluginStart;
diff --git a/x-pack/plugins/observability_log_explorer/tsconfig.json b/x-pack/plugins/observability_log_explorer/tsconfig.json
index 7266e097dae62..109b54b929ec7 100644
--- a/x-pack/plugins/observability_log_explorer/tsconfig.json
+++ b/x-pack/plugins/observability_log_explorer/tsconfig.json
@@ -33,7 +33,8 @@
"@kbn/core-mount-utils-browser-internal",
"@kbn/xstate-utils",
"@kbn/shared-ux-utility",
- "@kbn/ui-theme"
+ "@kbn/ui-theme",
+ "@kbn/logs-shared-plugin"
],
"exclude": [
"target/**/*"
diff --git a/x-pack/plugins/observability_onboarding/kibana.jsonc b/x-pack/plugins/observability_onboarding/kibana.jsonc
index 5c1615c3a95ba..c2b89c8c9b4fa 100644
--- a/x-pack/plugins/observability_onboarding/kibana.jsonc
+++ b/x-pack/plugins/observability_onboarding/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/observability-onboarding-plugin",
- "owner": "@elastic/apm-ui",
+ "owner": "@elastic/obs-ux-logs-team",
"plugin": {
"id": "observabilityOnboarding",
"server": true,
diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts
index 15fb98540e438..cb4ce27a69031 100644
--- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts
+++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts
@@ -63,6 +63,7 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve
cy.getBySel('globalLoadingIndicator').should('not.exist');
closeDateTabIfVisible();
cy.getBySel('edit-rule-actions-tab').click();
+ cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.contains('Response actions are run on each rule execution.');
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();
cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => {
diff --git a/x-pack/plugins/osquery/cypress/tasks/response_actions.ts b/x-pack/plugins/osquery/cypress/tasks/response_actions.ts
index 3f59ebca9f560..d686392431b7a 100644
--- a/x-pack/plugins/osquery/cypress/tasks/response_actions.ts
+++ b/x-pack/plugins/osquery/cypress/tasks/response_actions.ts
@@ -45,6 +45,7 @@ export const checkOsqueryResponseActionsPermissions = (enabled: boolean) => {
cy.getBySel('globalLoadingIndicator').should('not.exist');
closeDateTabIfVisible();
cy.getBySel('edit-rule-actions-tab').click();
+ cy.getBySel('globalLoadingIndicator').should('not.exist');
cy.contains('Response actions are run on each rule execution.');
cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click();
if (enabled) {
diff --git a/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts b/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts
index 586ebe3716a96..fff242db7475c 100644
--- a/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts
+++ b/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts
@@ -45,7 +45,9 @@ export const createLiveQueryRoute = (router: IRouter, osqueryContext: OsqueryApp
const {
osquery: { writeLiveQueries, runSavedQueries },
- } = await coreStartServices.capabilities.resolveCapabilities(request);
+ } = await coreStartServices.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'osquery.*',
+ });
const isInvalid = !(
writeLiveQueries ||
diff --git a/x-pack/plugins/profiling/kibana.jsonc b/x-pack/plugins/profiling/kibana.jsonc
index 104196bababc9..296b4e40bb822 100644
--- a/x-pack/plugins/profiling/kibana.jsonc
+++ b/x-pack/plugins/profiling/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/profiling-plugin",
- "owner": "@elastic/profiling-ui",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "profiling",
"server": true,
diff --git a/x-pack/plugins/profiling_data_access/kibana.jsonc b/x-pack/plugins/profiling_data_access/kibana.jsonc
index a6bcd9f7ecff4..a2c3fb4cb267b 100644
--- a/x-pack/plugins/profiling_data_access/kibana.jsonc
+++ b/x-pack/plugins/profiling_data_access/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/profiling-data-access-plugin",
- "owner": "@elastic/profiling-ui",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "profilingDataAccess",
"server": true,
diff --git a/x-pack/plugins/rule_registry/kibana.jsonc b/x-pack/plugins/rule_registry/kibana.jsonc
index d5c867247e811..28612bff2b9cc 100644
--- a/x-pack/plugins/rule_registry/kibana.jsonc
+++ b/x-pack/plugins/rule_registry/kibana.jsonc
@@ -3,7 +3,7 @@
"id": "@kbn/rule-registry-plugin",
"owner": [
"@elastic/response-ops",
- "@elastic/actionable-observability"
+ "@elastic/obs-ux-management-team"
],
"plugin": {
"id": "ruleRegistry",
diff --git a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts
index 3cee2adf03f5c..398ff6a3c425b 100644
--- a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts
+++ b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts
@@ -165,6 +165,7 @@ describe('AnonymousAccessService', () => {
expect.objectContaining({ headers: {} }),
{
useDefaultCapabilities: true,
+ capabilityPath: '*',
}
);
});
@@ -202,6 +203,7 @@ describe('AnonymousAccessService', () => {
expect.objectContaining({ headers: {} }),
{
useDefaultCapabilities: true,
+ capabilityPath: '*',
}
);
});
@@ -225,7 +227,7 @@ describe('AnonymousAccessService', () => {
expect(startParams.capabilities.resolveCapabilities).toHaveBeenCalledTimes(1);
expect(startParams.capabilities.resolveCapabilities).toHaveBeenCalledWith(
expect.objectContaining({ headers: { authorization: 'Basic dXNlcjpwYXNzd29yZA==' } }),
- { useDefaultCapabilities: false }
+ { useDefaultCapabilities: false, capabilityPath: '*' }
);
});
@@ -245,7 +247,7 @@ describe('AnonymousAccessService', () => {
expect(startParams.capabilities.resolveCapabilities).toHaveBeenCalledTimes(1);
expect(startParams.capabilities.resolveCapabilities).toHaveBeenCalledWith(
expect.objectContaining({ headers: { authorization: 'Basic dXNlcjpwYXNzd29yZA==' } }),
- { useDefaultCapabilities: false }
+ { useDefaultCapabilities: false, capabilityPath: '*' }
);
});
});
diff --git a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts
index 8641d242d56eb..ad0a9b79fff46 100644
--- a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts
+++ b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts
@@ -121,6 +121,7 @@ export class AnonymousAccessService {
try {
return await capabilities.resolveCapabilities(fakeAnonymousRequest, {
+ capabilityPath: '*',
useDefaultCapabilities,
});
} catch (err) {
diff --git a/x-pack/plugins/security/server/authorization/authorization_service.test.ts b/x-pack/plugins/security/server/authorization/authorization_service.test.ts
index 0d1009bdd4b9e..a052d67532480 100644
--- a/x-pack/plugins/security/server/authorization/authorization_service.test.ts
+++ b/x-pack/plugins/security/server/authorization/authorization_service.test.ts
@@ -116,7 +116,9 @@ it(`#setup returns exposed services`, () => {
expect(authorizationModeFactory).toHaveBeenCalledWith(mockLicense);
expect(mockCoreSetup.capabilities.registerSwitcher).toHaveBeenCalledTimes(1);
- expect(mockCoreSetup.capabilities.registerSwitcher).toHaveBeenCalledWith(expect.any(Function));
+ expect(mockCoreSetup.capabilities.registerSwitcher).toHaveBeenCalledWith(expect.any(Function), {
+ capabilityPath: '*',
+ });
});
describe('#start', () => {
diff --git a/x-pack/plugins/security/server/authorization/authorization_service.tsx b/x-pack/plugins/security/server/authorization/authorization_service.tsx
index a2b32a0a6b13e..10bee6309438f 100644
--- a/x-pack/plugins/security/server/authorization/authorization_service.tsx
+++ b/x-pack/plugins/security/server/authorization/authorization_service.tsx
@@ -64,8 +64,11 @@ interface AuthorizationServiceSetupParams {
loggers: LoggerFactory;
features: FeaturesPluginSetup;
kibanaIndexName: string;
+
getSpacesService(): SpacesService | undefined;
+
getCurrentUser(request: KibanaRequest): AuthenticatedUser | null;
+
customBranding: CustomBrandingSetup;
}
@@ -174,6 +177,9 @@ export class AuthorizationService {
}
return await disableUICapabilities.usingPrivileges(uiCapabilities);
+ },
+ {
+ capabilityPath: '*',
}
);
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts
index 22c507804e1d8..b52f61febbafb 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts
@@ -4,9 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import type { ErrorSchema } from './error_schema_legacy';
+import type { ErrorSchema } from './error_schema.gen';
export const getErrorSchemaMock = (
id: string = '819eded6-e9c8-445b-a647-519aea39e063'
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts
index 0d243fc201fb9..f5c8440a07148 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts
@@ -8,12 +8,8 @@
export * from './alerts';
export * from './rule_response_actions';
export * from './rule_schema';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-export * from './error_schema_legacy';
-export * from './pagination';
+export * from './error_schema.gen';
+export * from './pagination.gen';
export * from './schemas';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-export * from './sorting_legacy';
+export * from './sorting.gen';
export * from './warning_schema.gen';
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.gen.ts
new file mode 100644
index 0000000000000..0a7336b8f78c3
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.gen.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; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { z } from 'zod';
+
+/*
+ * NOTICE: Do not edit this file manually.
+ * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
+ */
+
+/**
+ * Page number
+ */
+export type Page = z.infer;
+export const Page = z.number().int().min(1);
+
+/**
+ * Number of items per page
+ */
+export type PerPage = z.infer;
+export const PerPage = z.number().int().min(0);
+
+export type PaginationResult = z.infer;
+export const PaginationResult = z.object({
+ page: Page,
+ per_page: PerPage,
+ /**
+ * Total number of items
+ */
+ total: z.number().int().min(0),
+});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.schema.yaml
new file mode 100644
index 0000000000000..3afccce86e329
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.schema.yaml
@@ -0,0 +1,31 @@
+openapi: 3.0.0
+info:
+ title: Pagination Schema
+ version: 'not applicable'
+paths: {}
+components:
+ x-codegen-enabled: true
+ schemas:
+ Page:
+ type: integer
+ minimum: 1
+ description: Page number
+ PerPage:
+ type: integer
+ minimum: 0
+ description: Number of items per page
+ PaginationResult:
+ type: object
+ properties:
+ page:
+ $ref: '#/components/schemas/Page'
+ per_page:
+ $ref: '#/components/schemas/PerPage'
+ total:
+ type: integer
+ minimum: 0
+ description: Total number of items
+ required:
+ - page
+ - per_page
+ - total
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.ts
deleted file mode 100644
index bed2cade86df4..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/pagination.ts
+++ /dev/null
@@ -1,28 +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 * as t from 'io-ts';
-import { PositiveInteger, PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types';
-
-export type Page = t.TypeOf;
-export const Page = PositiveIntegerGreaterThanZero;
-
-export type PageOrUndefined = t.TypeOf;
-export const PageOrUndefined = t.union([Page, t.undefined]);
-
-export type PerPage = t.TypeOf;
-export const PerPage = PositiveInteger;
-
-export type PerPageOrUndefined = t.TypeOf;
-export const PerPageOrUndefined = t.union([PerPage, t.undefined]);
-
-export type PaginationResult = t.TypeOf;
-export const PaginationResult = t.type({
- page: Page,
- per_page: PerPage,
- total: PositiveInteger,
-});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts
index ccaf290dc5d33..e9956d88eb45a 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts
@@ -5,7 +5,4 @@
* 2.0.
*/
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-export { RESPONSE_ACTION_TYPES, SUPPORTED_RESPONSE_ACTION_TYPES } from './response_actions_legacy';
export * from './response_actions.gen';
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts
index 0d62dfd9c21f3..79ad21ddfb009 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts
@@ -367,26 +367,38 @@ export const RuleActionFrequency = z.object({
throttle: RuleActionThrottle.nullable(),
});
+export type RuleActionAlertsFilter = z.infer;
+export const RuleActionAlertsFilter = z.object({}).catchall(z.unknown());
+
+/**
+ * Object containing the allowed connector fields, which varies according to the connector type.
+ */
+export type RuleActionParams = z.infer;
+export const RuleActionParams = z.object({}).catchall(z.unknown());
+
+/**
+ * Optionally groups actions by use cases. Use `default` for alert notifications.
+ */
+export type RuleActionGroup = z.infer;
+export const RuleActionGroup = z.string();
+
+/**
+ * The connector ID.
+ */
+export type RuleActionId = z.infer;
+export const RuleActionId = z.string();
+
export type RuleAction = z.infer;
export const RuleAction = z.object({
/**
* The action type used for sending notifications.
*/
action_type_id: z.string(),
- /**
- * Optionally groups actions by use cases. Use `default` for alert notifications.
- */
- group: z.string(),
- /**
- * The connector ID.
- */
- id: z.string(),
- /**
- * Object containing the allowed connector fields, which varies according to the connector type.
- */
- params: z.object({}).catchall(z.unknown()),
+ group: RuleActionGroup,
+ id: RuleActionId,
+ params: RuleActionParams,
uuid: NonEmptyString.optional(),
- alerts_filter: z.object({}).catchall(z.unknown()).optional(),
+ alerts_filter: RuleActionAlertsFilter.optional(),
frequency: RuleActionFrequency.optional(),
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml
index 921f9350550b6..ad2bfaf76c4c0 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml
@@ -397,6 +397,23 @@ components:
- notifyWhen
- throttle
+ RuleActionAlertsFilter:
+ type: object
+ additionalProperties: true
+
+ RuleActionParams:
+ type: object
+ description: Object containing the allowed connector fields, which varies according to the connector type.
+ additionalProperties: true
+
+ RuleActionGroup:
+ type: string
+ description: Optionally groups actions by use cases. Use `default` for alert notifications.
+
+ RuleActionId:
+ type: string
+ description: The connector ID.
+
RuleAction:
type: object
properties:
@@ -404,20 +421,15 @@ components:
type: string
description: The action type used for sending notifications.
group:
- type: string
- description: Optionally groups actions by use cases. Use `default` for alert notifications.
+ $ref: '#/components/schemas/RuleActionGroup'
id:
- type: string
- description: The connector ID.
+ $ref: '#/components/schemas/RuleActionId'
params:
- type: object
- description: Object containing the allowed connector fields, which varies according to the connector type.
- additionalProperties: true
+ $ref: '#/components/schemas/RuleActionParams'
uuid:
$ref: '#/components/schemas/NonEmptyString'
alerts_filter:
- type: object
- additionalProperties: true
+ $ref: '#/components/schemas/RuleActionAlertsFilter'
frequency:
$ref: '#/components/schemas/RuleActionFrequency'
required:
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts
index abbfa4903ea31..062c913354404 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts
@@ -25,7 +25,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", and 52 more"`
+ );
});
test('strips any unknown values', () => {
@@ -46,7 +48,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"name: Required, description: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", and 52 more"`
+ );
});
test('[rule_id, description] does not validate', () => {
@@ -57,7 +61,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 44 more"`
+ );
});
test('[rule_id, description, from] does not validate', () => {
@@ -69,7 +75,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 44 more"`
+ );
});
test('[rule_id, description, from, to] does not validate', () => {
@@ -82,7 +90,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"name: Required, risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, and 44 more"`
+ );
});
test('[rule_id, description, from, to, name] does not validate', () => {
@@ -96,7 +106,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"risk_score: Required, severity: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", and 36 more"`
+ );
});
test('[rule_id, description, from, to, name, severity] does not validate', () => {
@@ -111,7 +123,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 28 more"`
+ );
});
test('[rule_id, description, from, to, name, severity, type] does not validate', () => {
@@ -127,7 +141,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 27 more"`
+ );
});
test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => {
@@ -144,7 +160,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 27 more"`
+ );
});
test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => {
@@ -162,7 +180,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", query: Required, language: Invalid literal value, expected \\"eql\\", risk_score: Required, and 27 more"`
+ );
});
test('[rule_id, description, from, to, name, severity, type, query, index, interval] does validate', () => {
@@ -202,7 +222,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"risk_score: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", risk_score: Required, risk_score: Required, and 22 more"`
+ );
});
test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score] does validate', () => {
@@ -368,7 +390,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"references.0: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", references.0: Expected string, received number, references.0: Expected string, received number, and 22 more"`
+ );
});
test('indexes cannot be numbers', () => {
@@ -379,7 +403,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", index.0: Expected string, received number, index.0: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", and 20 more"`
+ );
});
test('saved_query type can have filters with it', () => {
@@ -401,7 +427,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", filters: Expected array, received string, filters: Expected array, received string, type: Invalid literal value, expected \\"saved_query\\", and 20 more"`
+ );
});
test('language validates with kuery', () => {
@@ -434,7 +462,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up', type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 19 more"`
+ );
});
test('max_signals cannot be negative', () => {
@@ -493,7 +523,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"tags.0: Expected string, received number, tags.1: Expected string, received number, tags.2: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", and 38 more"`
+ );
});
test('You cannot send in an array of threat that are missing "framework"', () => {
@@ -519,7 +551,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"threat.0.framework: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", threat.0.framework: Required, threat.0.framework: Required, and 22 more"`
+ );
});
test('You cannot send in an array of threat that are missing "tactic"', () => {
@@ -541,7 +575,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"threat.0.tactic: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", threat.0.tactic: Required, threat.0.tactic: Required, and 22 more"`
+ );
});
test('You can send in an array of threat that are missing "technique"', () => {
@@ -583,7 +619,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"false_positives.0: Expected string, received number, false_positives.1: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", false_positives.0: Expected string, received number, and 30 more"`
+ );
});
test('You cannot set the risk_score to 101', () => {
@@ -655,7 +693,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"meta: Expected object, received string, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", meta: Expected object, received string, meta: Expected object, received string, and 22 more"`
+ );
});
test('You can omit the query string when filters are present', () => {
@@ -690,7 +730,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', and 22 more"`
+ );
});
test('You cannot send in an array of actions that are missing "group"', () => {
@@ -701,7 +743,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.group: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.group: Required, actions.0.group: Required, and 22 more"`
+ );
});
test('You cannot send in an array of actions that are missing "id"', () => {
@@ -712,7 +756,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.id: Required, actions.0.id: Required, and 22 more"`
+ );
});
test('You cannot send in an array of actions that are missing "action_type_id"', () => {
@@ -723,7 +769,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.action_type_id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.action_type_id: Required, actions.0.action_type_id: Required, and 22 more"`
+ );
});
test('You cannot send in an array of actions that are missing "params"', () => {
@@ -734,7 +782,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.params: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.params: Required, actions.0.params: Required, and 22 more"`
+ );
});
test('You cannot send in an array of actions that are including "actionTypeId"', () => {
@@ -752,7 +802,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.action_type_id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.action_type_id: Required, actions.0.action_type_id: Required, and 22 more"`
+ );
});
describe('note', () => {
@@ -788,7 +840,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"note: Expected string, received object, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", note: Expected string, received object, note: Expected string, received object, and 22 more"`
+ );
});
test('empty name is not valid', () => {
@@ -872,7 +926,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", saved_id: Required, type: Invalid literal value, expected \\"threshold\\", and 14 more"`
+ );
});
test('threshold is required when type is threshold and will not validate without it', () => {
@@ -880,7 +936,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 14 more"`
+ );
});
test('threshold rules fail validation if threshold is not greater than 0', () => {
@@ -958,7 +1016,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"exceptions_list.0.list_id: Required, exceptions_list.0.type: Required, exceptions_list.0.namespace_type: Invalid enum value. Expected 'agnostic' | 'single', received 'not a namespace type', type: Invalid literal value, expected \\"eql\\", query: Required, and 43 more"`
+ );
});
test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => {
@@ -999,7 +1059,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 14 more"`
+ );
});
test('fails validation when threat_mapping is an empty array', () => {
@@ -1068,7 +1130,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", data_view_id: Expected string, received number, data_view_id: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", and 20 more"`
+ );
});
test('it should validate a type of "query" with "data_view_id" defined', () => {
@@ -1131,7 +1195,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"investigation_fields.field_names: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", investigation_fields.field_names: Required, investigation_fields.field_names: Required, and 22 more"`
+ );
});
test('You can send in investigation_fields', () => {
@@ -1166,7 +1232,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"investigation_fields.field_names.0: Expected string, received number, investigation_fields.field_names.1: Expected string, received number, investigation_fields.field_names.2: Expected string, received number, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", and 38 more"`
+ );
});
test('You cannot send in investigation_fields without specifying fields', () => {
@@ -1177,7 +1245,9 @@ describe('rules schema', () => {
const result = RuleCreateProps.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"investigation_fields.field_names: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", investigation_fields.field_names: Required, investigation_fields.field_names: Required, and 22 more"`
+ );
});
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts
index e8573502cb662..d1432e5a67352 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts
@@ -40,7 +40,9 @@ describe('Rule response schema', () => {
const result = RuleResponse.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 15 more"`
+ );
});
test('it should validate a type of "query" with a saved_id together', () => {
@@ -68,7 +70,9 @@ describe('Rule response schema', () => {
const result = RuleResponse.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", type: Invalid literal value, expected \\"query\\", saved_id: Required, type: Invalid literal value, expected \\"threshold\\", and 14 more"`
+ );
});
test('it should validate a type of "timeline_id" if there is a "timeline_title" dependent', () => {
@@ -98,7 +102,9 @@ describe('Rule response schema', () => {
const result = RuleResponse.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"exceptions_list: Expected array, received string, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", exceptions_list: Expected array, received string, exceptions_list: Expected array, received string, and 22 more"`
+ );
});
});
@@ -232,6 +238,8 @@ describe('investigation_fields', () => {
const result = RuleResponse.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toEqual('Invalid input');
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"investigation_fields: Expected object, received string, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", investigation_fields: Expected object, received string, investigation_fields: Expected object, received string, and 22 more"`
+ );
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions_legacy.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/response_actions.ts
similarity index 82%
rename from x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions_legacy.ts
rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/response_actions.ts
index 6947953b4d65d..8f176a9908041 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions_legacy.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/response_actions.ts
@@ -4,18 +4,9 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-
import { arrayQueries, ecsMapping } from '@kbn/osquery-io-ts-types';
import * as t from 'io-ts';
import { ENABLED_AUTOMATED_RESPONSE_ACTION_COMMANDS } from '../../../../endpoint/service/response_actions/constants';
-import { ResponseActionTypesEnum } from './response_actions.gen';
-
-export const RESPONSE_ACTION_TYPES = {
- OSQUERY: ResponseActionTypesEnum['.osquery'],
- ENDPOINT: ResponseActionTypesEnum['.endpoint'],
-} as const;
-
-export const SUPPORTED_RESPONSE_ACTION_TYPES = Object.values(RESPONSE_ACTION_TYPES);
// to enable using RESPONSE_ACTION_API_COMMANDS_NAMES as a type
function keyObject(arr: T): { [K in T[number]]: null } {
@@ -47,13 +38,13 @@ export const OsqueryParamsCamelCase = t.type({
// When we create new response action types, create a union of types
export type RuleResponseOsqueryAction = t.TypeOf;
export const RuleResponseOsqueryAction = t.strict({
- actionTypeId: t.literal(RESPONSE_ACTION_TYPES.OSQUERY),
+ actionTypeId: t.literal('.osquery'),
params: OsqueryParamsCamelCase,
});
export type RuleResponseEndpointAction = t.TypeOf;
export const RuleResponseEndpointAction = t.strict({
- actionTypeId: t.literal(RESPONSE_ACTION_TYPES.ENDPOINT),
+ actionTypeId: t.literal('.endpoint'),
params: EndpointParams,
});
@@ -67,12 +58,12 @@ export const ResponseActionRuleParamsOrUndefined = t.union([
// When we create new response action types, create a union of types
const OsqueryResponseAction = t.strict({
- action_type_id: t.literal(RESPONSE_ACTION_TYPES.OSQUERY),
+ action_type_id: t.literal('.osquery'),
params: OsqueryParams,
});
const EndpointResponseAction = t.strict({
- action_type_id: t.literal(RESPONSE_ACTION_TYPES.ENDPOINT),
+ action_type_id: t.literal('.endpoint'),
params: EndpointParams,
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/rule_schemas.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/rule_schemas.ts
index e95fa38e0d2e6..4ec9ca19ee399 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/rule_schemas.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/rule_schemas.ts
@@ -26,20 +26,10 @@ import {
threat_mapping,
threat_query,
} from '@kbn/securitysolution-io-ts-alerting-types';
+import { PositiveInteger } from '@kbn/securitysolution-io-ts-types';
+import { ResponseActionArray } from './response_actions';
-import { RuleExecutionSummary } from '../../rule_monitoring/model';
-// eslint-disable-next-line no-restricted-imports
-import { ResponseActionArray } from '../rule_response_actions/response_actions_legacy';
-
-import {
- anomaly_threshold,
- created_at,
- created_by,
- revision,
- saved_id,
- updated_at,
- updated_by,
-} from '../schemas';
+import { anomaly_threshold, saved_id } from '../schemas';
import {
AlertsIndex,
@@ -51,10 +41,7 @@ import {
InvestigationFields,
InvestigationGuide,
IsRuleEnabled,
- IsRuleImmutable,
MaxSignals,
- RelatedIntegrationArray,
- RequiredFieldArray,
RuleAuthorArray,
RuleDescription,
RuleFalsePositiveArray,
@@ -63,7 +50,6 @@ import {
RuleMetadata,
RuleName,
RuleNameOverride,
- RuleObjectId,
RuleQuery,
RuleReferenceArray,
RuleSignatureId,
@@ -72,7 +58,6 @@ import {
SavedObjectResolveAliasPurpose,
SavedObjectResolveAliasTargetId,
SavedObjectResolveOutcome,
- SetupGuide,
ThreatArray,
TimelineTemplateId,
TimelineTemplateTitle,
@@ -186,28 +171,24 @@ export const baseSchema = buildRuleSchemas({
},
});
-const responseRequiredFields = {
- id: RuleObjectId,
- rule_id: RuleSignatureId,
- immutable: IsRuleImmutable,
- updated_at,
- updated_by,
- created_at,
- created_by,
- revision,
-
- // NOTE: For now, Related Integrations, Required Fields and Setup Guide are supported for prebuilt
- // rules only. We don't want to allow users to edit these 3 fields via the API. If we added them
- // to baseParams.defaultable, they would become a part of the request schema as optional fields.
- // This is why we add them here, in order to add them only to the response schema.
- related_integrations: RelatedIntegrationArray,
- required_fields: RequiredFieldArray,
- setup: SetupGuide,
-};
-
-const responseOptionalFields = {
- execution_summary: RuleExecutionSummary,
-};
+export type DurationMetric = t.TypeOf;
+export const DurationMetric = PositiveInteger;
+
+export type RuleExecutionMetrics = t.TypeOf;
+
+/**
+ @property total_search_duration_ms - "total time spent performing ES searches as measured by Kibana;
+ includes network latency and time spent serializing/deserializing request/response",
+ @property total_indexing_duration_ms - "total time spent indexing documents during current rule execution cycle",
+ @property total_enrichment_duration_ms - total time spent enriching documents during current rule execution cycle
+ @property execution_gap_duration_s - "duration in seconds of execution gap"
+*/
+export const RuleExecutionMetrics = t.partial({
+ total_search_duration_ms: DurationMetric,
+ total_indexing_duration_ms: DurationMetric,
+ total_enrichment_duration_ms: DurationMetric,
+ execution_gap_duration_s: DurationMetric,
+});
export type BaseCreateProps = t.TypeOf;
export const BaseCreateProps = baseSchema.create;
@@ -225,36 +206,9 @@ export const SharedCreateProps = t.intersection([
t.exact(t.partial({ rule_id: RuleSignatureId })),
]);
-type SharedUpdateProps = t.TypeOf;
-const SharedUpdateProps = t.intersection([
- baseSchema.create,
- t.exact(t.partial({ rule_id: RuleSignatureId })),
- t.exact(t.partial({ id: RuleObjectId })),
-]);
-
-type SharedPatchProps = t.TypeOf;
-const SharedPatchProps = t.intersection([
- baseSchema.patch,
- t.exact(t.partial({ rule_id: RuleSignatureId, id: RuleObjectId })),
-]);
-
-export type SharedResponseProps = t.TypeOf;
-export const SharedResponseProps = t.intersection([
- baseSchema.response,
- t.exact(t.type(responseRequiredFields)),
- t.exact(t.partial(responseOptionalFields)),
-]);
-
// -------------------------------------------------------------------------------------------------
// EQL rule schema
-export enum QueryLanguage {
- 'kuery' = 'kuery',
- 'lucene' = 'lucene',
- 'eql' = 'eql',
- 'esql' = 'esql',
-}
-
export type KqlQueryLanguage = t.TypeOf;
export const KqlQueryLanguage = t.keyof({ kuery: null, lucene: null });
@@ -278,21 +232,6 @@ const eqlSchema = buildRuleSchemas({
defaultable: {},
});
-export type EqlRule = t.TypeOf;
-export const EqlRule = t.intersection([SharedResponseProps, eqlSchema.response]);
-
-export type EqlRuleCreateProps = t.TypeOf;
-export const EqlRuleCreateProps = t.intersection([SharedCreateProps, eqlSchema.create]);
-
-export type EqlRuleUpdateProps = t.TypeOf;
-export const EqlRuleUpdateProps = t.intersection([SharedUpdateProps, eqlSchema.create]);
-
-export type EqlRulePatchProps = t.TypeOf;
-export const EqlRulePatchProps = t.intersection([SharedPatchProps, eqlSchema.patch]);
-
-export type EqlPatchParams = t.TypeOf;
-export const EqlPatchParams = eqlSchema.patch;
-
// -------------------------------------------------------------------------------------------------
// ES|QL rule schema
@@ -309,21 +248,6 @@ const esqlSchema = buildRuleSchemas({
defaultable: {},
});
-export type EsqlRule = t.TypeOf;
-export const EsqlRule = t.intersection([SharedResponseProps, esqlSchema.response]);
-
-export type EsqlRuleCreateProps = t.TypeOf;
-export const EsqlRuleCreateProps = t.intersection([SharedCreateProps, esqlSchema.create]);
-
-export type EsqlRuleUpdateProps = t.TypeOf;
-export const EsqlRuleUpdateProps = t.intersection([SharedUpdateProps, esqlSchema.create]);
-
-export type EsqlRulePatchProps = t.TypeOf;
-export const EsqlRulePatchProps = t.intersection([SharedPatchProps, esqlSchema.patch]);
-
-export type EsqlPatchParams = t.TypeOf;
-export const EsqlPatchParams = esqlSchema.patch;
-
// -------------------------------------------------------------------------------------------------
// Indicator Match rule schema
@@ -351,30 +275,6 @@ const threatMatchSchema = buildRuleSchemas({
},
});
-export type ThreatMatchRule = t.TypeOf;
-export const ThreatMatchRule = t.intersection([SharedResponseProps, threatMatchSchema.response]);
-
-export type ThreatMatchRuleCreateProps = t.TypeOf;
-export const ThreatMatchRuleCreateProps = t.intersection([
- SharedCreateProps,
- threatMatchSchema.create,
-]);
-
-export type ThreatMatchRuleUpdateProps = t.TypeOf;
-export const ThreatMatchRuleUpdateProps = t.intersection([
- SharedUpdateProps,
- threatMatchSchema.create,
-]);
-
-export type ThreatMatchRulePatchProps = t.TypeOf;
-export const ThreatMatchRulePatchProps = t.intersection([
- SharedPatchProps,
- threatMatchSchema.patch,
-]);
-
-export type ThreatMatchPatchParams = t.TypeOf;
-export const ThreatMatchPatchParams = threatMatchSchema.patch;
-
// -------------------------------------------------------------------------------------------------
// Custom Query rule schema
@@ -396,21 +296,6 @@ const querySchema = buildRuleSchemas({
},
});
-export type QueryRule = t.TypeOf;
-export const QueryRule = t.intersection([SharedResponseProps, querySchema.response]);
-
-export type QueryRuleCreateProps = t.TypeOf;
-export const QueryRuleCreateProps = t.intersection([SharedCreateProps, querySchema.create]);
-
-export type QueryRuleUpdateProps = t.TypeOf;
-export const QueryRuleUpdateProps = t.intersection([SharedUpdateProps, querySchema.create]);
-
-export type QueryRulePatchProps = t.TypeOf;
-export const QueryRulePatchProps = t.intersection([SharedPatchProps, querySchema.patch]);
-
-export type QueryPatchParams = t.TypeOf;
-export const QueryPatchParams = querySchema.patch;
-
// -------------------------------------------------------------------------------------------------
// Saved Query rule schema
@@ -434,27 +319,6 @@ const savedQuerySchema = buildRuleSchemas({
},
});
-export type SavedQueryRule = t.TypeOf;
-export const SavedQueryRule = t.intersection([SharedResponseProps, savedQuerySchema.response]);
-
-export type SavedQueryRuleCreateProps = t.TypeOf;
-export const SavedQueryRuleCreateProps = t.intersection([
- SharedCreateProps,
- savedQuerySchema.create,
-]);
-
-export type SavedQueryRuleUpdateProps = t.TypeOf;
-export const SavedQueryRuleUpdateProps = t.intersection([
- SharedUpdateProps,
- savedQuerySchema.create,
-]);
-
-export type SavedQueryRulePatchProps = t.TypeOf;
-export const SavedQueryRulePatchProps = t.intersection([SharedPatchProps, savedQuerySchema.patch]);
-
-export type SavedQueryPatchParams = t.TypeOf;
-export const SavedQueryPatchParams = savedQuerySchema.patch;
-
// -------------------------------------------------------------------------------------------------
// Threshold rule schema
@@ -475,21 +339,6 @@ const thresholdSchema = buildRuleSchemas({
},
});
-export type ThresholdRule = t.TypeOf;
-export const ThresholdRule = t.intersection([SharedResponseProps, thresholdSchema.response]);
-
-export type ThresholdRuleCreateProps = t.TypeOf;
-export const ThresholdRuleCreateProps = t.intersection([SharedCreateProps, thresholdSchema.create]);
-
-export type ThresholdRuleUpdateProps = t.TypeOf;
-export const ThresholdRuleUpdateProps = t.intersection([SharedUpdateProps, thresholdSchema.create]);
-
-export type ThresholdRulePatchProps = t.TypeOf;
-export const ThresholdRulePatchProps = t.intersection([SharedPatchProps, thresholdSchema.patch]);
-
-export type ThresholdPatchParams = t.TypeOf;
-export const ThresholdPatchParams = thresholdSchema.patch;
-
// -------------------------------------------------------------------------------------------------
// Machine Learning rule schema
@@ -503,33 +352,6 @@ const machineLearningSchema = buildRuleSchemas({
defaultable: {},
});
-export type MachineLearningRule = t.TypeOf;
-export const MachineLearningRule = t.intersection([
- SharedResponseProps,
- machineLearningSchema.response,
-]);
-
-export type MachineLearningRuleCreateProps = t.TypeOf;
-export const MachineLearningRuleCreateProps = t.intersection([
- SharedCreateProps,
- machineLearningSchema.create,
-]);
-
-export type MachineLearningRuleUpdateProps = t.TypeOf;
-export const MachineLearningRuleUpdateProps = t.intersection([
- SharedUpdateProps,
- machineLearningSchema.create,
-]);
-
-export type MachineLearningRulePatchProps = t.TypeOf;
-export const MachineLearningRulePatchProps = t.intersection([
- SharedPatchProps,
- machineLearningSchema.patch,
-]);
-
-export type MachineLearningPatchParams = t.TypeOf;
-export const MachineLearningPatchParams = machineLearningSchema.patch;
-
// -------------------------------------------------------------------------------------------------
// New Terms rule schema
@@ -550,21 +372,6 @@ const newTermsSchema = buildRuleSchemas({
},
});
-export type NewTermsRule = t.TypeOf;
-export const NewTermsRule = t.intersection([SharedResponseProps, newTermsSchema.response]);
-
-export type NewTermsRuleCreateProps = t.TypeOf;
-export const NewTermsRuleCreateProps = t.intersection([SharedCreateProps, newTermsSchema.create]);
-
-export type NewTermsRuleUpdateProps = t.TypeOf;
-export const NewTermsRuleUpdateProps = t.intersection([SharedUpdateProps, newTermsSchema.create]);
-
-export type NewTermsRulePatchProps = t.TypeOf;
-export const NewTermsRulePatchProps = t.intersection([SharedPatchProps, newTermsSchema.patch]);
-
-export type NewTermsPatchParams = t.TypeOf;
-export const NewTermsPatchParams = newTermsSchema.patch;
-
// -------------------------------------------------------------------------------------------------
// Combined type specific schemas
@@ -579,42 +386,3 @@ export const TypeSpecificCreateProps = t.union([
machineLearningSchema.create,
newTermsSchema.create,
]);
-
-export type TypeSpecificPatchProps = t.TypeOf;
-export const TypeSpecificPatchProps = t.union([
- eqlSchema.patch,
- esqlSchema.patch,
- threatMatchSchema.patch,
- querySchema.patch,
- savedQuerySchema.patch,
- thresholdSchema.patch,
- machineLearningSchema.patch,
- newTermsSchema.patch,
-]);
-
-export type TypeSpecificResponse = t.TypeOf;
-export const TypeSpecificResponse = t.union([
- eqlSchema.response,
- esqlSchema.response,
- threatMatchSchema.response,
- querySchema.response,
- savedQuerySchema.response,
- thresholdSchema.response,
- machineLearningSchema.response,
- newTermsSchema.response,
-]);
-
-// -------------------------------------------------------------------------------------------------
-// Final combined schemas
-
-export type RuleCreateProps = t.TypeOf;
-export const RuleCreateProps = t.intersection([TypeSpecificCreateProps, SharedCreateProps]);
-
-export type RuleUpdateProps = t.TypeOf;
-export const RuleUpdateProps = t.intersection([TypeSpecificCreateProps, SharedUpdateProps]);
-
-export type RulePatchProps = t.TypeOf;
-export const RulePatchProps = t.intersection([TypeSpecificPatchProps, SharedPatchProps]);
-
-export type RuleResponse = t.TypeOf;
-export const RuleResponse = t.intersection([TypeSpecificResponse, SharedResponseProps]);
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts
index 9c325d1e70fc0..35a394edcb6ad 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts
@@ -33,12 +33,6 @@ export type Status = t.TypeOf;
export const conflicts = t.keyof({ abort: null, proceed: null });
-export const queryFilter = t.string;
-export type QueryFilter = t.TypeOf;
-
-export const queryFilterOrUndefined = t.union([queryFilter, t.undefined]);
-export type QueryFilterOrUndefined = t.TypeOf;
-
export const signal_ids = t.array(t.string);
export type SignalIds = t.TypeOf;
@@ -48,23 +42,12 @@ export const signal_status_query = t.object;
export const alert_tag_ids = t.array(t.string);
export type AlertTagIds = t.TypeOf;
-export const fields = t.array(t.string);
-export type Fields = t.TypeOf;
-export const fieldsOrUndefined = t.union([fields, t.undefined]);
-export type FieldsOrUndefined = t.TypeOf;
-
export const created_at = IsoDateString;
export const updated_at = IsoDateString;
export const created_by = t.string;
export const updated_by = t.string;
-export const status_code = PositiveInteger;
-export const message = t.string;
-export const perPage = PositiveInteger;
-export const total = PositiveInteger;
export const revision = PositiveInteger;
-export const success = t.boolean;
-export const success_count = PositiveInteger;
export const indexRecord = t.record(
t.string,
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts
index 17ad724039d7e..04a5fadefe051 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts
@@ -5,85 +5,30 @@
* 2.0.
*/
-import { pipe } from 'fp-ts/lib/pipeable';
-import { left } from 'fp-ts/lib/Either';
-import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import { DefaultSortOrderAsc, DefaultSortOrderDesc } from './sorting_legacy';
-
-describe('Common sorting schemas', () => {
- describe('DefaultSortOrderAsc', () => {
- describe('Validation succeeds', () => {
- it('when valid sort order is passed', () => {
- const payload = 'desc';
- const decoded = DefaultSortOrderAsc.decode(payload);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
- });
- });
-
- describe('Validation fails', () => {
- it('when invalid sort order is passed', () => {
- const payload = 'behind_you';
- const decoded = DefaultSortOrderAsc.decode(payload);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "behind_you" supplied to "DefaultSortOrderAsc"',
- ]);
- expect(message.schema).toEqual({});
- });
- });
-
- describe('Validation sets the default sort order "asc"', () => {
- it('when sort order is not passed', () => {
- const payload = undefined;
- const decoded = DefaultSortOrderAsc.decode(payload);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual('asc');
- });
- });
+import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers';
+import { SortOrder } from './sorting.gen';
+
+describe('SortOrder schema', () => {
+ it('accepts asc value', () => {
+ const payload = 'asc';
+ const result = SortOrder.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
- describe('DefaultSortOrderDesc', () => {
- describe('Validation succeeds', () => {
- it('when valid sort order is passed', () => {
- const payload = 'asc';
- const decoded = DefaultSortOrderDesc.decode(payload);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
- });
- });
-
- describe('Validation fails', () => {
- it('when invalid sort order is passed', () => {
- const payload = 'behind_you';
- const decoded = DefaultSortOrderDesc.decode(payload);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "behind_you" supplied to "DefaultSortOrderDesc"',
- ]);
- expect(message.schema).toEqual({});
- });
- });
-
- describe('Validation sets the default sort order "desc"', () => {
- it('when sort order is not passed', () => {
- const payload = null;
- const decoded = DefaultSortOrderDesc.decode(payload);
- const message = pipe(decoded, foldLeftRight);
+ it('accepts desc value', () => {
+ const payload = 'desc';
+ const result = SortOrder.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
+ });
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual('desc');
- });
- });
+ it('fails on unknown value', () => {
+ const payload = 'invalid';
+ const result = SortOrder.safeParse(payload);
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toEqual(
+ "Invalid enum value. Expected 'asc' | 'desc', received 'invalid'"
+ );
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting_legacy.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting_legacy.ts
deleted file mode 100644
index 8aa8cf2831ea1..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting_legacy.ts
+++ /dev/null
@@ -1,40 +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 * as t from 'io-ts';
-import type { Either } from 'fp-ts/lib/Either';
-import { capitalize } from 'lodash';
-
-export type SortOrder = t.TypeOf;
-export const SortOrder = t.keyof({ asc: null, desc: null });
-
-export type SortOrderOrUndefined = t.TypeOf;
-export const SortOrderOrUndefined = t.union([SortOrder, t.undefined]);
-
-const defaultSortOrder = (order: SortOrder): t.Type => {
- return new t.Type(
- `DefaultSortOrder${capitalize(order)}`,
- SortOrder.is,
- (input, context): Either =>
- input == null ? t.success(order) : SortOrder.validate(input, context),
- t.identity
- );
-};
-
-/**
- * Types the DefaultSortOrderAsc as:
- * - If undefined, then a default sort order of 'asc' will be set
- * - If a string is sent in, then the string will be validated to ensure it's a valid SortOrder
- */
-export const DefaultSortOrderAsc = defaultSortOrder('asc');
-
-/**
- * Types the DefaultSortOrderDesc as:
- * - If undefined, then a default sort order of 'desc' will be set
- * - If a string is sent in, then the string will be validated to ensure it's a valid SortOrder
- */
-export const DefaultSortOrderDesc = defaultSortOrder('desc');
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts
index feecf23faf293..75eb2b543d337 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts
@@ -12,9 +12,7 @@ import type {
ExceptionListItemSchema,
} from '@kbn/securitysolution-io-ts-list-types';
import { createRuleExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import { RuleObjectId } from '../../model/rule_schema_legacy';
+import { UUID } from '@kbn/securitysolution-io-ts-types';
/**
* URL path parameters of the API route.
@@ -22,7 +20,7 @@ import { RuleObjectId } from '../../model/rule_schema_legacy';
export type CreateRuleExceptionsRequestParams = t.TypeOf;
export const CreateRuleExceptionsRequestParams = t.exact(
t.type({
- id: RuleObjectId,
+ id: UUID,
})
);
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts
new file mode 100644
index 0000000000000..d11eea7b16711
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts
@@ -0,0 +1,291 @@
+/*
+ * 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 { z } from 'zod';
+import { BooleanFromString } from '@kbn/zod-helpers';
+
+/*
+ * NOTICE: Do not edit this file manually.
+ * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
+ */
+
+import { RuleResponse } from '../../model/rule_schema/rule_schemas.gen';
+import {
+ RuleActionGroup,
+ RuleActionId,
+ RuleActionParams,
+ RuleActionFrequency,
+ RuleActionAlertsFilter,
+ IndexPatternArray,
+ RuleTagArray,
+ TimelineTemplateId,
+ TimelineTemplateTitle,
+} from '../../model/rule_schema/common_attributes.gen';
+
+export type BulkEditSkipReason = z.infer;
+export const BulkEditSkipReason = z.literal('RULE_NOT_MODIFIED');
+
+export type BulkActionSkipResult = z.infer;
+export const BulkActionSkipResult = z.object({
+ id: z.string(),
+ name: z.string().optional(),
+ skip_reason: BulkEditSkipReason,
+});
+
+export type RuleDetailsInError = z.infer;
+export const RuleDetailsInError = z.object({
+ id: z.string(),
+ name: z.string().optional(),
+});
+
+export type BulkActionsDryRunErrCode = z.infer;
+export const BulkActionsDryRunErrCode = z.enum([
+ 'IMMUTABLE',
+ 'MACHINE_LEARNING_AUTH',
+ 'MACHINE_LEARNING_INDEX_PATTERN',
+ 'ESQL_INDEX_PATTERN',
+]);
+export type BulkActionsDryRunErrCodeEnum = typeof BulkActionsDryRunErrCode.enum;
+export const BulkActionsDryRunErrCodeEnum = BulkActionsDryRunErrCode.enum;
+
+export type NormalizedRuleError = z.infer;
+export const NormalizedRuleError = z.object({
+ message: z.string(),
+ status_code: z.number().int(),
+ err_code: BulkActionsDryRunErrCode.optional(),
+ rules: z.array(RuleDetailsInError),
+});
+
+export type BulkEditActionResults = z.infer;
+export const BulkEditActionResults = z.object({
+ updated: z.array(RuleResponse),
+ created: z.array(RuleResponse),
+ deleted: z.array(RuleResponse),
+ skipped: z.array(BulkActionSkipResult),
+});
+
+export type BulkEditActionSummary = z.infer;
+export const BulkEditActionSummary = z.object({
+ failed: z.number().int(),
+ skipped: z.number().int(),
+ succeeded: z.number().int(),
+ total: z.number().int(),
+});
+
+export type BulkEditActionResponse = z.infer;
+export const BulkEditActionResponse = z.object({
+ success: z.boolean().optional(),
+ status_code: z.number().int().optional(),
+ message: z.string().optional(),
+ rules_count: z.number().int().optional(),
+ attributes: z.object({
+ results: BulkEditActionResults,
+ summary: BulkEditActionSummary,
+ errors: z.array(NormalizedRuleError).optional(),
+ }),
+});
+
+export type BulkExportActionResponse = z.infer;
+export const BulkExportActionResponse = z.string();
+
+export type BulkActionBase = z.infer;
+export const BulkActionBase = z.object({
+ /**
+ * Query to filter rules
+ */
+ query: z.string().optional(),
+ /**
+ * Array of rule IDs
+ */
+ ids: z.array(z.string()).min(1).optional(),
+});
+
+export type BulkDeleteRules = z.infer;
+export const BulkDeleteRules = BulkActionBase.and(
+ z.object({
+ action: z.literal('delete'),
+ })
+);
+
+export type BulkDisableRules = z.infer;
+export const BulkDisableRules = BulkActionBase.and(
+ z.object({
+ action: z.literal('disable'),
+ })
+);
+
+export type BulkEnableRules = z.infer;
+export const BulkEnableRules = BulkActionBase.and(
+ z.object({
+ action: z.literal('enable'),
+ })
+);
+
+export type BulkExportRules = z.infer;
+export const BulkExportRules = BulkActionBase.and(
+ z.object({
+ action: z.literal('export'),
+ })
+);
+
+export type BulkDuplicateRules = z.infer;
+export const BulkDuplicateRules = BulkActionBase.and(
+ z.object({
+ action: z.literal('duplicate'),
+ duplicate: z
+ .object({
+ /**
+ * Whether to copy exceptions from the original rule
+ */
+ include_exceptions: z.boolean(),
+ /**
+ * Whether to copy expired exceptions from the original rule
+ */
+ include_expired_exceptions: z.boolean(),
+ })
+ .optional(),
+ })
+);
+
+/**
+ * The condition for throttling the notification: 'rule', 'no_actions', or time duration
+ */
+export type ThrottleForBulkActions = z.infer;
+export const ThrottleForBulkActions = z.enum(['rule', '1h', '1d', '7d']);
+export type ThrottleForBulkActionsEnum = typeof ThrottleForBulkActions.enum;
+export const ThrottleForBulkActionsEnum = ThrottleForBulkActions.enum;
+
+export type BulkActionType = z.infer;
+export const BulkActionType = z.enum([
+ 'enable',
+ 'disable',
+ 'export',
+ 'delete',
+ 'duplicate',
+ 'edit',
+]);
+export type BulkActionTypeEnum = typeof BulkActionType.enum;
+export const BulkActionTypeEnum = BulkActionType.enum;
+
+export type BulkActionEditType = z.infer;
+export const BulkActionEditType = z.enum([
+ 'add_tags',
+ 'delete_tags',
+ 'set_tags',
+ 'add_index_patterns',
+ 'delete_index_patterns',
+ 'set_index_patterns',
+ 'set_timeline',
+ 'add_rule_actions',
+ 'set_rule_actions',
+ 'set_schedule',
+]);
+export type BulkActionEditTypeEnum = typeof BulkActionEditType.enum;
+export const BulkActionEditTypeEnum = BulkActionEditType.enum;
+
+export type NormalizedRuleAction = z.infer;
+export const NormalizedRuleAction = z
+ .object({
+ group: RuleActionGroup,
+ id: RuleActionId,
+ params: RuleActionParams,
+ frequency: RuleActionFrequency.optional(),
+ alerts_filter: RuleActionAlertsFilter.optional(),
+ })
+ .strict();
+
+export type BulkActionEditPayloadRuleActions = z.infer;
+export const BulkActionEditPayloadRuleActions = z.object({
+ type: z.enum(['add_rule_actions', 'set_rule_actions']),
+ value: z.object({
+ throttle: ThrottleForBulkActions.optional(),
+ actions: z.array(NormalizedRuleAction),
+ }),
+});
+
+export type BulkActionEditPayloadSchedule = z.infer;
+export const BulkActionEditPayloadSchedule = z.object({
+ type: z.literal('set_schedule'),
+ value: z.object({
+ /**
+ * Interval in which the rule is executed
+ */
+ interval: z.string().regex(/^[1-9]\d*[smh]$/),
+ /**
+ * Lookback time for the rule
+ */
+ lookback: z.string().regex(/^[1-9]\d*[smh]$/),
+ }),
+});
+
+export type BulkActionEditPayloadIndexPatterns = z.infer;
+export const BulkActionEditPayloadIndexPatterns = z.object({
+ type: z.enum(['add_index_patterns', 'delete_index_patterns', 'set_index_patterns']),
+ value: IndexPatternArray,
+ overwrite_data_views: z.boolean().optional(),
+});
+
+export type BulkActionEditPayloadTags = z.infer;
+export const BulkActionEditPayloadTags = z.object({
+ type: z.enum(['add_tags', 'delete_tags', 'set_tags']),
+ value: RuleTagArray,
+});
+
+export type BulkActionEditPayloadTimeline = z.infer;
+export const BulkActionEditPayloadTimeline = z.object({
+ type: z.literal('set_timeline'),
+ value: z.object({
+ timeline_id: TimelineTemplateId,
+ timeline_title: TimelineTemplateTitle,
+ }),
+});
+
+export type BulkActionEditPayload = z.infer;
+export const BulkActionEditPayload = z.union([
+ BulkActionEditPayloadTags,
+ BulkActionEditPayloadIndexPatterns,
+ BulkActionEditPayloadTimeline,
+ BulkActionEditPayloadRuleActions,
+ BulkActionEditPayloadSchedule,
+]);
+
+export type BulkEditRules = z.infer;
+export const BulkEditRules = BulkActionBase.and(
+ z.object({
+ action: z.literal('edit'),
+ /**
+ * Array of objects containing the edit operations
+ */
+ edit: z.array(BulkActionEditPayload).min(1),
+ })
+);
+
+export type PerformBulkActionRequestQuery = z.infer;
+export const PerformBulkActionRequestQuery = z.object({
+ /**
+ * Enables dry run mode for the request call.
+ */
+ dry_run: BooleanFromString.optional(),
+});
+export type PerformBulkActionRequestQueryInput = z.input;
+
+export type PerformBulkActionRequestBody = z.infer;
+export const PerformBulkActionRequestBody = z.union([
+ BulkDeleteRules,
+ BulkDisableRules,
+ BulkEnableRules,
+ BulkExportRules,
+ BulkDuplicateRules,
+ BulkEditRules,
+]);
+export type PerformBulkActionRequestBodyInput = z.input;
+
+export type PerformBulkActionResponse = z.infer;
+export const PerformBulkActionResponse = z.union([
+ BulkEditActionResponse,
+ BulkExportActionResponse,
+]);
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.mock.ts
index 66ce78ff9b615..fa4fcefbcad1a 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.mock.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.mock.ts
@@ -5,18 +5,18 @@
* 2.0.
*/
-import { BulkActionType, BulkActionEditType } from './bulk_actions_route';
-import type { PerformBulkActionRequestBody } from './bulk_actions_route';
+import type { PerformBulkActionRequestBody } from './bulk_actions_route.gen';
+import { BulkActionEditTypeEnum, BulkActionTypeEnum } from './bulk_actions_route.gen';
export const getPerformBulkActionSchemaMock = (): PerformBulkActionRequestBody => ({
query: '',
ids: undefined,
- action: BulkActionType.disable,
+ action: BulkActionTypeEnum.disable,
});
export const getPerformBulkActionEditSchemaMock = (): PerformBulkActionRequestBody => ({
query: '',
ids: undefined,
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.add_tags, value: ['tag1'] }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [{ type: BulkActionEditTypeEnum.add_tags, value: ['tag1'] }],
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml
index 8eba09881bbd9..583782f086ae7 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml
@@ -6,7 +6,7 @@ paths:
/api/detection_engine/rules/_bulk_action:
post:
operationId: PerformBulkAction
- x-codegen-enabled: false
+ x-codegen-enabled: true
summary: Applies a bulk action to multiple rules
description: The bulk action is applied to all rules that match the filter or to the list of rules by their IDs.
tags:
@@ -22,19 +22,24 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/PerformBulkActionRequest'
+ oneOf:
+ - $ref: '#/components/schemas/BulkDeleteRules'
+ - $ref: '#/components/schemas/BulkDisableRules'
+ - $ref: '#/components/schemas/BulkEnableRules'
+ - $ref: '#/components/schemas/BulkExportRules'
+ - $ref: '#/components/schemas/BulkDuplicateRules'
+ - $ref: '#/components/schemas/BulkEditRules'
responses:
200:
description: OK
content:
application/json:
schema:
- type: array
- items:
- $ref: '#/components/schemas/BulkEditActionResponse'
+ oneOf:
+ - $ref: '#/components/schemas/BulkEditActionResponse'
+ - $ref: '#/components/schemas/BulkExportActionResponse'
components:
- x-codegen-enabled: false
schemas:
BulkEditSkipReason:
type: string
@@ -66,6 +71,11 @@ components:
BulkActionsDryRunErrCode:
type: string
+ enum:
+ - IMMUTABLE
+ - MACHINE_LEARNING_AUTH
+ - MACHINE_LEARNING_INDEX_PATTERN
+ - ESQL_INDEX_PATTERN
NormalizedRuleError:
type: object
@@ -127,35 +137,17 @@ components:
- succeeded
- total
- BulkEditActionSuccessResponse:
+ BulkEditActionResponse:
type: object
properties:
success:
type: boolean
- rules_count:
- type: integer
- attributes:
- type: object
- properties:
- results:
- $ref: '#/components/schemas/BulkEditActionResults'
- summary:
- $ref: '#/components/schemas/BulkEditActionSummary'
- required:
- - results
- - summary
- required:
- - success
- - rules_count
- - attributes
-
- BulkEditActionErrorResponse:
- type: object
- properties:
status_code:
type: integer
message:
type: string
+ rules_count:
+ type: integer
attributes:
type: object
properties:
@@ -171,35 +163,23 @@ components:
- results
- summary
required:
- - status_code
- - message
- attributes
- BulkEditActionResponse:
- oneOf:
- - $ref: '#/components/schemas/BulkEditActionSuccessResponse'
- - $ref: '#/components/schemas/BulkEditActionErrorResponse'
+ BulkExportActionResponse:
+ type: string
BulkActionBase:
- oneOf:
- - type: object
- properties:
- query:
- type: string
- description: Query to filter rules
- required:
- - query
- additionalProperties: false
-
- - type: object
- properties:
- ids:
- type: array
- description: Array of rule IDs
- minItems: 1
- items:
- type: string
- additionalProperties: false
+ type: object
+ properties:
+ query:
+ type: string
+ description: Query to filter rules
+ ids:
+ type: array
+ description: Array of rule IDs
+ minItems: 1
+ items:
+ type: string
BulkDeleteRules:
allOf:
@@ -262,35 +242,20 @@ components:
include_expired_exceptions:
type: boolean
description: Whether to copy expired exceptions from the original rule
+ required:
+ - include_exceptions
+ - include_expired_exceptions
required:
- action
- RuleActionSummary:
- type: boolean
- description: Action summary indicates whether we will send a summary notification about all the generate alerts or notification per individual alert
-
- RuleActionNotifyWhen:
- type: string
- description: "The condition for throttling the notification: 'onActionGroupChange', 'onActiveAlert', or 'onThrottleInterval'"
- enum:
- - onActionGroupChange
- - onActiveAlert
- - onThrottleInterval
-
- RuleActionThrottle:
+ ThrottleForBulkActions:
type: string
description: "The condition for throttling the notification: 'rule', 'no_actions', or time duration"
-
- RuleActionFrequency:
- type: object
- properties:
- summary:
- $ref: '#/components/schemas/RuleActionSummary'
- notifyWhen:
- $ref: '#/components/schemas/RuleActionNotifyWhen'
- throttle:
- $ref: '#/components/schemas/RuleActionThrottle'
- nullable: true
+ enum:
+ - rule
+ - 1h
+ - 1d
+ - 7d
BulkActionType:
type: string
@@ -316,6 +281,26 @@ components:
- set_rule_actions
- set_schedule
+ # Per rulesClient.bulkEdit rules actions operation contract (x-pack/plugins/alerting/server/rules_client/rules_client.ts) normalized rule action object is expected (NormalizedAlertAction) as value for the edit operation
+ NormalizedRuleAction:
+ type: object
+ properties:
+ group:
+ $ref: '../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleActionGroup'
+ id:
+ $ref: '../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleActionId'
+ params:
+ $ref: '../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleActionParams'
+ frequency:
+ $ref: '../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleActionFrequency'
+ alerts_filter:
+ $ref: '../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleActionAlertsFilter'
+ required:
+ - group
+ - id
+ - params
+ additionalProperties: false
+
BulkActionEditPayloadRuleActions:
type: object
properties:
@@ -326,28 +311,11 @@ components:
type: object
properties:
throttle:
- $ref: '#/components/schemas/RuleActionThrottle'
+ $ref: '#/components/schemas/ThrottleForBulkActions'
actions:
type: array
items:
- type: object
- properties:
- group:
- type: string
- description: Action group
- id:
- type: string
- description: Action ID
- params:
- type: object
- description: Action parameters
- frequency:
- $ref: '#/components/schemas/RuleActionFrequency'
- description: Action frequency
- required:
- - group
- - id
- - params
+ $ref: '#/components/schemas/NormalizedRuleAction'
required:
- actions
required:
@@ -366,12 +334,19 @@ components:
interval:
type: string
description: Interval in which the rule is executed
+ pattern: '^[1-9]\d*[smh]$' # any number except zero followed by one of the suffixes 's', 'm', 'h'
+ example: '1h'
lookback:
type: string
description: Lookback time for the rule
+ pattern: '^[1-9]\d*[smh]$' # any number except zero followed by one of the suffixes 's', 'm', 'h'
+ example: '1h'
required:
- interval
- lookback
+ required:
+ - type
+ - value
BulkActionEditPayloadIndexPatterns:
type: object
@@ -441,22 +416,13 @@ components:
properties:
action:
type: string
- x-type: literal
enum: [edit]
edit:
type: array
description: Array of objects containing the edit operations
items:
$ref: '#/components/schemas/BulkActionEditPayload'
+ minItems: 1
required:
- action
- - rule
-
- PerformBulkActionRequest:
- oneOf:
- - $ref: '#/components/schemas/BulkDeleteRules'
- - $ref: '#/components/schemas/BulkDisableRules'
- - $ref: '#/components/schemas/BulkEnableRules'
- - $ref: '#/components/schemas/BulkExportRules'
- - $ref: '#/components/schemas/BulkDuplicateRules'
- - $ref: '#/components/schemas/BulkEditRules'
+ - edit
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.test.ts
index 70ae548674332..ff5289f79d98d 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.test.ts
@@ -5,19 +5,12 @@
* 2.0.
*/
-import { left } from 'fp-ts/lib/Either';
-import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
+import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers';
import {
+ BulkActionEditTypeEnum,
+ BulkActionTypeEnum,
PerformBulkActionRequestBody,
- BulkActionType,
- BulkActionEditType,
-} from './bulk_actions_route';
-
-const retrieveValidationMessage = (payload: unknown) => {
- const decoded = PerformBulkActionRequestBody.decode(payload);
- const checked = exactCheck(payload, decoded);
- return foldLeftRight(checked);
-};
+} from './bulk_actions_route.gen';
describe('Perform bulk action request schema', () => {
describe('cases common to every bulk action', () => {
@@ -25,62 +18,64 @@ describe('Perform bulk action request schema', () => {
test('valid request: missing query', () => {
const payload: PerformBulkActionRequestBody = {
query: undefined,
- action: BulkActionType.enable,
+ action: BulkActionTypeEnum.enable,
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
test('invalid request: missing action', () => {
const payload: Omit = {
query: 'name: test',
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "undefined" supplied to "action"',
- 'Invalid value "undefined" supplied to "edit"',
- ]);
- expect(message.schema).toEqual({});
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 2 more"`
+ );
});
test('invalid request: unknown action', () => {
const payload: Omit & { action: 'unknown' } = {
- query: 'name: test',
action: 'unknown',
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "unknown" supplied to "action"',
- 'Invalid value "undefined" supplied to "edit"',
- ]);
- expect(message.schema).toEqual({});
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 2 more"`
+ );
});
- test('invalid request: unknown property', () => {
+ test('strips unknown properties', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.enable,
+ action: BulkActionTypeEnum.enable,
mock: ['id'],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseSuccess(result);
- expect(getPaths(left(message.errors))).toEqual(['invalid keys "mock,["id"]"']);
- expect(message.schema).toEqual({});
+ expect(result.data).toEqual({
+ query: 'name: test',
+ action: BulkActionTypeEnum.enable,
+ });
});
test('invalid request: wrong type for ids', () => {
const payload = {
ids: 'mock',
- action: BulkActionType.enable,
+ action: BulkActionTypeEnum.enable,
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
- expect(getPaths(left(message.errors))).toEqual(['Invalid value "mock" supplied to "ids"']);
- expect(message.schema).toEqual({});
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"ids: Expected array, received string, action: Invalid literal value, expected \\"delete\\", ids: Expected array, received string, action: Invalid literal value, expected \\"disable\\", ids: Expected array, received string, and 7 more"`
+ );
});
});
@@ -88,11 +83,11 @@ describe('Perform bulk action request schema', () => {
test('valid request', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.enable,
+ action: BulkActionTypeEnum.enable,
};
- const message = retrieveValidationMessage(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -100,11 +95,11 @@ describe('Perform bulk action request schema', () => {
test('valid request', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.disable,
+ action: BulkActionTypeEnum.disable,
};
- const message = retrieveValidationMessage(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -112,11 +107,11 @@ describe('Perform bulk action request schema', () => {
test('valid request', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.export,
+ action: BulkActionTypeEnum.export,
};
- const message = retrieveValidationMessage(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -124,11 +119,11 @@ describe('Perform bulk action request schema', () => {
test('valid request', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.delete,
+ action: BulkActionTypeEnum.delete,
};
- const message = retrieveValidationMessage(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -136,15 +131,15 @@ describe('Perform bulk action request schema', () => {
test('valid request', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.duplicate,
- [BulkActionType.duplicate]: {
+ action: BulkActionTypeEnum.duplicate,
+ [BulkActionTypeEnum.duplicate]: {
include_exceptions: false,
include_expired_exceptions: false,
},
};
- const message = retrieveValidationMessage(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -153,47 +148,30 @@ describe('Perform bulk action request schema', () => {
test('invalid request: missing edit payload', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- };
-
- const message = retrieveValidationMessage(payload);
-
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "undefined" supplied to "edit"',
- ]);
- expect(message.schema).toEqual({});
- });
-
- test('invalid request: specified edit payload for another action', () => {
- const payload = {
- query: 'name: test',
- action: BulkActionType.enable,
- [BulkActionType.edit]: [{ type: BulkActionEditType.set_tags, value: ['test-tag'] }],
+ action: BulkActionTypeEnum.edit,
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
- expect(getPaths(left(message.errors))).toEqual([
- 'invalid keys "edit,[{"type":"set_tags","value":["test-tag"]}]"',
- ]);
- expect(message.schema).toEqual({});
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 1 more"`
+ );
});
test('invalid request: wrong type for edit payload', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: { type: BulkActionEditType.set_tags, value: ['test-tag'] },
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: { type: BulkActionEditTypeEnum.set_tags, value: ['test-tag'] },
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "{"type":"set_tags","value":["test-tag"]}" supplied to "edit"',
- ]);
- expect(message.schema).toEqual({});
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 1 more"`
+ );
});
});
@@ -201,57 +179,61 @@ describe('Perform bulk action request schema', () => {
test('invalid request: wrong tags type', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.set_tags, value: 'test-tag' }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [{ type: BulkActionEditTypeEnum.set_tags, value: 'test-tag' }],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "test-tag" supplied to "edit,value"',
- 'Invalid value "set_tags" supplied to "edit,type"',
- ]);
- expect(message.schema).toEqual({});
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 9 more"`
+ );
});
test('valid request: add_tags edit action', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.add_tags, value: ['test-tag'] }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
+ { type: BulkActionEditTypeEnum.add_tags, value: ['test-tag'] },
+ ],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
test('valid request: set_tags edit action', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.set_tags, value: ['test-tag'] }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
+ { type: BulkActionEditTypeEnum.set_tags, value: ['test-tag'] },
+ ],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
test('valid request: delete_tags edit action', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.delete_tags, value: ['test-tag'] }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
+ { type: BulkActionEditTypeEnum.delete_tags, value: ['test-tag'] },
+ ],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -259,63 +241,61 @@ describe('Perform bulk action request schema', () => {
test('invalid request: wrong index_patterns type', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.set_tags, value: 'logs-*' }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [{ type: BulkActionEditTypeEnum.set_tags, value: 'logs-*' }],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "logs-*" supplied to "edit,value"',
- 'Invalid value "set_tags" supplied to "edit,type"',
- ]);
- expect(message.schema).toEqual({});
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 9 more"`
+ );
});
test('valid request: set_index_patterns edit action', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
- { type: BulkActionEditType.set_index_patterns, value: ['logs-*'] },
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
+ { type: BulkActionEditTypeEnum.set_index_patterns, value: ['logs-*'] },
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
test('valid request: add_index_patterns edit action', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
- { type: BulkActionEditType.add_index_patterns, value: ['logs-*'] },
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
+ { type: BulkActionEditTypeEnum.add_index_patterns, value: ['logs-*'] },
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
test('valid request: delete_index_patterns edit action', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
- { type: BulkActionEditType.delete_index_patterns, value: ['logs-*'] },
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
+ { type: BulkActionEditTypeEnum.delete_index_patterns, value: ['logs-*'] },
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -323,27 +303,25 @@ describe('Perform bulk action request schema', () => {
test('invalid request: wrong timeline payload type', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.set_timeline, value: [] }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [{ type: BulkActionEditTypeEnum.set_timeline, value: [] }],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "set_timeline" supplied to "edit,type"',
- 'Invalid value "[]" supplied to "edit,value"',
- ]);
- expect(message.schema).toEqual({});
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 7 more"`
+ );
});
test('invalid request: missing timeline_id', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_title: 'Test timeline title',
},
@@ -351,24 +329,21 @@ describe('Perform bulk action request schema', () => {
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual(
- expect.arrayContaining([
- 'Invalid value "{"timeline_title":"Test timeline title"}" supplied to "edit,value"',
- 'Invalid value "undefined" supplied to "edit,value,timeline_id"',
- ])
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 10 more"`
);
- expect(message.schema).toEqual({});
});
test('valid request: set_timeline edit action', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_id: 'timelineid',
timeline_title: 'Test timeline title',
@@ -377,10 +352,10 @@ describe('Perform bulk action request schema', () => {
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -388,27 +363,25 @@ describe('Perform bulk action request schema', () => {
test('invalid request: wrong schedules payload type', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.set_schedule, value: [] }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [{ type: BulkActionEditTypeEnum.set_schedule, value: [] }],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "set_schedule" supplied to "edit,type"',
- 'Invalid value "[]" supplied to "edit,value"',
- ]);
- expect(message.schema).toEqual({});
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 7 more"`
+ );
});
test('invalid request: wrong type of payload data', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
interval: '-10m',
lookback: '1m',
@@ -417,25 +390,21 @@ describe('Perform bulk action request schema', () => {
],
} as PerformBulkActionRequestBody;
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual(
- expect.arrayContaining([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "{"interval":"-10m","lookback":"1m"}" supplied to "edit,value"',
- 'Invalid value "-10m" supplied to "edit,value,interval"',
- ])
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"edit.0.value.interval: Invalid"`
);
- expect(message.schema).toEqual({});
});
test('invalid request: missing interval', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
lookback: '1m',
},
@@ -443,25 +412,21 @@ describe('Perform bulk action request schema', () => {
],
} as PerformBulkActionRequestBody;
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual(
- expect.arrayContaining([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "{"lookback":"1m"}" supplied to "edit,value"',
- 'Invalid value "undefined" supplied to "edit,value,interval"',
- ])
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 10 more"`
);
- expect(message.schema).toEqual({});
});
test('invalid request: missing lookback', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
interval: '1m',
},
@@ -469,25 +434,21 @@ describe('Perform bulk action request schema', () => {
],
} as PerformBulkActionRequestBody;
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual(
- expect.arrayContaining([
- 'Invalid value "edit" supplied to "action"',
- 'Invalid value "{"interval":"1m"}" supplied to "edit,value"',
- 'Invalid value "undefined" supplied to "edit,value,lookback"',
- ])
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 10 more"`
);
- expect(message.schema).toEqual({});
});
test('valid request: set_schedule edit action', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
interval: '1m',
lookback: '1m',
@@ -496,10 +457,10 @@ describe('Perform bulk action request schema', () => {
],
} as PerformBulkActionRequestBody;
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
@@ -507,25 +468,25 @@ describe('Perform bulk action request schema', () => {
test('invalid request: invalid rule actions payload', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [{ type: BulkActionEditType.add_rule_actions, value: [] }],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [{ type: BulkActionEditTypeEnum.add_rule_actions, value: [] }],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual(
- expect.arrayContaining(['Invalid value "[]" supplied to "edit,value"'])
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 7 more"`
);
- expect(message.schema).toEqual({});
});
test('invalid request: missing actions in payload', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
},
@@ -533,21 +494,21 @@ describe('Perform bulk action request schema', () => {
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual(
- expect.arrayContaining(['Invalid value "undefined" supplied to "edit,value,actions"'])
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"action: Invalid literal value, expected \\"delete\\", action: Invalid literal value, expected \\"disable\\", action: Invalid literal value, expected \\"enable\\", action: Invalid literal value, expected \\"export\\", action: Invalid literal value, expected \\"duplicate\\", and 11 more"`
);
- expect(message.schema).toEqual({});
});
test('invalid request: invalid action_type_id property in actions array', () => {
const payload = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -567,20 +528,20 @@ describe('Perform bulk action request schema', () => {
],
};
- const message = retrieveValidationMessage(payload);
- expect(getPaths(left(message.errors))).toEqual(
- expect.arrayContaining(['invalid keys "action_type_id"'])
+ const result = PerformBulkActionRequestBody.safeParse(payload);
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"edit.0.value.actions.0: Unrecognized key(s) in object: 'action_type_id'"`
);
- expect(message.schema).toEqual({});
});
test('valid request: add_rule_actions edit action', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -599,19 +560,19 @@ describe('Perform bulk action request schema', () => {
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
test('valid request: set_rule_actions edit action', () => {
const payload: PerformBulkActionRequestBody = {
query: 'name: test',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -632,10 +593,10 @@ describe('Perform bulk action request schema', () => {
],
};
- const message = retrieveValidationMessage(payload);
+ const result = PerformBulkActionRequestBody.safeParse(payload);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.ts
deleted file mode 100644
index 768626d08769d..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.ts
+++ /dev/null
@@ -1,269 +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 * as t from 'io-ts';
-
-import { NonEmptyArray, TimeDuration } from '@kbn/securitysolution-io-ts-types';
-import {
- RuleActionAlertsFilter,
- RuleActionFrequency,
- RuleActionGroup,
- RuleActionId,
- RuleActionParams,
-} from '@kbn/securitysolution-io-ts-alerting-types';
-
-import type { BulkActionSkipResult } from '@kbn/alerting-plugin/common';
-import type { RuleResponse } from '../../model';
-import type { BulkActionsDryRunErrCode } from '../../../../constants';
-
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import {
- IndexPatternArray,
- RuleQuery,
- RuleTagArray,
- TimelineTemplateId,
- TimelineTemplateTitle,
-} from '../../model/rule_schema_legacy';
-
-export enum BulkActionType {
- 'enable' = 'enable',
- 'disable' = 'disable',
- 'export' = 'export',
- 'delete' = 'delete',
- 'duplicate' = 'duplicate',
- 'edit' = 'edit',
-}
-
-export enum BulkActionEditType {
- 'add_tags' = 'add_tags',
- 'delete_tags' = 'delete_tags',
- 'set_tags' = 'set_tags',
- 'add_index_patterns' = 'add_index_patterns',
- 'delete_index_patterns' = 'delete_index_patterns',
- 'set_index_patterns' = 'set_index_patterns',
- 'set_timeline' = 'set_timeline',
- 'add_rule_actions' = 'add_rule_actions',
- 'set_rule_actions' = 'set_rule_actions',
- 'set_schedule' = 'set_schedule',
-}
-
-export type ThrottleForBulkActions = t.TypeOf;
-export const ThrottleForBulkActions = t.union([
- t.literal('rule'),
- t.literal('1h'),
- t.literal('1d'),
- t.literal('7d'),
-]);
-
-type BulkActionEditPayloadTags = t.TypeOf;
-const BulkActionEditPayloadTags = t.type({
- type: t.union([
- t.literal(BulkActionEditType.add_tags),
- t.literal(BulkActionEditType.delete_tags),
- t.literal(BulkActionEditType.set_tags),
- ]),
- value: RuleTagArray,
-});
-
-export type BulkActionEditPayloadIndexPatterns = t.TypeOf<
- typeof BulkActionEditPayloadIndexPatterns
->;
-const BulkActionEditPayloadIndexPatterns = t.intersection([
- t.type({
- type: t.union([
- t.literal(BulkActionEditType.add_index_patterns),
- t.literal(BulkActionEditType.delete_index_patterns),
- t.literal(BulkActionEditType.set_index_patterns),
- ]),
- value: IndexPatternArray,
- }),
- t.exact(t.partial({ overwrite_data_views: t.boolean })),
-]);
-
-type BulkActionEditPayloadTimeline = t.TypeOf;
-const BulkActionEditPayloadTimeline = t.type({
- type: t.literal(BulkActionEditType.set_timeline),
- value: t.type({
- timeline_id: TimelineTemplateId,
- timeline_title: TimelineTemplateTitle,
- }),
-});
-
-/**
- * per rulesClient.bulkEdit rules actions operation contract (x-pack/plugins/alerting/server/rules_client/rules_client.ts)
- * normalized rule action object is expected (NormalizedAlertAction) as value for the edit operation
- */
-export type NormalizedRuleAction = t.TypeOf;
-export const NormalizedRuleAction = t.exact(
- t.intersection([
- t.type({
- group: RuleActionGroup,
- id: RuleActionId,
- params: RuleActionParams,
- }),
- t.partial({ frequency: RuleActionFrequency }),
- t.partial({ alerts_filter: RuleActionAlertsFilter }),
- ])
-);
-
-export type BulkActionEditPayloadRuleActions = t.TypeOf;
-export const BulkActionEditPayloadRuleActions = t.type({
- type: t.union([
- t.literal(BulkActionEditType.add_rule_actions),
- t.literal(BulkActionEditType.set_rule_actions),
- ]),
- value: t.intersection([
- t.partial({ throttle: ThrottleForBulkActions }),
- t.type({
- actions: t.array(NormalizedRuleAction),
- }),
- ]),
-});
-
-type BulkActionEditPayloadSchedule = t.TypeOf;
-const BulkActionEditPayloadSchedule = t.type({
- type: t.literal(BulkActionEditType.set_schedule),
- value: t.type({
- interval: TimeDuration({ allowedUnits: ['s', 'm', 'h'] }),
- lookback: TimeDuration({ allowedUnits: ['s', 'm', 'h'] }),
- }),
-});
-
-export type BulkActionEditPayload = t.TypeOf;
-export const BulkActionEditPayload = t.union([
- BulkActionEditPayloadTags,
- BulkActionEditPayloadIndexPatterns,
- BulkActionEditPayloadTimeline,
- BulkActionEditPayloadRuleActions,
- BulkActionEditPayloadSchedule,
-]);
-
-const bulkActionDuplicatePayload = t.exact(
- t.type({
- include_exceptions: t.boolean,
- include_expired_exceptions: t.boolean,
- })
-);
-
-export type BulkActionDuplicatePayload = t.TypeOf;
-
-/**
- * actions that modify rules attributes
- */
-export type BulkActionEditForRuleAttributes =
- | BulkActionEditPayloadTags
- | BulkActionEditPayloadRuleActions
- | BulkActionEditPayloadSchedule;
-
-/**
- * actions that modify rules params
- */
-export type BulkActionEditForRuleParams =
- | BulkActionEditPayloadIndexPatterns
- | BulkActionEditPayloadTimeline
- | BulkActionEditPayloadSchedule;
-
-/**
- * Request body parameters of the API route.
- */
-export type PerformBulkActionRequestBody = t.TypeOf;
-export const PerformBulkActionRequestBody = t.intersection([
- t.exact(
- t.type({
- query: t.union([RuleQuery, t.undefined]),
- })
- ),
- t.exact(t.partial({ ids: NonEmptyArray(t.string) })),
- t.union([
- t.exact(
- t.type({
- action: t.union([
- t.literal(BulkActionType.delete),
- t.literal(BulkActionType.disable),
- t.literal(BulkActionType.enable),
- t.literal(BulkActionType.export),
- ]),
- })
- ),
- t.intersection([
- t.exact(
- t.type({
- action: t.literal(BulkActionType.duplicate),
- })
- ),
- t.exact(
- t.partial({
- [BulkActionType.duplicate]: bulkActionDuplicatePayload,
- })
- ),
- ]),
- t.exact(
- t.type({
- action: t.literal(BulkActionType.edit),
- [BulkActionType.edit]: NonEmptyArray(BulkActionEditPayload),
- })
- ),
- ]),
-]);
-
-/**
- * Query string parameters of the API route.
- */
-export type PerformBulkActionRequestQuery = t.TypeOf;
-export const PerformBulkActionRequestQuery = t.exact(
- t.partial({
- dry_run: t.union([t.literal('true'), t.literal('false')]),
- })
-);
-
-export interface RuleDetailsInError {
- id: string;
- name?: string;
-}
-export interface NormalizedRuleError {
- message: string;
- status_code: number;
- err_code?: BulkActionsDryRunErrCode;
- rules: RuleDetailsInError[];
-}
-export interface BulkEditActionResults {
- updated: RuleResponse[];
- created: RuleResponse[];
- deleted: RuleResponse[];
- skipped: BulkActionSkipResult[];
-}
-
-export interface BulkEditActionSummary {
- failed: number;
- skipped: number;
- succeeded: number;
- total: number;
-}
-export interface BulkEditActionSuccessResponse {
- success: boolean;
- rules_count: number;
- attributes: {
- results: BulkEditActionResults;
- summary: BulkEditActionSummary;
- };
-}
-export interface BulkEditActionErrorResponse {
- status_code: number;
- message: string;
- attributes: {
- results: BulkEditActionResults;
- summary: BulkEditActionSummary;
- errors?: NormalizedRuleError[];
- };
-}
-
-export type BulkEditActionResponse = BulkEditActionSuccessResponse | BulkEditActionErrorResponse;
-
-export type BulkExportActionResponse = string;
-
-export type PerformBulkActionResponse = BulkEditActionResponse | BulkExportActionResponse;
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_types.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_types.ts
new file mode 100644
index 0000000000000..6e57e5abe2410
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_types.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import type {
+ BulkActionEditPayloadIndexPatterns,
+ BulkActionEditPayloadRuleActions,
+ BulkActionEditPayloadSchedule,
+ BulkActionEditPayloadTags,
+ BulkActionEditPayloadTimeline,
+} from './bulk_actions_route.gen';
+
+/**
+ * actions that modify rules attributes
+ */
+export type BulkActionEditForRuleAttributes =
+ | BulkActionEditPayloadTags
+ | BulkActionEditPayloadRuleActions
+ | BulkActionEditPayloadSchedule;
+
+/**
+ * actions that modify rules params
+ */
+export type BulkActionEditForRuleParams =
+ | BulkActionEditPayloadIndexPatterns
+ | BulkActionEditPayloadTimeline
+ | BulkActionEditPayloadSchedule;
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts
index 40955f2eba40a..2e6cff31f8f7d 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts
@@ -26,7 +26,9 @@ describe('Bulk create rules request schema', () => {
const result = BulkCreateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.name: Required, 0.description: Required, 0.risk_score: Required, 0.severity: Required, 0.type: Invalid literal value, expected \\"eql\\", and 52 more"`
+ );
});
test('single array element does validate', () => {
@@ -56,7 +58,9 @@ describe('Bulk create rules request schema', () => {
const result = BulkCreateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"`
+ );
});
test('two array elements where the first is valid but the second is invalid (risk_score) will not validate', () => {
@@ -68,7 +72,9 @@ describe('Bulk create rules request schema', () => {
const result = BulkCreateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"1.risk_score: Required, 1.type: Invalid literal value, expected \\"eql\\", 1.language: Invalid literal value, expected \\"eql\\", 1.risk_score: Required, 1.risk_score: Required, and 22 more"`
+ );
});
test('two array elements where the first is invalid (risk_score) but the second is valid will not validate', () => {
@@ -80,7 +86,9 @@ describe('Bulk create rules request schema', () => {
const result = BulkCreateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"`
+ );
});
test('two array elements where both are invalid (risk_score) will not validate', () => {
@@ -95,7 +103,7 @@ describe('Bulk create rules request schema', () => {
const result = BulkCreateRulesRequestBody.safeParse(payload);
expectParseError(result);
expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
- `"0: Invalid input, 1: Invalid input"`
+ `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 49 more"`
);
});
@@ -121,7 +129,9 @@ describe('Bulk create rules request schema', () => {
const result = BulkCreateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', and 22 more"`
+ );
});
test('You can set "note" to a string', () => {
@@ -154,6 +164,8 @@ describe('Bulk create rules request schema', () => {
const result = BulkCreateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.note: Expected string, received object, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.note: Expected string, received object, 0.note: Expected string, received object, and 22 more"`
+ );
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts
index 443a3e0862b45..d5325ad5ed13f 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts
@@ -70,6 +70,8 @@ describe('Bulk patch rules request schema', () => {
const result = BulkPatchRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"1.note: Expected string, received object, 1.note: Expected string, received object, 1.note: Expected string, received object, 1.note: Expected string, received object, 1.note: Expected string, received object, and 3 more"`
+ );
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts
index 86a3a943b6626..3fa69c6ad24dc 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts
@@ -27,7 +27,9 @@ describe('Bulk update rules request schema', () => {
const result = BulkUpdateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.name: Required, 0.description: Required, 0.risk_score: Required, 0.severity: Required, 0.type: Invalid literal value, expected \\"eql\\", and 52 more"`
+ );
});
test('single array element does validate', () => {
@@ -57,7 +59,9 @@ describe('Bulk update rules request schema', () => {
const result = BulkUpdateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"`
+ );
});
test('two array elements where the first is valid but the second is invalid (risk_score) will not validate', () => {
@@ -69,7 +73,9 @@ describe('Bulk update rules request schema', () => {
const result = BulkUpdateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"1.risk_score: Required, 1.type: Invalid literal value, expected \\"eql\\", 1.language: Invalid literal value, expected \\"eql\\", 1.risk_score: Required, 1.risk_score: Required, and 22 more"`
+ );
});
test('two array elements where the first is invalid (risk_score) but the second is valid will not validate', () => {
@@ -81,7 +87,9 @@ describe('Bulk update rules request schema', () => {
const result = BulkUpdateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 22 more"`
+ );
});
test('two array elements where both are invalid (risk_score) will not validate', () => {
@@ -96,7 +104,7 @@ describe('Bulk update rules request schema', () => {
const result = BulkUpdateRulesRequestBody.safeParse(payload);
expectParseError(result);
expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
- `"0: Invalid input, 1: Invalid input"`
+ `"0.risk_score: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.risk_score: Required, 0.risk_score: Required, and 49 more"`
);
});
@@ -122,7 +130,9 @@ describe('Bulk update rules request schema', () => {
const result = BulkUpdateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', 0.severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'madeup', and 22 more"`
+ );
});
test('You can set "namespace" to a string', () => {
@@ -165,6 +175,8 @@ describe('Bulk update rules request schema', () => {
const result = BulkUpdateRulesRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.note: Expected string, received object, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", 0.note: Expected string, received object, 0.note: Expected string, received object, and 22 more"`
+ );
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts
index d8e3c997e2279..413d83f9fee01 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts
@@ -45,7 +45,9 @@ describe('Bulk CRUD rules response schema', () => {
const result = BulkCrudRulesResponse.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.error: Required, 0: Unrecognized key(s) in object: 'author', 'created_at', 'updated_at', 'created_by', 'description', 'enabled', 'false_positives', 'from', 'immutable', 'references', 'revision', 'severity', 'severity_mapping', 'updated_by', 'tags', 'to', 'threat', 'version', 'output_index', 'max_signals', 'risk_score', 'risk_score_mapping', 'interval', 'exceptions_list', 'related_integrations', 'required_fields', 'setup', 'throttle', 'actions', 'building_block_type', 'note', 'license', 'outcome', 'alias_target_id', 'alias_purpose', 'timeline_id', 'timeline_title', 'meta', 'rule_name_override', 'timestamp_override', 'timestamp_override_fallback_disabled', 'namespace', 'investigation_fields', 'query', 'type', 'language', 'index', 'data_view_id', 'filters', 'saved_id', 'response_actions', 'alert_suppression', 0.name: Required, 0.type: Invalid literal value, expected \\"eql\\", 0.language: Invalid literal value, expected \\"eql\\", and 24 more"`
+ );
});
test('it should NOT validate an invalid error message with a deleted value', () => {
@@ -56,7 +58,9 @@ describe('Bulk CRUD rules response schema', () => {
const result = BulkCrudRulesResponse.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"0.error: Required, 0.name: Required, 0.description: Required, 0.risk_score: Required, 0.severity: Required, and 267 more"`
+ );
});
test('it should omit any extra rule props', () => {
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts
index b70b5a6a7d908..1994b3de5d453 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts
@@ -373,7 +373,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"references.0: Expected string, received number, references.0: Expected string, received number, references.0: Expected string, received number, references.0: Expected string, received number, references.0: Expected string, received number, and 3 more"`
+ );
});
test('indexes cannot be numbers', () => {
@@ -385,7 +387,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", index.0: Expected string, received number, index.0: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", index.0: Expected string, received number, and 8 more"`
+ );
});
test('saved_id is not required when type is saved_query and will validate without it', () => {
@@ -456,7 +460,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up', type: Invalid literal value, expected \\"saved_query\\", language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up', and 9 more"`
+ );
});
test('max_signals cannot be negative', () => {
@@ -518,7 +524,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"meta: Expected object, received string, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", meta: Expected object, received string, meta: Expected object, received string, and 12 more"`
+ );
});
test('filters cannot be a string', () => {
@@ -529,7 +537,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", filters: Expected array, received string, filters: Expected array, received string, type: Invalid literal value, expected \\"saved_query\\", and 10 more"`
+ );
});
test('name cannot be an empty string', () => {
@@ -631,7 +641,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"threat.0.framework: Required, threat.0.framework: Required, threat.0.framework: Required, threat.0.framework: Required, threat.0.framework: Required, and 3 more"`
+ );
});
test('threat is invalid when updated with missing tactic sub-object', () => {
@@ -655,7 +667,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"threat.0.tactic: Required, threat.0.tactic: Required, threat.0.tactic: Required, threat.0.tactic: Required, threat.0.tactic: Required, and 3 more"`
+ );
});
test('threat is valid when updated with missing technique', () => {
@@ -700,7 +714,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk', and 3 more"`
+ );
});
describe('note', () => {
@@ -744,7 +760,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"note: Expected string, received object, note: Expected string, received object, note: Expected string, received object, note: Expected string, received object, note: Expected string, received object, and 3 more"`
+ );
});
});
@@ -756,7 +774,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.group: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.group: Required, actions.0.group: Required, and 12 more"`
+ );
});
test('You cannot send in an array of actions that are missing "id"', () => {
@@ -767,7 +787,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.id: Required, actions.0.id: Required, and 12 more"`
+ );
});
test('You cannot send in an array of actions that are missing "params"', () => {
@@ -778,7 +800,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.params: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.params: Required, actions.0.params: Required, and 12 more"`
+ );
});
test('You cannot send in an array of actions that are including "actionTypeId"', () => {
@@ -796,7 +820,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"actions.0.action_type_id: Required, type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", actions.0.action_type_id: Required, actions.0.action_type_id: Required, and 12 more"`
+ );
});
describe('exception_list', () => {
@@ -862,7 +888,9 @@ describe('Patch rule request schema', () => {
const result = PatchRuleRequestBody.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"exceptions_list.0.list_id: Required, exceptions_list.0.type: Required, exceptions_list.0.namespace_type: Invalid enum value. Expected 'agnostic' | 'single', received 'not a namespace type', type: Invalid literal value, expected \\"eql\\", exceptions_list.0.list_id: Required, and 26 more"`
+ );
});
test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => {
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.gen.ts
index 01cd91216753f..2dfb54396c9ce 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.gen.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.gen.ts
@@ -6,6 +6,7 @@
*/
import { z } from 'zod';
+import { BooleanFromString } from '@kbn/zod-helpers';
/*
* NOTICE: Do not edit this file manually.
@@ -19,13 +20,7 @@ export const ExportRulesRequestQuery = z.object({
/**
* Determines whether a summary of the exported rules is returned.
*/
- exclude_export_details: z.preprocess(
- (value: unknown) => (typeof value === 'boolean' ? String(value) : value),
- z
- .enum(['true', 'false'])
- .default('false')
- .transform((value) => value === 'true')
- ),
+ exclude_export_details: BooleanFromString.optional().default(false),
/**
* File name for saving the exported rules.
*/
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts
index 49b56c6673218..783556d2076af 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts
@@ -120,7 +120,7 @@ describe('Export rules request schema', () => {
const result = ExportRulesRequestQuery.safeParse(payload);
expectParseError(result);
expect(stringifyZodError(result.error)).toEqual(
- `exclude_export_details: Invalid enum value. Expected 'true' | 'false', received 'invalid string'`
+ `exclude_export_details: Invalid enum value. Expected 'true' | 'false', received 'invalid string', exclude_export_details: Expected boolean, received string`
);
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.gen.ts
new file mode 100644
index 0000000000000..a515cf70f9513
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.gen.ts
@@ -0,0 +1,71 @@
+/*
+ * 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 { z } from 'zod';
+import { ArrayFromString } from '@kbn/zod-helpers';
+
+/*
+ * NOTICE: Do not edit this file manually.
+ * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
+ */
+
+import { SortOrder } from '../../model/sorting.gen';
+import { RuleResponse } from '../../model/rule_schema/rule_schemas.gen';
+
+export type FindRulesSortField = z.infer;
+export const FindRulesSortField = z.enum([
+ 'created_at',
+ 'createdAt',
+ 'enabled',
+ 'execution_summary.last_execution.date',
+ 'execution_summary.last_execution.metrics.execution_gap_duration_s',
+ 'execution_summary.last_execution.metrics.total_indexing_duration_ms',
+ 'execution_summary.last_execution.metrics.total_search_duration_ms',
+ 'execution_summary.last_execution.status',
+ 'name',
+ 'risk_score',
+ 'riskScore',
+ 'severity',
+ 'updated_at',
+ 'updatedAt',
+]);
+export type FindRulesSortFieldEnum = typeof FindRulesSortField.enum;
+export const FindRulesSortFieldEnum = FindRulesSortField.enum;
+
+export type FindRulesRequestQuery = z.infer;
+export const FindRulesRequestQuery = z.object({
+ fields: ArrayFromString(z.string()).optional(),
+ /**
+ * Search query
+ */
+ filter: z.string().optional(),
+ /**
+ * Field to sort by
+ */
+ sort_field: FindRulesSortField.optional(),
+ /**
+ * Sort order
+ */
+ sort_order: SortOrder.optional(),
+ /**
+ * Page number
+ */
+ page: z.coerce.number().int().min(1).optional().default(1),
+ /**
+ * Rules per page
+ */
+ per_page: z.coerce.number().int().min(0).optional().default(20),
+});
+export type FindRulesRequestQueryInput = z.input;
+
+export type FindRulesResponse = z.infer;
+export const FindRulesResponse = z.object({
+ page: z.number().int(),
+ perPage: z.number().int(),
+ total: z.number().int(),
+ data: z.array(RuleResponse),
+});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml
new file mode 100644
index 0000000000000..4fa1c14542ed0
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml
@@ -0,0 +1,98 @@
+openapi: 3.0.0
+info:
+ title: Find Rules API endpoint
+ version: 2023-10-31
+paths:
+ /api/detection_engine/rules/_find:
+ get:
+ operationId: FindRules
+ x-codegen-enabled: true
+ description: Finds rules that match the given query.
+ tags:
+ - Rules API
+ parameters:
+ - name: 'fields'
+ in: query
+ required: false
+ schema:
+ type: array
+ items:
+ type: string
+ - name: 'filter'
+ in: query
+ description: Search query
+ required: false
+ schema:
+ type: string
+ - name: 'sort_field'
+ in: query
+ description: Field to sort by
+ required: false
+ schema:
+ $ref: '#/components/schemas/FindRulesSortField'
+ - name: 'sort_order'
+ in: query
+ description: Sort order
+ required: false
+ schema:
+ $ref: '../../model/sorting.schema.yaml#/components/schemas/SortOrder'
+ - name: 'page'
+ in: query
+ description: Page number
+ required: false
+ schema:
+ type: integer
+ minimum: 1
+ default: 1
+ - name: 'per_page'
+ in: query
+ description: Rules per page
+ required: false
+ schema:
+ type: integer
+ minimum: 0
+ default: 20
+
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ page:
+ type: integer
+ perPage:
+ type: integer
+ total:
+ type: integer
+ data:
+ type: array
+ items:
+ $ref: '../../model/rule_schema/rule_schemas.schema.yaml#/components/schemas/RuleResponse'
+ required:
+ - page
+ - perPage
+ - total
+ - data
+
+components:
+ schemas:
+ FindRulesSortField:
+ type: string
+ enum:
+ - 'created_at'
+ - 'createdAt' # Legacy notation, keeping for backwards compatibility
+ - 'enabled'
+ - 'execution_summary.last_execution.date'
+ - 'execution_summary.last_execution.metrics.execution_gap_duration_s'
+ - 'execution_summary.last_execution.metrics.total_indexing_duration_ms'
+ - 'execution_summary.last_execution.metrics.total_search_duration_ms'
+ - 'execution_summary.last_execution.status'
+ - 'name'
+ - 'risk_score'
+ - 'riskScore' # Legacy notation, keeping for backwards compatibility
+ - 'severity'
+ - 'updated_at'
+ - 'updatedAt' # Legacy notation, keeping for backwards compatibility
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.test.ts
index 391826fed9923..aa4bb53ab7481 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.test.ts
@@ -5,21 +5,17 @@
* 2.0.
*/
-import { left } from 'fp-ts/lib/Either';
-import { pipe } from 'fp-ts/lib/pipeable';
-import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
-
-import { FindRulesRequestQuery } from './find_rules_route';
+import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers';
+import type { FindRulesRequestQueryInput } from './find_rules_route.gen';
+import { FindRulesRequestQuery } from './find_rules_route.gen';
describe('Find rules request schema', () => {
test('empty objects do validate', () => {
- const payload: FindRulesRequestQuery = {};
+ const payload: FindRulesRequestQueryInput = {};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual({
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual({
page: 1,
per_page: 20,
});
@@ -35,167 +31,126 @@ describe('Find rules request schema', () => {
sort_order: 'asc',
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(payload);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual(payload);
});
- test('made up parameters do not validate', () => {
- const payload: Partial & { madeUp: string } = {
+ test('made up parameters are ignored', () => {
+ const payload: Partial & { madeUp: string } = {
madeUp: 'invalid value',
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']);
- expect(message.schema).toEqual({});
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data).toEqual({
+ page: 1,
+ per_page: 20,
+ });
});
test('per_page validates', () => {
- const payload: FindRulesRequestQuery = {
+ const payload: FindRulesRequestQueryInput = {
per_page: 5,
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).per_page).toEqual(payload.per_page);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data.per_page).toEqual(payload.per_page);
});
test('page validates', () => {
- const payload: FindRulesRequestQuery = {
+ const payload: FindRulesRequestQueryInput = {
page: 5,
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).page).toEqual(payload.page);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data.page).toEqual(payload.page);
});
test('sort_field validates', () => {
- const payload: FindRulesRequestQuery = {
+ const payload: FindRulesRequestQueryInput = {
sort_field: 'name',
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).sort_field).toEqual('name');
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data.sort_field).toEqual(payload.sort_field);
});
test('fields validates with a string', () => {
- const payload: FindRulesRequestQuery = {
+ const payload: FindRulesRequestQueryInput = {
fields: ['some value'],
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).fields).toEqual(payload.fields);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data.fields).toEqual(payload.fields);
});
test('fields validates with multiple strings', () => {
- const payload: FindRulesRequestQuery = {
+ const payload: FindRulesRequestQueryInput = {
fields: ['some value 1', 'some value 2'],
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).fields).toEqual(payload.fields);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data.fields).toEqual(payload.fields);
});
test('fields does not validate with a number', () => {
- const payload: Omit & { fields: number } = {
+ const payload: Omit & { fields: number } = {
fields: 5,
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "fields"']);
- expect(message.schema).toEqual({});
- });
-
- test('per_page has a default of 20', () => {
- const payload: FindRulesRequestQuery = {};
-
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).per_page).toEqual(20);
- });
-
- test('page has a default of 1', () => {
- const payload: FindRulesRequestQuery = {};
-
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).page).toEqual(1);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toEqual('fields: Expected array, received number');
});
test('filter works with a string', () => {
- const payload: FindRulesRequestQuery = {
+ const payload: FindRulesRequestQueryInput = {
filter: 'some value 1',
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).filter).toEqual(payload.filter);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data.filter).toEqual(payload.filter);
});
test('filter does not work with a number', () => {
- const payload: Omit & { filter: number } = {
+ const payload: Omit & { filter: number } = {
filter: 5,
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "filter"']);
- expect(message.schema).toEqual({});
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toEqual('filter: Expected string, received number');
});
test('sort_order validates with desc and sort_field', () => {
- const payload: FindRulesRequestQuery = {
+ const payload: FindRulesRequestQueryInput = {
sort_order: 'desc',
sort_field: 'name',
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect((message.schema as FindRulesRequestQuery).sort_order).toEqual(payload.sort_order);
- expect((message.schema as FindRulesRequestQuery).sort_field).toEqual(payload.sort_field);
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseSuccess(result);
+ expect(result.data.sort_order).toEqual(payload.sort_order);
+ expect(result.data.sort_field).toEqual(payload.sort_field);
});
test('sort_order does not validate with a string other than asc and desc', () => {
- const payload: Omit & { sort_order: string } = {
+ const payload: Omit & { sort_order: string } = {
sort_order: 'some other string',
sort_field: 'name',
};
- const decoded = FindRulesRequestQuery.decode(payload);
- const checked = exactCheck(payload, decoded);
- const message = pipe(checked, foldLeftRight);
- expect(getPaths(left(message.errors))).toEqual([
- 'Invalid value "some other string" supplied to "sort_order"',
- ]);
- expect(message.schema).toEqual({});
+ const result = FindRulesRequestQuery.safeParse(payload);
+ expectParseError(result);
+ expect(stringifyZodError(result.error)).toEqual(
+ "sort_order: Invalid enum value. Expected 'asc' | 'desc', received 'some other string'"
+ );
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.ts
deleted file mode 100644
index 7e16b696bdd70..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.ts
+++ /dev/null
@@ -1,54 +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 * as t from 'io-ts';
-import { DefaultPerPage, DefaultPage } from '@kbn/securitysolution-io-ts-alerting-types';
-import type { RuleResponse } from '../../model';
-import { SortOrder, queryFilter, fields } from '../../model';
-
-export type FindRulesSortField = t.TypeOf;
-export const FindRulesSortField = t.union([
- t.literal('created_at'),
- t.literal('createdAt'), // Legacy notation, keeping for backwards compatibility
- t.literal('enabled'),
- t.literal('execution_summary.last_execution.date'),
- t.literal('execution_summary.last_execution.metrics.execution_gap_duration_s'),
- t.literal('execution_summary.last_execution.metrics.total_indexing_duration_ms'),
- t.literal('execution_summary.last_execution.metrics.total_search_duration_ms'),
- t.literal('execution_summary.last_execution.status'),
- t.literal('name'),
- t.literal('risk_score'),
- t.literal('riskScore'), // Legacy notation, keeping for backwards compatibility
- t.literal('severity'),
- t.literal('updated_at'),
- t.literal('updatedAt'), // Legacy notation, keeping for backwards compatibility
-]);
-
-export type FindRulesSortFieldOrUndefined = t.TypeOf;
-export const FindRulesSortFieldOrUndefined = t.union([FindRulesSortField, t.undefined]);
-
-/**
- * Query string parameters of the API route.
- */
-export type FindRulesRequestQuery = t.TypeOf;
-export const FindRulesRequestQuery = t.exact(
- t.partial({
- fields,
- filter: queryFilter,
- sort_field: FindRulesSortField,
- sort_order: SortOrder,
- page: DefaultPage, // defaults to 1
- per_page: DefaultPerPage, // defaults to 20
- })
-);
-
-export interface FindRulesResponse {
- page: number;
- perPage: number;
- total: number;
- data: RuleResponse[];
-}
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.test.ts
index 93cded33f6d94..c9fb9ce9a3524 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.test.ts
@@ -5,19 +5,19 @@
* 2.0.
*/
-import type { FindRulesRequestQuery } from './find_rules_route';
+import type { FindRulesRequestQueryInput } from './find_rules_route.gen';
import { validateFindRulesRequestQuery } from './request_schema_validation';
describe('Find rules request schema, additional validation', () => {
describe('validateFindRulesRequestQuery', () => {
test('You can have an empty sort_field and empty sort_order', () => {
- const schema: FindRulesRequestQuery = {};
+ const schema: FindRulesRequestQueryInput = {};
const errors = validateFindRulesRequestQuery(schema);
expect(errors).toEqual([]);
});
test('You can have both a sort_field and and a sort_order', () => {
- const schema: FindRulesRequestQuery = {
+ const schema: FindRulesRequestQueryInput = {
sort_field: 'name',
sort_order: 'asc',
};
@@ -26,7 +26,7 @@ describe('Find rules request schema, additional validation', () => {
});
test('You cannot have sort_field without sort_order', () => {
- const schema: FindRulesRequestQuery = {
+ const schema: FindRulesRequestQueryInput = {
sort_field: 'name',
};
const errors = validateFindRulesRequestQuery(schema);
@@ -36,7 +36,7 @@ describe('Find rules request schema, additional validation', () => {
});
test('You cannot have sort_order without sort_field', () => {
- const schema: FindRulesRequestQuery = {
+ const schema: FindRulesRequestQueryInput = {
sort_order: 'asc',
};
const errors = validateFindRulesRequestQuery(schema);
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.ts
index 769ef566d1efd..69d94be334e3f 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/request_schema_validation.ts
@@ -5,23 +5,16 @@
* 2.0.
*/
-import type { FindRulesRequestQuery } from './find_rules_route';
+import type { FindRulesRequestQueryInput } from './find_rules_route.gen';
/**
* Additional validation that is implemented outside of the schema itself.
*/
-export const validateFindRulesRequestQuery = (query: FindRulesRequestQuery): string[] => {
- return [...validateSortOrder(query)];
-};
-
-const validateSortOrder = (query: FindRulesRequestQuery): string[] => {
+export const validateFindRulesRequestQuery = (query: FindRulesRequestQueryInput): string[] => {
if (query.sort_order != null || query.sort_field != null) {
if (query.sort_order == null || query.sort_field == null) {
return ['when "sort_order" and "sort_field" must exist together or not at all'];
- } else {
- return [];
}
- } else {
- return [];
}
+ return [];
};
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.gen.ts
index d0a105e28c2c8..225179a6c0489 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.gen.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.gen.ts
@@ -6,6 +6,7 @@
*/
import { z } from 'zod';
+import { BooleanFromString } from '@kbn/zod-helpers';
/*
* NOTICE: Do not edit this file manually.
@@ -20,43 +21,19 @@ export const ImportRulesRequestQuery = z.object({
/**
* Determines whether existing rules with the same `rule_id` are overwritten.
*/
- overwrite: z.preprocess(
- (value: unknown) => (typeof value === 'boolean' ? String(value) : value),
- z
- .enum(['true', 'false'])
- .default('false')
- .transform((value) => value === 'true')
- ),
+ overwrite: BooleanFromString.optional().default(false),
/**
* Determines whether existing exception lists with the same `list_id` are overwritten.
*/
- overwrite_exceptions: z.preprocess(
- (value: unknown) => (typeof value === 'boolean' ? String(value) : value),
- z
- .enum(['true', 'false'])
- .default('false')
- .transform((value) => value === 'true')
- ),
+ overwrite_exceptions: BooleanFromString.optional().default(false),
/**
* Determines whether existing actions with the same `kibana.alert.rule.actions.id` are overwritten.
*/
- overwrite_action_connectors: z.preprocess(
- (value: unknown) => (typeof value === 'boolean' ? String(value) : value),
- z
- .enum(['true', 'false'])
- .default('false')
- .transform((value) => value === 'true')
- ),
+ overwrite_action_connectors: BooleanFromString.optional().default(false),
/**
* Generates a new list ID for each imported exception list.
*/
- as_new_list: z.preprocess(
- (value: unknown) => (typeof value === 'boolean' ? String(value) : value),
- z
- .enum(['true', 'false'])
- .default('false')
- .transform((value) => value === 'true')
- ),
+ as_new_list: BooleanFromString.optional().default(false),
});
export type ImportRulesRequestQueryInput = z.input;
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts
index 7fdab0816d650..709e63a6ec402 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts
@@ -5,7 +5,8 @@
* 2.0.
*/
-export * from './bulk_actions/bulk_actions_route';
+export * from './bulk_actions/bulk_actions_types';
+export * from './bulk_actions/bulk_actions_route.gen';
export * from './bulk_crud/bulk_create_rules/bulk_create_rules_route.gen';
export * from './bulk_crud/bulk_delete_rules/bulk_delete_rules_route.gen';
export * from './bulk_crud/bulk_patch_rules/bulk_patch_rules_route.gen';
@@ -22,7 +23,7 @@ export * from './crud/update_rule/request_schema_validation';
export * from './crud/update_rule/update_rule_route.gen';
export * from './export_rules/export_rules_details_schema';
export * from './export_rules/export_rules_route.gen';
-export * from './find_rules/find_rules_route';
+export * from './find_rules/find_rules_route.gen';
export * from './find_rules/request_schema_validation';
export * from './get_rule_management_filters/get_rule_management_filters_route';
export * from './import_rules/import_rules_route.gen';
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/index.ts
index 1494e09b9c51a..ddb132ebf64bb 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/index.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/index.ts
@@ -10,15 +10,15 @@ export * from './detection_engine_health/get_rule_health/get_rule_health_route';
export * from './detection_engine_health/get_space_health/get_space_health_route';
export * from './detection_engine_health/setup_health/setup_health_route';
export * from './detection_engine_health/model';
-export * from './rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route';
+export * from './rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.gen';
export * from './rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.gen';
export * from './urls';
-export * from './model/execution_event';
-export * from './model/execution_metrics';
+export * from './model/execution_event.gen';
+export * from './model/execution_metrics.gen';
export * from './model/execution_result.gen';
export * from './model/execution_settings';
export * from './model/execution_status.gen';
export * from './model/execution_status';
-export * from './model/execution_summary';
+export * from './model/execution_summary.gen';
export * from './model/log_level';
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.gen.ts
new file mode 100644
index 0000000000000..e493c5233a03d
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.gen.ts
@@ -0,0 +1,44 @@
+/*
+ * 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 { z } from 'zod';
+
+/*
+ * NOTICE: Do not edit this file manually.
+ * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
+ */
+
+export type LogLevel = z.infer;
+export const LogLevel = z.enum(['trace', 'debug', 'info', 'warn', 'error']);
+export type LogLevelEnum = typeof LogLevel.enum;
+export const LogLevelEnum = LogLevel.enum;
+
+/**
+ * Type of a plain rule execution event:
+- message: Simple log message of some log level, such as debug, info or error.
+- status-change: We log an event of this type each time a rule changes its status during an execution.
+- execution-metrics: We log an event of this type at the end of a rule execution. It contains various execution metrics such as search and indexing durations.
+ */
+export type RuleExecutionEventType = z.infer;
+export const RuleExecutionEventType = z.enum(['message', 'status-change', 'execution-metrics']);
+export type RuleExecutionEventTypeEnum = typeof RuleExecutionEventType.enum;
+export const RuleExecutionEventTypeEnum = RuleExecutionEventType.enum;
+
+/**
+ * Plain rule execution event. A rule can write many of them during each execution. Events can be of different types and log levels.
+
+NOTE: This is a read model of rule execution events and it is pretty generic. It contains only a subset of their fields: only those fields that are common to all types of execution events.
+ */
+export type RuleExecutionEvent = z.infer;
+export const RuleExecutionEvent = z.object({
+ timestamp: z.string().datetime(),
+ sequence: z.number().int(),
+ level: LogLevel,
+ type: RuleExecutionEventType,
+ execution_id: z.string().min(1),
+ message: z.string(),
+});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.mock.ts
index c8efaa8dd85b8..3d987356a37c9 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.mock.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.mock.ts
@@ -5,9 +5,8 @@
* 2.0.
*/
-import type { RuleExecutionEvent } from './execution_event';
-import { RuleExecutionEventType } from './execution_event';
-import { LogLevel } from './log_level';
+import type { RuleExecutionEvent } from './execution_event.gen';
+import { LogLevelEnum, RuleExecutionEventTypeEnum } from './execution_event.gen';
const DEFAULT_TIMESTAMP = '2021-12-28T10:10:00.806Z';
const DEFAULT_SEQUENCE_NUMBER = 0;
@@ -17,13 +16,13 @@ const getMessageEvent = (props: Partial = {}): RuleExecution
// Default values
timestamp: DEFAULT_TIMESTAMP,
sequence: DEFAULT_SEQUENCE_NUMBER,
- level: LogLevel.debug,
+ level: LogLevelEnum.debug,
execution_id: 'execution-id-1',
message: 'Some message',
// Overridden values
...props,
// Mandatory values for this type of event
- type: RuleExecutionEventType.message,
+ type: RuleExecutionEventTypeEnum.message,
};
};
@@ -37,8 +36,8 @@ const getRunningStatusChange = (props: Partial = {}): RuleEx
// Overridden values
...props,
// Mandatory values for this type of event
- level: LogLevel.info,
- type: RuleExecutionEventType['status-change'],
+ level: LogLevelEnum.info,
+ type: RuleExecutionEventTypeEnum['status-change'],
};
};
@@ -54,8 +53,8 @@ const getPartialFailureStatusChange = (
// Overridden values
...props,
// Mandatory values for this type of event
- level: LogLevel.warn,
- type: RuleExecutionEventType['status-change'],
+ level: LogLevelEnum.warn,
+ type: RuleExecutionEventTypeEnum['status-change'],
};
};
@@ -69,8 +68,8 @@ const getFailedStatusChange = (props: Partial = {}): RuleExe
// Overridden values
...props,
// Mandatory values for this type of event
- level: LogLevel.error,
- type: RuleExecutionEventType['status-change'],
+ level: LogLevelEnum.error,
+ type: RuleExecutionEventTypeEnum['status-change'],
};
};
@@ -84,8 +83,8 @@ const getSucceededStatusChange = (props: Partial = {}): Rule
// Overridden values
...props,
// Mandatory values for this type of event
- level: LogLevel.info,
- type: RuleExecutionEventType['status-change'],
+ level: LogLevelEnum.info,
+ type: RuleExecutionEventTypeEnum['status-change'],
};
};
@@ -99,8 +98,8 @@ const getExecutionMetricsEvent = (props: Partial = {}): Rule
// Overridden values
...props,
// Mandatory values for this type of event
- level: LogLevel.debug,
- type: RuleExecutionEventType['execution-metrics'],
+ level: LogLevelEnum.debug,
+ type: RuleExecutionEventTypeEnum['execution-metrics'],
};
};
@@ -120,7 +119,7 @@ const getSomeEvents = (): RuleExecutionEvent[] => [
getMessageEvent({
timestamp: '2021-12-28T10:10:06.806Z',
sequence: 6,
- level: LogLevel.debug,
+ level: LogLevelEnum.debug,
message: 'Rule execution started',
}),
getFailedStatusChange({
@@ -138,7 +137,7 @@ const getSomeEvents = (): RuleExecutionEvent[] => [
getMessageEvent({
timestamp: '2021-12-28T10:10:02.806Z',
sequence: 2,
- level: LogLevel.error,
+ level: LogLevelEnum.error,
message: 'Some error',
}),
getRunningStatusChange({
@@ -148,7 +147,7 @@ const getSomeEvents = (): RuleExecutionEvent[] => [
getMessageEvent({
timestamp: '2021-12-28T10:10:00.806Z',
sequence: 0,
- level: LogLevel.debug,
+ level: LogLevelEnum.debug,
message: 'Rule execution started',
}),
];
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.schema.yaml
new file mode 100644
index 0000000000000..d49a49d222401
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.schema.yaml
@@ -0,0 +1,49 @@
+openapi: '3.0.0'
+info:
+ title: Execution Event Schema
+ version: 'not applicable'
+paths: {}
+components:
+ x-codegen-enabled: true
+ schemas:
+ LogLevel:
+ type: string
+ enum: ['trace', 'debug', 'info', 'warn', 'error']
+
+ RuleExecutionEventType:
+ type: string
+ enum: ['message', 'status-change', 'execution-metrics']
+ description: |-
+ Type of a plain rule execution event:
+ - message: Simple log message of some log level, such as debug, info or error.
+ - status-change: We log an event of this type each time a rule changes its status during an execution.
+ - execution-metrics: We log an event of this type at the end of a rule execution. It contains various execution metrics such as search and indexing durations.
+
+ RuleExecutionEvent:
+ type: object
+ properties:
+ timestamp:
+ type: string
+ format: date-time
+ sequence:
+ type: integer
+ level:
+ $ref: '#/components/schemas/LogLevel'
+ type:
+ $ref: '#/components/schemas/RuleExecutionEventType'
+ execution_id:
+ type: string
+ minLength: 1
+ message:
+ type: string
+ required:
+ - timestamp
+ - sequence
+ - level
+ - type
+ - execution_id
+ - message
+ description: |-
+ Plain rule execution event. A rule can write many of them during each execution. Events can be of different types and log levels.
+
+ NOTE: This is a read model of rule execution events and it is pretty generic. It contains only a subset of their fields: only those fields that are common to all types of execution events.
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.ts
deleted file mode 100644
index 64acfb01e2e2a..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_event.ts
+++ /dev/null
@@ -1,61 +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 * as t from 'io-ts';
-import { enumeration, IsoDateString, NonEmptyString } from '@kbn/securitysolution-io-ts-types';
-import { enumFromString } from '../../../../utils/enum_from_string';
-import { TLogLevel } from './log_level';
-
-/**
- * Type of a plain rule execution event.
- */
-export enum RuleExecutionEventType {
- /**
- * Simple log message of some log level, such as debug, info or error.
- */
- 'message' = 'message',
-
- /**
- * We log an event of this type each time a rule changes its status during an execution.
- */
- 'status-change' = 'status-change',
-
- /**
- * We log an event of this type at the end of a rule execution. It contains various execution
- * metrics such as search and indexing durations.
- */
- 'execution-metrics' = 'execution-metrics',
-}
-
-export const TRuleExecutionEventType = enumeration(
- 'RuleExecutionEventType',
- RuleExecutionEventType
-);
-
-/**
- * An array of supported types of rule execution events.
- */
-export const RULE_EXECUTION_EVENT_TYPES = Object.values(RuleExecutionEventType);
-
-export const ruleExecutionEventTypeFromString = enumFromString(RuleExecutionEventType);
-
-/**
- * Plain rule execution event. A rule can write many of them during each execution. Events can be
- * of different types and log levels.
- *
- * NOTE: This is a read model of rule execution events and it is pretty generic. It contains only a
- * subset of their fields: only those fields that are common to all types of execution events.
- */
-export type RuleExecutionEvent = t.TypeOf;
-export const RuleExecutionEvent = t.type({
- timestamp: IsoDateString,
- sequence: t.number,
- level: TLogLevel,
- type: TRuleExecutionEventType,
- execution_id: NonEmptyString,
- message: t.string,
-});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.gen.ts
index 235437cc5ed68..67aac49310a7d 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.gen.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.gen.ts
@@ -15,16 +15,19 @@ import { z } from 'zod';
export type RuleExecutionMetrics = z.infer;
export const RuleExecutionMetrics = z.object({
/**
- * Total time spent searching for events
+ * Total time spent performing ES searches as measured by Kibana; includes network latency and time spent serializing/deserializing request/response
*/
total_search_duration_ms: z.number().int().min(0).optional(),
/**
- * Total time spent indexing alerts
+ * Total time spent indexing documents during current rule execution cycle
*/
total_indexing_duration_ms: z.number().int().min(0).optional(),
+ /**
+ * Total time spent enriching documents during current rule execution cycle
+ */
total_enrichment_duration_ms: z.number().int().min(0).optional(),
/**
- * Time gap between last execution and current execution
+ * Duration in seconds of execution gap
*/
execution_gap_duration_s: z.number().int().min(0).optional(),
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.schema.yaml
index 7e04ef38a0a87..985da08e1df88 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.schema.yaml
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.schema.yaml
@@ -10,17 +10,18 @@ components:
type: object
properties:
total_search_duration_ms:
- description: Total time spent searching for events
+ description: Total time spent performing ES searches as measured by Kibana; includes network latency and time spent serializing/deserializing request/response
type: integer
minimum: 0
total_indexing_duration_ms:
- description: Total time spent indexing alerts
+ description: Total time spent indexing documents during current rule execution cycle
type: integer
minimum: 0
total_enrichment_duration_ms:
+ description: Total time spent enriching documents during current rule execution cycle
type: integer
minimum: 0
execution_gap_duration_s:
- description: Time gap between last execution and current execution
+ description: Duration in seconds of execution gap
type: integer
minimum: 0
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.ts
deleted file mode 100644
index b15c76119e441..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.ts
+++ /dev/null
@@ -1,28 +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 * as t from 'io-ts';
-import { PositiveInteger } from '@kbn/securitysolution-io-ts-types';
-
-export type DurationMetric = t.TypeOf;
-export const DurationMetric = PositiveInteger;
-
-export type RuleExecutionMetrics = t.TypeOf;
-
-/**
- @property total_search_duration_ms - "total time spent performing ES searches as measured by Kibana;
- includes network latency and time spent serializing/deserializing request/response",
- @property total_indexing_duration_ms - "total time spent indexing documents during current rule execution cycle",
- @property total_enrichment_duration_ms - total time spent enriching documents during current rule execution cycle
- @property execution_gap_duration_s - "duration in seconds of execution gap"
-*/
-export const RuleExecutionMetrics = t.partial({
- total_search_duration_ms: DurationMetric,
- total_indexing_duration_ms: DurationMetric,
- total_enrichment_duration_ms: DurationMetric,
- execution_gap_duration_s: DurationMetric,
-});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts
index ae031191fd74d..903912b39cbb2 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts
@@ -6,14 +6,10 @@
*/
import type { RuleLastRunOutcomes } from '@kbn/alerting-plugin/common';
-import { enumeration } from '@kbn/securitysolution-io-ts-types';
import { assertUnreachable } from '../../../../utility_types';
import type { RuleExecutionStatus, RuleExecutionStatusOrder } from './execution_status.gen';
import { RuleExecutionStatusEnum } from './execution_status.gen';
-// TODO remove after the migration to Zod is done
-export const TRuleExecutionStatus = enumeration('RuleExecutionStatus', RuleExecutionStatusEnum);
-
export const ruleExecutionStatusToNumber = (
status: RuleExecutionStatus
): RuleExecutionStatusOrder => {
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.mock.ts
index 59482e759f902..5ffc034edd172 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.mock.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.mock.ts
@@ -6,7 +6,7 @@
*/
import { RuleExecutionStatusEnum } from './execution_status.gen';
-import type { RuleExecutionSummary } from './execution_summary';
+import type { RuleExecutionSummary } from './execution_summary.gen';
const getSummarySucceeded = (): RuleExecutionSummary => ({
last_execution: {
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.ts
deleted file mode 100644
index a747d2f021b7c..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.ts
+++ /dev/null
@@ -1,22 +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 { IsoDateString } from '@kbn/securitysolution-io-ts-types';
-import * as t from 'io-ts';
-import { RuleExecutionMetrics } from './execution_metrics';
-import { TRuleExecutionStatus } from './execution_status';
-
-export type RuleExecutionSummary = t.TypeOf;
-export const RuleExecutionSummary = t.type({
- last_execution: t.type({
- date: IsoDateString,
- status: TRuleExecutionStatus,
- status_order: t.number,
- message: t.string,
- metrics: RuleExecutionMetrics,
- }),
-});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/index.ts
index b4f003cf48228..7fbb16e206197 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/index.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/index.ts
@@ -5,10 +5,10 @@
* 2.0.
*/
-export * from './execution_event';
-export * from './execution_metrics';
+export * from './execution_event.gen';
+export * from './execution_metrics.gen';
export * from './execution_result.gen';
export * from './execution_settings';
export * from './execution_status.gen';
-export * from './execution_summary';
+export * from './execution_summary.gen';
export * from './log_level';
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/log_level.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/log_level.ts
index 495589b3cd432..e7004455160bd 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/log_level.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/log_level.ts
@@ -5,42 +5,31 @@
* 2.0.
*/
-import { enumeration } from '@kbn/securitysolution-io-ts-types';
-import { enumFromString } from '../../../../utils/enum_from_string';
import { assertUnreachable } from '../../../../utility_types';
import type { RuleExecutionStatus } from './execution_status.gen';
import { RuleExecutionStatusEnum } from './execution_status.gen';
-
-export enum LogLevel {
- 'trace' = 'trace',
- 'debug' = 'debug',
- 'info' = 'info',
- 'warn' = 'warn',
- 'error' = 'error',
-}
-
-export const TLogLevel = enumeration('LogLevel', LogLevel);
+import { LogLevel, LogLevelEnum } from './execution_event.gen';
/**
* An array of supported log levels.
*/
-export const LOG_LEVELS = Object.values(LogLevel);
+export const LOG_LEVELS = LogLevel.options;
-export const logLevelToNumber = (level: keyof typeof LogLevel | null | undefined): number => {
+export const logLevelToNumber = (level: LogLevel | null | undefined): number => {
if (!level) {
return 0;
}
switch (level) {
- case 'trace':
+ case LogLevelEnum.trace:
return 0;
- case 'debug':
+ case LogLevelEnum.debug:
return 10;
- case 'info':
+ case LogLevelEnum.info:
return 20;
- case 'warn':
+ case LogLevelEnum.warn:
return 30;
- case 'error':
+ case LogLevelEnum.error:
return 40;
default:
assertUnreachable(level);
@@ -50,34 +39,32 @@ export const logLevelToNumber = (level: keyof typeof LogLevel | null | undefined
export const logLevelFromNumber = (num: number | null | undefined): LogLevel => {
if (num === null || num === undefined || num < 10) {
- return LogLevel.trace;
+ return LogLevelEnum.trace;
}
if (num < 20) {
- return LogLevel.debug;
+ return LogLevelEnum.debug;
}
if (num < 30) {
- return LogLevel.info;
+ return LogLevelEnum.info;
}
if (num < 40) {
- return LogLevel.warn;
+ return LogLevelEnum.warn;
}
- return LogLevel.error;
+ return LogLevelEnum.error;
};
-export const logLevelFromString = enumFromString(LogLevel);
-
export const logLevelFromExecutionStatus = (status: RuleExecutionStatus): LogLevel => {
switch (status) {
case RuleExecutionStatusEnum['going to run']:
case RuleExecutionStatusEnum.running:
case RuleExecutionStatusEnum.succeeded:
- return LogLevel.info;
+ return LogLevelEnum.info;
case RuleExecutionStatusEnum['partial failure']:
- return LogLevel.warn;
+ return LogLevelEnum.warn;
case RuleExecutionStatusEnum.failed:
- return LogLevel.error;
+ return LogLevelEnum.error;
default:
assertUnreachable(status);
- return LogLevel.trace;
+ return LogLevelEnum.trace;
}
};
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.gen.ts
index 751e571aae3fd..352a8cbdf89b0 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.gen.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.gen.ts
@@ -6,48 +6,43 @@
*/
import { z } from 'zod';
+import { ArrayFromString } from '@kbn/zod-helpers';
/*
* NOTICE: Do not edit this file manually.
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
*/
-import { RuleExecutionStatus } from '../../model/execution_status.gen';
import {
- SortFieldOfRuleExecutionResult,
- RuleExecutionResult,
-} from '../../model/execution_result.gen';
+ RuleExecutionEventType,
+ LogLevel,
+ RuleExecutionEvent,
+} from '../../model/execution_event.gen';
import { SortOrder } from '../../../model/sorting.gen';
+import { PaginationResult } from '../../../model/pagination.gen';
export type GetRuleExecutionEventsRequestQuery = z.infer;
export const GetRuleExecutionEventsRequestQuery = z.object({
/**
- * Start date of the time range to query
+ * Include events of matching the search term. If omitted, all events will be included.
*/
- start: z.string().datetime(),
+ search_term: z.string().optional(),
/**
- * End date of the time range to query
+ * Include events of the specified types. If omitted, all types of events will be included.
*/
- end: z.string().datetime(),
+ event_types: ArrayFromString(RuleExecutionEventType).optional().default([]),
/**
- * Query text to filter results by
+ * Include events having these log levels. If omitted, events of all levels will be included.
*/
- query_text: z.string().optional().default(''),
+ log_levels: ArrayFromString(LogLevel).optional().default([]),
/**
- * Comma-separated list of rule execution statuses to filter results by
+ * Start date of the time range to query
*/
- status_filters: z
- .preprocess(
- (value: unknown) =>
- typeof value === 'string' ? (value === '' ? [] : value.split(',')) : value,
- z.array(RuleExecutionStatus)
- )
- .optional()
- .default([]),
+ date_start: z.string().datetime().optional(),
/**
- * Field to sort results by
+ * End date of the time range to query
*/
- sort_field: SortFieldOfRuleExecutionResult.optional().default('timestamp'),
+ date_end: z.string().datetime().optional(),
/**
* Sort order to sort results by
*/
@@ -69,9 +64,6 @@ export type GetRuleExecutionEventsRequestParams = z.infer<
typeof GetRuleExecutionEventsRequestParams
>;
export const GetRuleExecutionEventsRequestParams = z.object({
- /**
- * Saved object ID of the rule to get execution results for
- */
ruleId: z.string().min(1),
});
export type GetRuleExecutionEventsRequestParamsInput = z.input<
@@ -80,6 +72,6 @@ export type GetRuleExecutionEventsRequestParamsInput = z.input<
export type GetRuleExecutionEventsResponse = z.infer;
export const GetRuleExecutionEventsResponse = z.object({
- events: z.array(RuleExecutionResult).optional(),
- total: z.number().int().optional(),
+ events: z.array(RuleExecutionEvent),
+ pagination: PaginationResult,
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.mock.ts
index b46f8d9b13870..e730350215f8e 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.mock.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.mock.ts
@@ -6,7 +6,7 @@
*/
import { ruleExecutionEventMock } from '../../model/execution_event.mock';
-import type { GetRuleExecutionEventsResponse } from './get_rule_execution_events_route';
+import type { GetRuleExecutionEventsResponse } from './get_rule_execution_events_route.gen';
const getSomeResponse = (): GetRuleExecutionEventsResponse => {
const events = ruleExecutionEventMock.getSomeEvents();
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml
index 677213bae4f2e..990ea4ef64876 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml
@@ -14,47 +14,47 @@ paths:
- name: ruleId
in: path
required: true
- description: Saved object ID of the rule to get execution results for
schema:
type: string
minLength: 1
- - name: start
+ - name: search_term
in: query
- required: true
- description: Start date of the time range to query
- schema:
- type: string
- format: date-time
- - name: end
- in: query
- required: true
- description: End date of the time range to query
+ required: false
+ description: Include events of matching the search term. If omitted, all events will be included.
schema:
type: string
- format: date-time
- - name: query_text
+ - name: event_types
in: query
required: false
- description: Query text to filter results by
+ description: Include events of the specified types. If omitted, all types of events will be included.
schema:
- type: string
- default: ''
- - name: status_filters
+ type: array
+ items:
+ $ref: '../../model/execution_event.schema.yaml#/components/schemas/RuleExecutionEventType'
+ default: []
+ - name: log_levels
in: query
required: false
- description: Comma-separated list of rule execution statuses to filter results by
+ description: Include events having these log levels. If omitted, events of all levels will be included.
schema:
type: array
items:
- $ref: '../../model/execution_status.schema.yaml#/components/schemas/RuleExecutionStatus'
+ $ref: '../../model/execution_event.schema.yaml#/components/schemas/LogLevel'
default: []
- - name: sort_field
+ - name: date_start
in: query
required: false
- description: Field to sort results by
+ description: Start date of the time range to query
schema:
- $ref: '../../model/execution_result.schema.yaml#/components/schemas/SortFieldOfRuleExecutionResult'
- default: timestamp
+ type: string
+ format: date-time
+ - name: date_end
+ in: query
+ required: false
+ description: End date of the time range to query
+ schema:
+ type: string
+ format: date-time
- name: sort_order
in: query
required: false
@@ -87,6 +87,9 @@ paths:
events:
type: array
items:
- $ref: '../../model/execution_result.schema.yaml#/components/schemas/RuleExecutionResult'
- total:
- type: integer
+ $ref: '../../model/execution_event.schema.yaml#/components/schemas/RuleExecutionEvent'
+ pagination:
+ $ref: '../../../model/pagination.schema.yaml#/components/schemas/PaginationResult'
+ required:
+ - events
+ - pagination
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts
index ecf94032039ac..5f73b6109e820 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts
@@ -5,14 +5,11 @@
* 2.0.
*/
-import { pipe } from 'fp-ts/lib/pipeable';
-import { left } from 'fp-ts/lib/Either';
-import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
-
+import { expectParseError, expectParseSuccess } from '@kbn/zod-helpers';
import {
GetRuleExecutionEventsRequestParams,
GetRuleExecutionEventsRequestQuery,
-} from './get_rule_execution_events_route';
+} from './get_rule_execution_events_route.gen';
describe('Request schema of Get rule execution events', () => {
describe('GetRuleExecutionEventsRequestParams', () => {
@@ -22,11 +19,10 @@ describe('Request schema of Get rule execution events', () => {
ruleId: 'some id',
};
- const decoded = GetRuleExecutionEventsRequestParams.decode(input);
- const message = pipe(decoded, foldLeftRight);
+ const results = GetRuleExecutionEventsRequestParams.safeParse(input);
+ expectParseSuccess(results);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(
+ expect(results.data).toEqual(
expect.objectContaining({
ruleId: 'some id',
})
@@ -39,23 +35,21 @@ describe('Request schema of Get rule execution events', () => {
foo: 'bar', // this one is not in the schema and will be stripped
};
- const decoded = GetRuleExecutionEventsRequestParams.decode(input);
- const message = pipe(decoded, foldLeftRight);
+ const results = GetRuleExecutionEventsRequestParams.safeParse(input);
+ expectParseSuccess(results);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual({
- ruleId: 'some id',
- });
+ expect(results.data).toEqual(
+ expect.objectContaining({
+ ruleId: 'some id',
+ })
+ );
});
});
describe('Validation fails', () => {
const test = (input: unknown) => {
- const decoded = GetRuleExecutionEventsRequestParams.decode(input);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors)).length).toBeGreaterThan(0);
- expect(message.schema).toEqual({});
+ const results = GetRuleExecutionEventsRequestParams.safeParse(input);
+ expectParseError(results);
};
it('when not all the required parameters are passed', () => {
@@ -84,11 +78,10 @@ describe('Request schema of Get rule execution events', () => {
per_page: 6,
};
- const decoded = GetRuleExecutionEventsRequestQuery.decode(input);
- const message = pipe(decoded, foldLeftRight);
+ const result = GetRuleExecutionEventsRequestQuery.safeParse(input);
+ expectParseSuccess(result);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual({
+ expect(result.data).toEqual({
event_types: ['message', 'status-change'],
log_levels: ['debug', 'info', 'error'],
sort_order: 'asc',
@@ -107,11 +100,10 @@ describe('Request schema of Get rule execution events', () => {
foo: 'bar', // this one is not in the schema and will be stripped
};
- const decoded = GetRuleExecutionEventsRequestQuery.decode(input);
- const message = pipe(decoded, foldLeftRight);
+ const result = GetRuleExecutionEventsRequestQuery.safeParse(input);
+ expectParseSuccess(result);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual({
+ expect(result.data).toEqual({
event_types: ['message', 'status-change'],
log_levels: ['debug', 'info', 'error'],
sort_order: 'asc',
@@ -119,25 +111,12 @@ describe('Request schema of Get rule execution events', () => {
per_page: 6,
});
});
-
- it('when no parameters are passed (all are have default values)', () => {
- const input = {};
-
- const decoded = GetRuleExecutionEventsRequestQuery.decode(input);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual(expect.any(Object));
- });
});
describe('Validation fails', () => {
const test = (input: unknown) => {
- const decoded = GetRuleExecutionEventsRequestQuery.decode(input);
- const message = pipe(decoded, foldLeftRight);
-
- expect(getPaths(left(message.errors)).length).toBeGreaterThan(0);
- expect(message.schema).toEqual({});
+ const result = GetRuleExecutionEventsRequestQuery.safeParse(input);
+ expectParseError(result);
};
it('when invalid parameters are passed', () => {
@@ -147,21 +126,18 @@ describe('Request schema of Get rule execution events', () => {
});
});
- describe('Validation sets default values', () => {
- it('when optional parameters are not passed', () => {
- const input = {};
+ it('Validation sets default values when optional parameters are not passed', () => {
+ const input = {};
- const decoded = GetRuleExecutionEventsRequestQuery.decode(input);
- const message = pipe(decoded, foldLeftRight);
+ const result = GetRuleExecutionEventsRequestQuery.safeParse(input);
+ expectParseSuccess(result);
- expect(getPaths(left(message.errors))).toEqual([]);
- expect(message.schema).toEqual({
- event_types: [],
- log_levels: [],
- sort_order: 'desc',
- page: 1,
- per_page: 20,
- });
+ expect(result.data).toEqual({
+ event_types: [],
+ log_levels: [],
+ sort_order: 'desc',
+ page: 1,
+ per_page: 20,
});
});
});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts
deleted file mode 100644
index 628e71cf51790..0000000000000
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts
+++ /dev/null
@@ -1,60 +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 * as t from 'io-ts';
-
-import { DefaultPerPage, DefaultPage } from '@kbn/securitysolution-io-ts-alerting-types';
-import { defaultCsvArray, IsoDateString, NonEmptyString } from '@kbn/securitysolution-io-ts-types';
-
-import { DefaultSortOrderDesc, PaginationResult } from '../../../model';
-import { RuleExecutionEvent, TRuleExecutionEventType, TLogLevel } from '../../model';
-
-/**
- * URL path parameters of the API route.
- */
-export type GetRuleExecutionEventsRequestParams = t.TypeOf<
- typeof GetRuleExecutionEventsRequestParams
->;
-export const GetRuleExecutionEventsRequestParams = t.exact(
- t.type({
- ruleId: NonEmptyString,
- })
-);
-
-/**
- * Query string parameters of the API route.
- */
-export type GetRuleExecutionEventsRequestQuery = t.TypeOf<
- typeof GetRuleExecutionEventsRequestQuery
->;
-export const GetRuleExecutionEventsRequestQuery = t.exact(
- t.intersection([
- t.partial({
- search_term: NonEmptyString,
- event_types: defaultCsvArray(TRuleExecutionEventType),
- log_levels: defaultCsvArray(TLogLevel),
- date_start: IsoDateString,
- date_end: IsoDateString,
- }),
- t.type({
- sort_order: DefaultSortOrderDesc, // defaults to 'desc'
- page: DefaultPage, // defaults to 1
- per_page: DefaultPerPage, // defaults to 20
- }),
- ])
-);
-
-/**
- * Response body of the API route.
- */
-export type GetRuleExecutionEventsResponse = t.TypeOf;
-export const GetRuleExecutionEventsResponse = t.exact(
- t.type({
- events: t.array(RuleExecutionEvent),
- pagination: PaginationResult,
- })
-);
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.gen.ts
index 442c45f3e8dc9..cb8e2f1d8ffa5 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.gen.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.gen.ts
@@ -6,6 +6,7 @@
*/
import { z } from 'zod';
+import { ArrayFromString } from '@kbn/zod-helpers';
/*
* NOTICE: Do not edit this file manually.
@@ -38,14 +39,7 @@ export const GetRuleExecutionResultsRequestQuery = z.object({
/**
* Comma-separated list of rule execution statuses to filter results by
*/
- status_filters: z
- .preprocess(
- (value: unknown) =>
- typeof value === 'string' ? (value === '' ? [] : value.split(',')) : value,
- z.array(RuleExecutionStatus)
- )
- .optional()
- .default([]),
+ status_filters: ArrayFromString(RuleExecutionStatus).optional().default([]),
/**
* Field to sort results by
*/
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts
index dd1ecc4208ef7..9089efeb87d05 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts
+++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts
@@ -8,9 +8,6 @@
import * as t from 'io-ts';
import { PositiveInteger, PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import { IndexPatternArray } from '../../model/rule_schema_legacy';
export const signalsReindexOptions = t.partial({
requests_per_second: t.number,
@@ -23,7 +20,7 @@ export type SignalsReindexOptions = t.TypeOf;
export const createSignalsMigrationSchema = t.intersection([
t.exact(
t.type({
- index: IndexPatternArray,
+ index: t.array(t.string),
})
),
t.exact(signalsReindexOptions),
diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts
index 864b4613857e2..c423b2a4418bb 100644
--- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts
+++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts
@@ -21,7 +21,7 @@ import {
SavedObjectResolveAliasTargetId,
SavedObjectResolveOutcome,
} from '../../detection_engine/model/rule_schema_legacy';
-import { ErrorSchema, success, success_count as successCount } from '../../detection_engine';
+import { ErrorSchema } from './error_schema';
export const BareNoteSchema = runtimeTypes.intersection([
runtimeTypes.type({
@@ -497,8 +497,8 @@ export interface ExportTimelineNotFoundError {
export const importTimelineResultSchema = runtimeTypes.exact(
runtimeTypes.type({
- success,
- success_count: successCount,
+ success: runtimeTypes.boolean,
+ success_count: PositiveInteger,
timelines_installed: PositiveInteger,
timelines_updated: PositiveInteger,
errors: runtimeTypes.array(ErrorSchema),
diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/error_schema.mock.ts b/x-pack/plugins/security_solution/common/api/timeline/model/error_schema.mock.ts
new file mode 100644
index 0000000000000..7c24d605d5f98
--- /dev/null
+++ b/x-pack/plugins/security_solution/common/api/timeline/model/error_schema.mock.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import type { ErrorSchema } from './error_schema';
+
+export const getErrorSchemaMock = (
+ id: string = '819eded6-e9c8-445b-a647-519aea39e063'
+): ErrorSchema => ({
+ id,
+ error: {
+ status_code: 404,
+ message: 'id: "819eded6-e9c8-445b-a647-519aea39e063" not found',
+ },
+});
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts b/x-pack/plugins/security_solution/common/api/timeline/model/error_schema.test.ts
similarity index 93%
rename from x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts
rename to x-pack/plugins/security_solution/common/api/timeline/model/error_schema.test.ts
index 164f5ee854efc..8326479db9c14 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts
+++ b/x-pack/plugins/security_solution/common/api/timeline/model/error_schema.test.ts
@@ -8,9 +8,7 @@
import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
import { left } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import { ErrorSchema } from './error_schema_legacy';
+import { ErrorSchema } from './error_schema';
import { getErrorSchemaMock } from './error_schema.mock';
describe('error_schema', () => {
diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema_legacy.ts b/x-pack/plugins/security_solution/common/api/timeline/model/error_schema.ts
similarity index 69%
rename from x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema_legacy.ts
rename to x-pack/plugins/security_solution/common/api/timeline/model/error_schema.ts
index c2efee05269c1..a0ac17765c3a8 100644
--- a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema_legacy.ts
+++ b/x-pack/plugins/security_solution/common/api/timeline/model/error_schema.ts
@@ -5,22 +5,16 @@
* 2.0.
*/
-import { NonEmptyString } from '@kbn/securitysolution-io-ts-types';
+import { NonEmptyString, PositiveInteger } from '@kbn/securitysolution-io-ts-types';
import * as t from 'io-ts';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import { RuleSignatureId } from './rule_schema_legacy';
-
-import { status_code, message } from './schemas';
-
// We use id: t.string intentionally and _never_ the id from global schemas as
// sometimes echo back out the id that the user gave us and it is not guaranteed
// to be a UUID but rather just a string
const partial = t.exact(
t.partial({
id: t.string,
- rule_id: RuleSignatureId,
+ rule_id: NonEmptyString,
list_id: NonEmptyString,
item_id: NonEmptyString,
})
@@ -28,8 +22,8 @@ const partial = t.exact(
const required = t.exact(
t.type({
error: t.type({
- status_code,
- message,
+ status_code: PositiveInteger,
+ message: t.string,
}),
})
);
diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts
index c6edaf898f67f..a7460bcd70345 100644
--- a/x-pack/plugins/security_solution/common/constants.ts
+++ b/x-pack/plugins/security_solution/common/constants.ts
@@ -505,3 +505,8 @@ export const DEFAULT_ALERT_TAGS_VALUE = [
i18n.FALSE_POSITIVE,
i18n.FURTHER_INVESTIGATION_REQUIRED,
] as const;
+
+/**
+ * Max length for the comments within security solution
+ */
+export const MAX_COMMENT_LENGTH = 30000 as const;
diff --git a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.test.ts b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.test.ts
index 6bdce7573ed4c..1e2db97225580 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.test.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.test.ts
@@ -17,8 +17,8 @@ import type {
ResponseAction,
RuleResponseAction,
} from '../api/detection_engine/model/rule_response_actions';
-import { RESPONSE_ACTION_TYPES } from '../api/detection_engine/model/rule_response_actions';
-import type { NormalizedRuleAction } from '../api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { ResponseActionTypesEnum } from '../api/detection_engine/model/rule_response_actions';
+import type { NormalizedRuleAction } from '../api/detection_engine/rule_management';
import type { RuleAction } from '@kbn/alerting-plugin/common';
describe('transform_actions', () => {
@@ -93,7 +93,7 @@ describe('transform_actions', () => {
});
test('it should transform ResponseAction[] to RuleResponseAction[]', () => {
const ruleAction: ResponseAction = {
- action_type_id: RESPONSE_ACTION_TYPES.OSQUERY,
+ action_type_id: ResponseActionTypesEnum['.osquery'],
params: {
ecs_mapping: {},
saved_query_id: undefined,
@@ -117,7 +117,7 @@ describe('transform_actions', () => {
test('it should transform RuleResponseAction[] to ResponseAction[]', () => {
const alertAction: RuleResponseAction = {
- actionTypeId: RESPONSE_ACTION_TYPES.OSQUERY,
+ actionTypeId: ResponseActionTypesEnum['.osquery'],
params: {
ecsMapping: {},
savedQueryId: undefined,
diff --git a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts
index 5750f35d893e2..1f3727e6e4e0b 100644
--- a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts
+++ b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts
@@ -7,12 +7,12 @@
import type { RuleAction as AlertingRuleAction } from '@kbn/alerting-plugin/common';
import type { NormalizedAlertAction } from '@kbn/alerting-plugin/server/rules_client';
-import type { NormalizedRuleAction } from '../api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { NormalizedRuleAction } from '../api/detection_engine/rule_management';
import type {
ResponseAction,
RuleResponseAction,
} from '../api/detection_engine/model/rule_response_actions';
-import { RESPONSE_ACTION_TYPES } from '../api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../api/detection_engine/model/rule_response_actions';
import type { RuleAction } from '../api/detection_engine/model';
export const transformRuleToAlertAction = ({
@@ -63,7 +63,12 @@ export const transformNormalizedRuleToAlertAction = ({
group,
id,
params: params as AlertingRuleAction['params'],
- ...(alertsFilter && { alertsFilter }),
+ ...(alertsFilter && {
+ // We use "unknown" as the alerts filter type which is stricter than the one
+ // used in the alerting plugin (what they use is essentially "any"). So we
+ // have to to cast here
+ alertsFilter: alertsFilter as AlertingRuleAction['alertsFilter'],
+ }),
...(frequency && { frequency }),
});
@@ -85,7 +90,7 @@ export const transformRuleToAlertResponseAction = ({
action_type_id: actionTypeId,
params,
}: ResponseAction): RuleResponseAction => {
- if (actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY) {
+ if (actionTypeId === ResponseActionTypesEnum['.osquery']) {
const {
saved_query_id: savedQueryId,
ecs_mapping: ecsMapping,
@@ -113,7 +118,7 @@ export const transformAlertToRuleResponseAction = ({
actionTypeId,
params,
}: RuleResponseAction): ResponseAction => {
- if (actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY) {
+ if (actionTypeId === ResponseActionTypesEnum['.osquery']) {
const { savedQueryId, ecsMapping, packId, ...rest } = params;
return {
params: {
diff --git a/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts b/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts
index 6058f60e1e1c6..c05ca782aface 100644
--- a/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts
+++ b/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts
@@ -6,9 +6,6 @@
*/
import * as t from 'io-ts';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import { DataViewId } from '../../api/detection_engine/model/rule_schema_legacy';
import { afterKeysSchema } from '../after_keys';
import { identifierTypeSchema } from '../identifier_types';
import { riskWeightsSchema } from '../risk_weights/schema';
@@ -16,7 +13,7 @@ import { riskWeightsSchema } from '../risk_weights/schema';
export const riskScoreCalculationRequestSchema = t.exact(
t.intersection([
t.type({
- data_view_id: DataViewId,
+ data_view_id: t.string,
identifier_type: identifierTypeSchema,
range: t.type({
start: t.string,
diff --git a/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts b/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts
index c440248311636..76ee6a303532b 100644
--- a/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts
+++ b/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts
@@ -6,9 +6,6 @@
*/
import * as t from 'io-ts';
-// TODO https://github.com/elastic/security-team/issues/7491
-// eslint-disable-next-line no-restricted-imports
-import { DataViewId } from '../../api/detection_engine/model/rule_schema_legacy';
import { afterKeysSchema } from '../after_keys';
import { identifierTypeSchema } from '../identifier_types';
import { rangeSchema } from '../range';
@@ -17,7 +14,7 @@ import { riskWeightsSchema } from '../risk_weights/schema';
export const riskScorePreviewRequestSchema = t.exact(
t.intersection([
t.type({
- data_view_id: DataViewId,
+ data_view_id: t.string,
}),
t.partial({
after_keys: afterKeysSchema,
diff --git a/x-pack/plugins/security_solution/common/types/response_actions/index.ts b/x-pack/plugins/security_solution/common/types/response_actions/index.ts
index 07124b6bc5e45..35333bdc54eb7 100644
--- a/x-pack/plugins/security_solution/common/types/response_actions/index.ts
+++ b/x-pack/plugins/security_solution/common/types/response_actions/index.ts
@@ -13,7 +13,7 @@ export interface RawEventData {
_index: string;
}
-export enum RESPONSE_ACTION_TYPES {
+export enum ResponseActionTypesEnum {
OSQUERY = '.osquery',
ENDPOINT = '.endpoint',
}
@@ -34,7 +34,7 @@ export interface ExpandedEventFieldsObject {
type RuleParameters = Array<{
response_actions: Array<{
- action_type_id: RESPONSE_ACTION_TYPES;
+ action_type_id: ResponseActionTypesEnum;
params: Record;
}>;
}>;
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx
index 7323c293cd94c..edc72e92ff153 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { mount } from 'enzyme';
import type { ReactWrapper } from 'enzyme';
import React from 'react';
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx
index 289561c0bc4aa..274c649ece9dc 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/osquery_tab.tsx
@@ -20,7 +20,7 @@ import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_fe
import { useKibana } from '../../lib/kibana';
import { EventsViewType } from './event_details';
import * as i18n from './translations';
-import { RESPONSE_ACTION_TYPES } from '../../../../common/api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../../../../common/api/detection_engine/model/rule_response_actions';
const TabContentWrapper = styled.div`
height: 100%;
@@ -71,7 +71,7 @@ export const useOsqueryTab = ({
}
const osqueryResponseActions = responseActions.filter(
- (responseAction) => responseAction.action_type_id === RESPONSE_ACTION_TYPES.OSQUERY
+ (responseAction) => responseAction.action_type_id === ResponseActionTypesEnum['.osquery']
);
if (!osqueryResponseActions?.length) {
diff --git a/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_score.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_score.test.tsx
index 4bdbbdca8bdca..d8b43fa9a603b 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_score.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_score.test.tsx
@@ -15,7 +15,7 @@ import { mockAnomalies } from '../mock';
import { TestProviders } from '../../../mock/test_providers';
import { useMountAppended } from '../../../utils/use_mount_appended';
import type { Anomalies } from '../types';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
jest.mock('../../../lib/kibana');
diff --git a/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_scores.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_scores.test.tsx
index 6a72d72a9eb59..b54ec85bab0e4 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_scores.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/ml/score/anomaly_scores.test.tsx
@@ -16,7 +16,7 @@ import { TestProviders } from '../../../mock/test_providers';
import { getEmptyValue } from '../../empty_value';
import type { Anomalies } from '../types';
import { useMountAppended } from '../../../utils/use_mount_appended';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
jest.mock('../../../lib/kibana');
diff --git a/x-pack/plugins/security_solution/public/common/components/ml/score/create_descriptions_list.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml/score/create_descriptions_list.test.tsx
index c9de8aad04de8..832c60c69be87 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml/score/create_descriptions_list.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/ml/score/create_descriptions_list.test.tsx
@@ -11,7 +11,7 @@ import { mockAnomalies } from '../mock';
import { createDescriptionList } from './create_description_list';
import { EuiDescriptionList } from '@elastic/eui';
import type { Anomaly } from '../types';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
jest.mock('../../../lib/kibana');
diff --git a/x-pack/plugins/security_solution/public/common/components/popover_items/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/popover_items/index.test.tsx
index 8d7123bfe6d66..58584f4325d4e 100644
--- a/x-pack/plugins/security_solution/public/common/components/popover_items/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/popover_items/index.test.tsx
@@ -10,8 +10,7 @@ import React from 'react';
import type { PopoverItemsProps } from '.';
import { PopoverItems } from '.';
import { TestProviders } from '../../mock';
-import { render, screen } from '@testing-library/react';
-import { within } from '@testing-library/dom';
+import { render, screen, within } from '@testing-library/react';
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
const mockTags = ['Elastic', 'Endpoint', 'Data Protection', 'ML', 'Continuous Monitoring'];
diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx
index ceab08373993a..ebda7e6748ebd 100644
--- a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx
@@ -22,7 +22,7 @@ import {
} from '../../mock';
import { createStore } from '../../store';
import type { EuiSuperSelectOption } from '@elastic/eui/src/components/form/super_select/super_select_control';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { useSourcererDataView } from '../../containers/sourcerer';
import { useSignalHelpers } from '../../containers/sourcerer/use_signal_helpers';
import { TimelineId } from '../../../../common/types/timeline';
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx
index 573419676a086..63b0490b91e60 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.test.tsx
@@ -8,7 +8,7 @@
import React from 'react';
import type { ReactWrapper } from 'enzyme';
import { mount, shallow } from 'enzyme';
-import { waitFor, render } from '@testing-library/react';
+import { act, fireEvent, render, waitFor } from '@testing-library/react';
import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_schema.mock';
import { getExceptionBuilderComponentLazy } from '@kbn/lists-plugin/public';
@@ -35,6 +35,7 @@ import {
import type { AlertData } from '../../utils/types';
import { useFindRules } from '../../../rule_management/logic/use_find_rules';
import { useFindExceptionListReferences } from '../../logic/use_find_references';
+import { MAX_COMMENT_LENGTH } from '../../../../../common/constants';
jest.mock('../../../../detections/containers/detection_engine/alerts/use_signal_index');
jest.mock('../../../../common/lib/kibana');
@@ -1305,5 +1306,46 @@ describe('When the add exception modal is opened', () => {
wrapper.find('button[data-test-subj="addExceptionConfirmButton"]').getDOMNode()
).toBeDisabled();
});
+
+ test('when there is a comment error has submit button disabled', async () => {
+ const { getByLabelText, queryByText, getByTestId } = render(
+
+
+
+ );
+
+ const commentInput = getByLabelText('Comment Input');
+
+ const commentErrorMessage = `The length of the comment is too long. The maximum length is ${MAX_COMMENT_LENGTH} characters.`;
+ expect(queryByText(commentErrorMessage)).toBeNull();
+
+ // Put comment with the length above maximum allowed
+ act(() => {
+ fireEvent.change(commentInput, {
+ target: {
+ value: [...new Array(MAX_COMMENT_LENGTH + 1).keys()].map((_) => 'a').join(''),
+ },
+ });
+ fireEvent.blur(commentInput);
+ });
+ expect(queryByText(commentErrorMessage)).not.toBeNull();
+ expect(getByTestId('addExceptionConfirmButton')).toBeDisabled();
+ });
});
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx
index d4108c3eddede..9eefb96be62c9 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx
@@ -157,6 +157,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
selectedRulesToAddTo,
exceptionListsToAddTo,
newComment,
+ commentErrorExists,
itemConditionValidationErrorExists,
errorSubmitting,
expireTime,
@@ -267,6 +268,16 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
[dispatch]
);
+ const setCommentError = useCallback(
+ (errorExists: boolean): void => {
+ dispatch({
+ type: 'setCommentError',
+ errorExists,
+ });
+ },
+ [dispatch]
+ );
+
const setBulkCloseIndex = useCallback(
(index: string[] | undefined): void => {
dispatch({
@@ -445,6 +456,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
exceptionItemName.trim() === '' ||
exceptionItems.every((item) => item.entries.length === 0) ||
itemConditionValidationErrorExists ||
+ commentErrorExists ||
expireErrorExists ||
(addExceptionToRadioSelection === 'add_to_lists' && isEmpty(exceptionListsToAddTo)) ||
(addExceptionToRadioSelection === 'select_rules_to_add_to' &&
@@ -462,6 +474,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
expireErrorExists,
selectedRulesToAddTo,
listType,
+ commentErrorExists,
]
);
@@ -555,6 +568,7 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({
initialIsOpen={!!newComment}
newCommentValue={newComment}
newCommentOnChange={setComment}
+ setCommentError={setCommentError}
/>
{listType !== ExceptionListTypeEnum.ENDPOINT && (
<>
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts
index 04d13c3a1b4e9..ec8040d1fe7cc 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/reducer.ts
@@ -21,6 +21,7 @@ export interface State {
initialItems: ExceptionsBuilderExceptionItem[];
exceptionItems: ExceptionsBuilderReturnExceptionItem[];
newComment: string;
+ commentErrorExists: boolean;
addExceptionToRadioSelection: string;
itemConditionValidationErrorExists: boolean;
closeSingleAlert: boolean;
@@ -40,6 +41,7 @@ export const initialState: State = {
exceptionItems: [],
exceptionItemMeta: { name: '' },
newComment: '',
+ commentErrorExists: false,
itemConditionValidationErrorExists: false,
closeSingleAlert: false,
bulkCloseAlerts: false,
@@ -76,6 +78,10 @@ export type Action =
type: 'setComment';
comment: string;
}
+ | {
+ type: 'setCommentError';
+ errorExists: boolean;
+ }
| {
type: 'setCloseSingleAlert';
close: boolean;
@@ -127,6 +133,7 @@ export type Action =
export const createExceptionItemsReducer =
() =>
+ /* eslint complexity: ["error", 21]*/
(state: State, action: Action): State => {
switch (action.type) {
case 'setExceptionItemMeta': {
@@ -172,6 +179,14 @@ export const createExceptionItemsReducer =
newComment: comment,
};
}
+ case 'setCommentError': {
+ const { errorExists } = action;
+
+ return {
+ ...state,
+ commentErrorExists: errorExists,
+ };
+ }
case 'setCloseSingleAlert': {
const { close } = action;
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx
index faa7c1385142c..077befdad52ba 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { waitFor } from '@testing-library/react';
+import { act, fireEvent, render, waitFor } from '@testing-library/react';
import { ThemeProvider } from 'styled-components';
import type { ReactWrapper } from 'enzyme';
import { mount } from 'enzyme';
@@ -34,6 +34,7 @@ import { useFetchIndexPatterns } from '../../logic/use_exception_flyout_data';
import { useCreateOrUpdateException } from '../../logic/use_create_update_exception';
import { useFindExceptionListReferences } from '../../logic/use_find_references';
import * as i18n from './translations';
+import { MAX_COMMENT_LENGTH } from '../../../../../common/constants';
const mockTheme = getMockTheme({
eui: {
@@ -693,5 +694,60 @@ describe('When the edit exception modal is opened', () => {
wrapper.find('button[data-test-subj="editExceptionConfirmButton"]').getDOMNode()
).toBeDisabled();
});
+
+ test('when there is a comment error has submit button disabled', async () => {
+ const { getByLabelText, queryByText, getByTestId } = render(
+
+
+
+ );
+
+ const commentInput = getByLabelText('Comment Input');
+
+ const commentErrorMessage = `The length of the comment is too long. The maximum length is ${MAX_COMMENT_LENGTH} characters.`;
+ expect(queryByText(commentErrorMessage)).toBeNull();
+
+ // Put comment with the length above maximum allowed
+ act(() => {
+ fireEvent.change(commentInput, {
+ target: {
+ value: [...new Array(MAX_COMMENT_LENGTH + 1).keys()].map((_) => 'a').join(''),
+ },
+ });
+ fireEvent.blur(commentInput);
+ });
+ expect(queryByText(commentErrorMessage)).not.toBeNull();
+ expect(getByTestId('editExceptionConfirmButton')).toBeDisabled();
+ });
});
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx
index 4d9e7c3bbc4ef..6d2526cdbf239 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/index.tsx
@@ -117,6 +117,7 @@ const EditExceptionFlyoutComponent: React.FC = ({
exceptionItems,
exceptionItemMeta: { name: exceptionItemName },
newComment,
+ commentErrorExists,
bulkCloseAlerts,
disableBulkClose,
bulkCloseIndex,
@@ -129,6 +130,7 @@ const EditExceptionFlyoutComponent: React.FC = ({
exceptionItems: [itemToEdit],
exceptionItemMeta: { name: itemToEdit.name },
newComment: '',
+ commentErrorExists: false,
bulkCloseAlerts: false,
disableBulkClose: true,
bulkCloseIndex: undefined,
@@ -197,6 +199,16 @@ const EditExceptionFlyoutComponent: React.FC = ({
[dispatch]
);
+ const setCommentError = useCallback(
+ (errorExists: boolean): void => {
+ dispatch({
+ type: 'setCommentError',
+ errorExists,
+ });
+ },
+ [dispatch]
+ );
+
const setBulkCloseAlerts = useCallback(
(bulkClose: boolean): void => {
dispatch({
@@ -337,8 +349,17 @@ const EditExceptionFlyoutComponent: React.FC = ({
exceptionItems.every((item) => item.entries.length === 0) ||
isLoading ||
entryErrorExists ||
+ expireErrorExists ||
+ commentErrorExists,
+ [
+ isLoading,
+ entryErrorExists,
+ exceptionItems,
+ isSubmitting,
+ isClosingAlerts,
expireErrorExists,
- [isLoading, entryErrorExists, exceptionItems, isSubmitting, isClosingAlerts, expireErrorExists]
+ commentErrorExists,
+ ]
);
return (
@@ -398,6 +419,7 @@ const EditExceptionFlyoutComponent: React.FC = ({
exceptionItemComments={itemToEdit.comments}
newCommentValue={newComment}
newCommentOnChange={setComment}
+ setCommentError={setCommentError}
/>
{listType !== ExceptionListTypeEnum.ENDPOINT && (
<>
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts
index e08b3c8d135c0..e6dee3af16572 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/edit_exception_flyout/reducer.ts
@@ -12,6 +12,7 @@ export interface State {
exceptionItems: ExceptionsBuilderReturnExceptionItem[];
exceptionItemMeta: { name: string };
newComment: string;
+ commentErrorExists: boolean;
bulkCloseAlerts: boolean;
disableBulkClose: boolean;
bulkCloseIndex: string[] | undefined;
@@ -29,6 +30,10 @@ export type Action =
type: 'setComment';
comment: string;
}
+ | {
+ type: 'setCommentError';
+ errorExists: boolean;
+ }
| {
type: 'setBulkCloseAlerts';
bulkClose: boolean;
@@ -81,6 +86,14 @@ export const createExceptionItemsReducer =
newComment: comment,
};
}
+ case 'setCommentError': {
+ const { errorExists } = action;
+
+ return {
+ ...state,
+ commentErrorExists: errorExists,
+ };
+ }
case 'setBulkCloseAlerts': {
const { bulkClose } = action;
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.test.tsx
index 7afa5e5a7eef0..8862c626ea6e4 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.test.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.test.tsx
@@ -6,9 +6,8 @@
*/
import React from 'react';
-import { fireEvent, render as rTLRender } from '@testing-library/react';
-import { waitFor } from '@testing-library/dom';
-import { act, renderHook } from '@testing-library/react-hooks';
+import { fireEvent, render as rTLRender, waitFor, act } from '@testing-library/react';
+import { renderHook } from '@testing-library/react-hooks';
import type { EuiTableFieldDataColumnType } from '@elastic/eui';
import type { Rule } from '../../../../rule_management/logic/types';
import { getRulesSchemaMock } from '../../../../../../common/api/detection_engine/model/rule_schema/mocks';
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx
index 47933db0b3522..6dd8684eaeaac 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.test.tsx
@@ -6,6 +6,7 @@
*/
import React from 'react';
+import { act, fireEvent, render } from '@testing-library/react';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { EuiTextArea } from '@elastic/eui';
@@ -13,6 +14,7 @@ import { ExceptionItemComments } from '.';
import { TestProviders } from '../../../../common/mock';
import { useCurrentUser } from '../../../../common/lib/kibana';
import { shallow } from 'enzyme';
+import { MAX_COMMENT_LENGTH } from '../../../../../common/constants';
jest.mock('../../../../common/lib/kibana');
@@ -38,6 +40,7 @@ describe('ExceptionItemComments', () => {
);
@@ -65,6 +68,7 @@ describe('ExceptionItemComments', () => {
);
@@ -92,6 +96,7 @@ describe('ExceptionItemComments', () => {
);
@@ -106,6 +111,7 @@ describe('ExceptionItemComments', () => {
);
@@ -122,6 +128,7 @@ describe('ExceptionItemComments', () => {
);
@@ -152,10 +159,53 @@ describe('ExceptionItemComments', () => {
]}
newCommentValue={''}
newCommentOnChange={mockOnCommentChange}
+ setCommentError={jest.fn()}
/>
);
expect(wrapper.find('[data-test-subj="exceptionItemCommentsAccordion"]').exists()).toBeTruthy();
});
+
+ it('it calls setCommentError on comment error update change', async () => {
+ const mockSetCommentError = jest.fn();
+ const { getByLabelText, queryByText } = render(
+
+
+
+ );
+
+ const commentInput = getByLabelText('Comment Input');
+
+ const commentErrorMessage = `The length of the comment is too long. The maximum length is ${MAX_COMMENT_LENGTH} characters.`;
+ expect(queryByText(commentErrorMessage)).toBeNull();
+
+ // Put comment with the length above maximum allowed
+ act(() => {
+ fireEvent.change(commentInput, {
+ target: {
+ value: [...new Array(MAX_COMMENT_LENGTH + 1).keys()].map((_) => 'a').join(''),
+ },
+ });
+ fireEvent.blur(commentInput);
+ });
+ expect(queryByText(commentErrorMessage)).not.toBeNull();
+ expect(mockSetCommentError).toHaveBeenCalledWith(true);
+
+ // Put comment with the allowed length
+ act(() => {
+ fireEvent.change(commentInput, {
+ target: {
+ value: 'Updating my new comment',
+ },
+ });
+ fireEvent.blur(commentInput);
+ });
+ expect(queryByText(commentErrorMessage)).toBeNull();
+ expect(mockSetCommentError).toHaveBeenCalledWith(false);
+ });
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx
index 0f32e2b4d1ab8..f262c7a07754a 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/index.tsx
@@ -5,19 +5,21 @@
* 2.0.
*/
-import React, { memo, useState, useCallback, useMemo } from 'react';
+import React, { memo, useState, useCallback, useMemo, useEffect } from 'react';
import styled, { css } from 'styled-components';
import type { EuiCommentProps } from '@elastic/eui';
import {
EuiTextArea,
EuiFlexGroup,
EuiFlexItem,
+ EuiFormRow,
EuiAvatar,
EuiAccordion,
EuiCommentList,
EuiText,
} from '@elastic/eui';
import type { Comment } from '@kbn/securitysolution-io-ts-list-types';
+import { MAX_COMMENT_LENGTH } from '../../../../../common/constants';
import * as i18n from './translations';
import { useCurrentUser } from '../../../../common/lib/kibana';
import { getFormattedComments } from '../../utils/helpers';
@@ -28,6 +30,7 @@ interface ExceptionItemCommentsProps {
accordionTitle?: JSX.Element;
initialIsOpen?: boolean;
newCommentOnChange: (value: string) => void;
+ setCommentError: (errorExists: boolean) => void;
}
const COMMENT_ACCORDION_BUTTON_CLASS_NAME = 'exceptionCommentAccordionButton';
@@ -53,8 +56,11 @@ export const ExceptionItemComments = memo(function ExceptionItemComments({
accordionTitle,
initialIsOpen = false,
newCommentOnChange,
+ setCommentError,
}: ExceptionItemCommentsProps) {
+ const [errorExists, setErrorExists] = useState(false);
const [shouldShowComments, setShouldShowComments] = useState(false);
+
const currentUser = useCurrentUser();
const fullName = currentUser?.fullName;
const userName = currentUser?.username;
@@ -73,9 +79,14 @@ export const ExceptionItemComments = memo(function ExceptionItemComments({
return userName && userName.length > 0 ? userName : i18n.UNKNOWN_AVATAR_NAME;
}, [fullName, userEmail, userName]);
+ useEffect(() => {
+ setCommentError(errorExists);
+ }, [errorExists, setCommentError]);
+
const handleOnChange = useCallback(
(event: React.ChangeEvent) => {
newCommentOnChange(event.target.value);
+ setErrorExists(event.target.value.length > MAX_COMMENT_LENGTH);
},
[newCommentOnChange]
);
@@ -121,14 +132,20 @@ export const ExceptionItemComments = memo(function ExceptionItemComments({
-
+
+
+
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/translations.ts
index afe20c6aada98..90c3d9bd0bc48 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/translations.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/item_comments/translations.ts
@@ -32,3 +32,10 @@ export const COMMENTS_HIDE = (comments: number) =>
values: { comments },
defaultMessage: 'Hide ({comments}) {comments, plural, =1 {Comment} other {Comments}}',
});
+
+export const COMMENT_MAX_LENGTH_ERROR = (length: number) =>
+ i18n.translate('xpack.securitySolution.rule_exceptions.itemComments.maxLengthError', {
+ values: { length },
+ defaultMessage:
+ 'The length of the comment is too long. The maximum length is {length} characters.',
+ });
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts
index 9e09a1754a04d..226d0a2bd16ed 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.test.ts
@@ -16,9 +16,9 @@ import {
getRulesSchemaMock,
} from '../../../../common/api/detection_engine/model/rule_schema/mocks';
import {
- BulkActionType,
- BulkActionEditType,
-} from '../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+ BulkActionTypeEnum,
+ BulkActionEditTypeEnum,
+} from '../../../../common/api/detection_engine/rule_management';
import { rulesMock } from '../logic/mock';
import type { FindRulesReferencedByExceptionsListProp } from '../logic/types';
@@ -701,7 +701,9 @@ describe('Detections Rules API', () => {
});
test('passes a query', async () => {
- await performBulkAction({ bulkAction: { type: BulkActionType.enable, query: 'some query' } });
+ await performBulkAction({
+ bulkAction: { type: BulkActionTypeEnum.enable, query: 'some query' },
+ });
expect(fetchMock).toHaveBeenCalledWith(
'/api/detection_engine/rules/_bulk_action',
@@ -720,7 +722,7 @@ describe('Detections Rules API', () => {
test('passes ids', async () => {
await performBulkAction({
- bulkAction: { type: BulkActionType.disable, ids: ['ruleId1', 'ruleId2'] },
+ bulkAction: { type: BulkActionTypeEnum.disable, ids: ['ruleId1', 'ruleId2'] },
});
expect(fetchMock).toHaveBeenCalledWith(
@@ -741,10 +743,10 @@ describe('Detections Rules API', () => {
test('passes edit payload', async () => {
await performBulkAction({
bulkAction: {
- type: BulkActionType.edit,
+ type: BulkActionTypeEnum.edit,
ids: ['ruleId1'],
editPayload: [
- { type: BulkActionEditType.add_index_patterns, value: ['some-index-pattern'] },
+ { type: BulkActionEditTypeEnum.add_index_patterns, value: ['some-index-pattern'] },
],
},
});
@@ -767,7 +769,7 @@ describe('Detections Rules API', () => {
test('executes dry run', async () => {
await performBulkAction({
- bulkAction: { type: BulkActionType.disable, query: 'some query' },
+ bulkAction: { type: BulkActionTypeEnum.disable, query: 'some query' },
dryRun: true,
});
@@ -787,7 +789,7 @@ describe('Detections Rules API', () => {
test('returns result', async () => {
const result = await performBulkAction({
bulkAction: {
- type: BulkActionType.disable,
+ type: BulkActionTypeEnum.disable,
query: 'some query',
},
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts
index 860e0fc86e850..70f0a56ef74cd 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts
@@ -27,12 +27,16 @@ import type {
ReviewRuleInstallationResponseBody,
} from '../../../../common/api/detection_engine/prebuilt_rules';
import type {
+ BulkDuplicateRules,
+ BulkActionEditPayload,
+ BulkActionType,
CoverageOverviewResponse,
GetRuleManagementFiltersResponse,
} from '../../../../common/api/detection_engine/rule_management';
import {
RULE_MANAGEMENT_FILTERS_URL,
RULE_MANAGEMENT_COVERAGE_OVERVIEW_URL,
+ BulkActionTypeEnum,
} from '../../../../common/api/detection_engine/rule_management';
import type { BulkActionsDryRunErrCode } from '../../../../common/constants';
import {
@@ -54,11 +58,6 @@ import {
import type { RulesReferencedByExceptionListsSchema } from '../../../../common/api/detection_engine/rule_exceptions';
import { DETECTION_ENGINE_RULES_EXCEPTIONS_REFERENCE_URL } from '../../../../common/api/detection_engine/rule_exceptions';
-import type {
- BulkActionDuplicatePayload,
- BulkActionEditPayload,
-} from '../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import { BulkActionType } from '../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
import type { PreviewResponse, RuleResponse } from '../../../../common/api/detection_engine';
import { KibanaServices } from '../../../common/lib/kibana';
@@ -331,18 +330,18 @@ export type QueryOrIds = { query: string; ids?: undefined } | { query?: undefine
type PlainBulkAction = {
type: Exclude<
BulkActionType,
- BulkActionType.edit | BulkActionType.export | BulkActionType.duplicate
+ BulkActionTypeEnum['edit'] | BulkActionTypeEnum['export'] | BulkActionTypeEnum['duplicate']
>;
} & QueryOrIds;
type EditBulkAction = {
- type: BulkActionType.edit;
+ type: BulkActionTypeEnum['edit'];
editPayload: BulkActionEditPayload[];
} & QueryOrIds;
type DuplicateBulkAction = {
- type: BulkActionType.duplicate;
- duplicatePayload?: BulkActionDuplicatePayload;
+ type: BulkActionTypeEnum['duplicate'];
+ duplicatePayload?: BulkDuplicateRules['duplicate'];
} & QueryOrIds;
export type BulkAction = PlainBulkAction | EditBulkAction | DuplicateBulkAction;
@@ -368,9 +367,9 @@ export async function performBulkAction({
action: bulkAction.type,
query: bulkAction.query,
ids: bulkAction.ids,
- edit: bulkAction.type === BulkActionType.edit ? bulkAction.editPayload : undefined,
+ edit: bulkAction.type === BulkActionTypeEnum.edit ? bulkAction.editPayload : undefined,
duplicate:
- bulkAction.type === BulkActionType.duplicate ? bulkAction.duplicatePayload : undefined,
+ bulkAction.type === BulkActionTypeEnum.duplicate ? bulkAction.duplicatePayload : undefined,
};
return KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_BULK_ACTION, {
@@ -392,7 +391,7 @@ export type BulkExportResponse = Blob;
*/
export async function bulkExportRules(queryOrIds: QueryOrIds): Promise {
const params = {
- action: BulkActionType.export,
+ action: BulkActionTypeEnum.export,
query: queryOrIds.query,
ids: queryOrIds.ids,
};
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts
index 1a52bbb0a8194..9e54e41f1b091 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_bulk_action_mutation.ts
@@ -7,7 +7,7 @@
import type { UseMutationOptions } from '@tanstack/react-query';
import { useMutation } from '@tanstack/react-query';
import type { IHttpFetchError } from '@kbn/core/public';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import type { BulkActionErrorResponse, BulkActionResponse, PerformBulkActionProps } from '../api';
import { performBulkAction } from '../api';
import { DETECTION_ENGINE_RULES_BULK_ACTION } from '../../../../../common/constants';
@@ -59,8 +59,8 @@ export const useBulkActionMutation = (
response?.attributes?.results?.updated ?? error?.body?.attributes?.results?.updated;
switch (actionType) {
- case BulkActionType.enable:
- case BulkActionType.disable: {
+ case BulkActionTypeEnum.enable:
+ case BulkActionTypeEnum.disable: {
invalidateFetchRuleByIdQuery();
invalidateFetchCoverageOverviewQuery();
if (updatedRules) {
@@ -72,7 +72,7 @@ export const useBulkActionMutation = (
}
break;
}
- case BulkActionType.delete:
+ case BulkActionTypeEnum.delete:
invalidateFindRulesQuery();
invalidateFetchRuleByIdQuery();
invalidateFetchRuleManagementFilters();
@@ -81,12 +81,12 @@ export const useBulkActionMutation = (
invalidateFetchPrebuiltRulesUpgradeReviewQuery();
invalidateFetchCoverageOverviewQuery();
break;
- case BulkActionType.duplicate:
+ case BulkActionTypeEnum.duplicate:
invalidateFindRulesQuery();
invalidateFetchRuleManagementFilters();
invalidateFetchCoverageOverviewQuery();
break;
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
if (updatedRules) {
// We have a list of updated rules, no need to invalidate all
updateRulesCache(updatedRules);
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/translations.ts
index 40877d8fcb2fd..99bad79536bd7 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/translations.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/translations.ts
@@ -6,54 +6,57 @@
*/
import type { HTTPError } from '../../../../../common/detection_engine/types';
-import type { BulkActionEditPayload } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import {
- BulkActionEditType,
+import type {
+ BulkActionEditPayload,
BulkActionType,
-} from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+} from '../../../../../common/api/detection_engine/rule_management';
+import {
+ BulkActionEditTypeEnum,
+ BulkActionTypeEnum,
+} from '../../../../../common/api/detection_engine/rule_management';
import * as i18n from '../../../../detections/pages/detection_engine/rules/translations';
import type { BulkActionResponse, BulkActionSummary } from '../../api/api';
export function summarizeBulkSuccess(action: BulkActionType): string {
switch (action) {
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
return i18n.RULES_BULK_EXPORT_SUCCESS;
- case BulkActionType.duplicate:
+ case BulkActionTypeEnum.duplicate:
return i18n.RULES_BULK_DUPLICATE_SUCCESS;
- case BulkActionType.delete:
+ case BulkActionTypeEnum.delete:
return i18n.RULES_BULK_DELETE_SUCCESS;
- case BulkActionType.enable:
+ case BulkActionTypeEnum.enable:
return i18n.RULES_BULK_ENABLE_SUCCESS;
- case BulkActionType.disable:
+ case BulkActionTypeEnum.disable:
return i18n.RULES_BULK_DISABLE_SUCCESS;
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
return i18n.RULES_BULK_EDIT_SUCCESS;
}
}
export function explainBulkSuccess(
- action: Exclude,
+ action: Exclude,
summary: BulkActionSummary
): string {
switch (action) {
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
return getExportSuccessToastMessage(summary.succeeded, summary.total);
- case BulkActionType.duplicate:
+ case BulkActionTypeEnum.duplicate:
return i18n.RULES_BULK_DUPLICATE_SUCCESS_DESCRIPTION(summary.succeeded);
- case BulkActionType.delete:
+ case BulkActionTypeEnum.delete:
return i18n.RULES_BULK_DELETE_SUCCESS_DESCRIPTION(summary.succeeded);
- case BulkActionType.enable:
+ case BulkActionTypeEnum.enable:
return i18n.RULES_BULK_ENABLE_SUCCESS_DESCRIPTION(summary.succeeded);
- case BulkActionType.disable:
+ case BulkActionTypeEnum.disable:
return i18n.RULES_BULK_DISABLE_SUCCESS_DESCRIPTION(summary.succeeded);
}
}
@@ -67,9 +70,9 @@ export function explainBulkEditSuccess(
if (
editPayload.some(
(x) =>
- x.type === BulkActionEditType.add_index_patterns ||
- x.type === BulkActionEditType.set_index_patterns ||
- x.type === BulkActionEditType.delete_index_patterns
+ x.type === BulkActionEditTypeEnum.add_index_patterns ||
+ x.type === BulkActionEditTypeEnum.set_index_patterns ||
+ x.type === BulkActionEditTypeEnum.delete_index_patterns
)
) {
return `${i18n.RULES_BULK_EDIT_SUCCESS_DESCRIPTION(
@@ -83,22 +86,22 @@ export function explainBulkEditSuccess(
export function summarizeBulkError(action: BulkActionType): string {
switch (action) {
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
return i18n.RULES_BULK_EXPORT_FAILURE;
- case BulkActionType.duplicate:
+ case BulkActionTypeEnum.duplicate:
return i18n.RULES_BULK_DUPLICATE_FAILURE;
- case BulkActionType.delete:
+ case BulkActionTypeEnum.delete:
return i18n.RULES_BULK_DELETE_FAILURE;
- case BulkActionType.enable:
+ case BulkActionTypeEnum.enable:
return i18n.RULES_BULK_ENABLE_FAILURE;
- case BulkActionType.disable:
+ case BulkActionTypeEnum.disable:
return i18n.RULES_BULK_DISABLE_FAILURE;
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
return i18n.RULES_BULK_EDIT_FAILURE;
}
}
@@ -112,22 +115,22 @@ export function explainBulkError(action: BulkActionType, error: HTTPError): stri
}
switch (action) {
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
return i18n.RULES_BULK_EXPORT_FAILURE_DESCRIPTION(summary.failed);
- case BulkActionType.duplicate:
+ case BulkActionTypeEnum.duplicate:
return i18n.RULES_BULK_DUPLICATE_FAILURE_DESCRIPTION(summary.failed);
- case BulkActionType.delete:
+ case BulkActionTypeEnum.delete:
return i18n.RULES_BULK_DELETE_FAILURE_DESCRIPTION(summary.failed);
- case BulkActionType.enable:
+ case BulkActionTypeEnum.enable:
return i18n.RULES_BULK_ENABLE_FAILURE_DESCRIPTION(summary.failed);
- case BulkActionType.disable:
+ case BulkActionTypeEnum.disable:
return i18n.RULES_BULK_DISABLE_FAILURE_DESCRIPTION(summary.failed);
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
return i18n.RULES_BULK_EDIT_FAILURE_DESCRIPTION(summary.failed, summary.skipped);
}
}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts
index 1ac62109cc626..968b40c7a6026 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts
@@ -6,7 +6,7 @@
*/
import { renderHook } from '@testing-library/react-hooks';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import { useRulesTableContextOptional } from '../../../rule_management_ui/components/rules_table/rules_table/rules_table_context';
import { useBulkExportMutation } from '../../api/hooks/use_bulk_export_mutation';
@@ -92,7 +92,7 @@ describe('useBulkExport', () => {
expect(setLoadingRules).toHaveBeenCalledWith({
ids: ['ruleId1', 'ruleId2'],
- action: BulkActionType.export,
+ action: BulkActionTypeEnum.export,
});
});
@@ -101,7 +101,7 @@ describe('useBulkExport', () => {
expect(setLoadingRules).toHaveBeenCalledWith({
ids: [],
- action: BulkActionType.export,
+ action: BulkActionTypeEnum.export,
});
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.ts
index 5554ba2296302..651b2b0e4b86c 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.ts
@@ -6,7 +6,7 @@
*/
import { useCallback } from 'react';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { useRulesTableContextOptional } from '../../../rule_management_ui/components/rules_table/rules_table/rules_table_context';
import { useBulkExportMutation } from '../../api/hooks/use_bulk_export_mutation';
import { useShowBulkErrorToast } from './use_show_bulk_error_toast';
@@ -24,12 +24,12 @@ export function useBulkExport() {
async (queryOrIds: QueryOrIds) => {
try {
setLoadingRules?.({
- ids: queryOrIds.ids ?? guessRuleIdsForBulkAction(BulkActionType.export),
- action: BulkActionType.export,
+ ids: queryOrIds.ids ?? guessRuleIdsForBulkAction(BulkActionTypeEnum.export),
+ action: BulkActionTypeEnum.export,
});
return await mutateAsync(queryOrIds);
} catch (error) {
- showBulkErrorToast({ actionType: BulkActionType.export, error });
+ showBulkErrorToast({ actionType: BulkActionTypeEnum.export, error });
} finally {
setLoadingRules?.({ ids: [], action: null });
}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_download_exported_rules.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_download_exported_rules.ts
index 94c26b278d1b1..7be106090bcfa 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_download_exported_rules.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_download_exported_rules.ts
@@ -6,7 +6,7 @@
*/
import { useCallback } from 'react';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { downloadBlob } from '../../../../common/utils/download_blob';
import * as i18n from '../../../../detections/pages/detection_engine/rules/translations';
import { getExportedRulesCounts } from '../../../rule_management_ui/components/rules_table/helpers';
@@ -27,11 +27,11 @@ export function useDownloadExportedRules() {
try {
downloadBlob(response, DEFAULT_EXPORT_FILENAME);
showBulkSuccessToast({
- actionType: BulkActionType.export,
+ actionType: BulkActionTypeEnum.export,
summary: await getExportedRulesCounts(response),
});
} catch (error) {
- showBulkErrorToast({ actionType: BulkActionType.export, error });
+ showBulkErrorToast({ actionType: BulkActionTypeEnum.export, error });
}
},
[showBulkSuccessToast, showBulkErrorToast]
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts
index 3c211247b94ec..6309d8b629bc2 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts
@@ -6,7 +6,7 @@
*/
import { renderHook } from '@testing-library/react-hooks';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../../common/lib/telemetry';
import { useBulkActionMutation } from '../../api/hooks/use_bulk_action_mutation';
@@ -61,7 +61,7 @@ describe('useExecuteBulkAction', () => {
it('executes bulk action', async () => {
const bulkAction = {
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
query: 'some query',
} as const;
@@ -73,7 +73,7 @@ describe('useExecuteBulkAction', () => {
describe('state handlers', () => {
it('shows success toast upon completion', async () => {
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
ids: ['ruleId1'],
});
@@ -84,7 +84,7 @@ describe('useExecuteBulkAction', () => {
it('does not shows success toast upon completion if suppressed', async () => {
await executeBulkAction(
{
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
ids: ['ruleId1'],
},
{ suppressSuccessToast: true }
@@ -100,7 +100,7 @@ describe('useExecuteBulkAction', () => {
});
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
ids: ['ruleId1'],
});
@@ -126,31 +126,31 @@ describe('useExecuteBulkAction', () => {
it('sets the loading state before execution', async () => {
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
ids: ['ruleId1', 'ruleId2'],
});
expect(setLoadingRules).toHaveBeenCalledWith({
ids: ['ruleId1', 'ruleId2'],
- action: BulkActionType.enable,
+ action: BulkActionTypeEnum.enable,
});
});
it('sets the empty loading state before execution when query is set', async () => {
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
query: 'some query',
});
expect(setLoadingRules).toHaveBeenCalledWith({
ids: [],
- action: BulkActionType.enable,
+ action: BulkActionTypeEnum.enable,
});
});
it('clears loading state for the processing rules after execution', async () => {
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
ids: ['ruleId1', 'ruleId2'],
});
@@ -163,7 +163,7 @@ describe('useExecuteBulkAction', () => {
});
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
ids: ['ruleId1', 'ruleId2'],
});
@@ -174,7 +174,7 @@ describe('useExecuteBulkAction', () => {
describe('telemetry', () => {
it('sends for enable action', async () => {
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
query: 'some query',
});
@@ -184,7 +184,7 @@ describe('useExecuteBulkAction', () => {
it('sends for disable action', async () => {
await executeBulkAction({
- type: BulkActionType.disable,
+ type: BulkActionTypeEnum.disable,
query: 'some query',
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.ts
index 9fbfb0c310f20..0a294647aad3f 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.ts
@@ -9,7 +9,8 @@ import type { NavigateToAppOptions } from '@kbn/core/public';
import { useCallback } from 'react';
import type { BulkActionResponse } from '..';
import { APP_UI_ID } from '../../../../../common/constants';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionType } from '../../../../../common/api/detection_engine/rule_management';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { SecurityPageName } from '../../../../app/types';
import { getEditRuleUrl } from '../../../../common/components/link_to/redirect_to_detection_engine';
import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../../common/lib/telemetry';
@@ -58,7 +59,7 @@ export const useExecuteBulkAction = (options?: UseExecuteBulkActionOptions) => {
actionType: bulkAction.type,
summary: response.attributes.summary,
editPayload:
- bulkAction.type === BulkActionType.edit ? bulkAction.editPayload : undefined,
+ bulkAction.type === BulkActionTypeEnum.edit ? bulkAction.editPayload : undefined,
});
}
@@ -83,14 +84,14 @@ export const useExecuteBulkAction = (options?: UseExecuteBulkActionOptions) => {
};
function sendTelemetry(action: BulkActionType, response: BulkActionResponse): void {
- if (action !== BulkActionType.disable && action !== BulkActionType.enable) {
+ if (action !== BulkActionTypeEnum.disable && action !== BulkActionTypeEnum.enable) {
return;
}
if (response.attributes.results.updated.some((rule) => rule.immutable)) {
track(
METRIC_TYPE.COUNT,
- action === BulkActionType.enable
+ action === BulkActionTypeEnum.enable
? TELEMETRY_EVENT.SIEM_RULE_ENABLED
: TELEMETRY_EVENT.SIEM_RULE_DISABLED
);
@@ -99,7 +100,7 @@ function sendTelemetry(action: BulkActionType, response: BulkActionResponse): vo
if (response.attributes.results.updated.some((rule) => !rule.immutable)) {
track(
METRIC_TYPE.COUNT,
- action === BulkActionType.disable
+ action === BulkActionTypeEnum.disable
? TELEMETRY_EVENT.CUSTOM_RULE_DISABLED
: TELEMETRY_EVENT.CUSTOM_RULE_ENABLED
);
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_guess_rule_ids_for_bulk_action.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_guess_rule_ids_for_bulk_action.ts
index ce262ce940f43..2a1acc7a3d4c8 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_guess_rule_ids_for_bulk_action.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_guess_rule_ids_for_bulk_action.ts
@@ -6,7 +6,8 @@
*/
import { useCallback } from 'react';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionType } from '../../../../../common/api/detection_engine/rule_management';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { useRulesTableContextOptional } from '../../../rule_management_ui/components/rules_table/rules_table/rules_table_context';
export function useGuessRuleIdsForBulkAction(): (bulkActionType: BulkActionType) => string[] {
@@ -16,9 +17,9 @@ export function useGuessRuleIdsForBulkAction(): (bulkActionType: BulkActionType)
(bulkActionType: BulkActionType) => {
const allRules = rulesTableContext?.state.isAllSelected ? rulesTableContext.state.rules : [];
const processingRules =
- bulkActionType === BulkActionType.enable
+ bulkActionType === BulkActionTypeEnum.enable
? allRules.filter((x) => !x.enabled)
- : bulkActionType === BulkActionType.disable
+ : bulkActionType === BulkActionTypeEnum.disable
? allRules.filter((x) => x.enabled)
: allRules;
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_error_toast.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_error_toast.ts
index 3f9230a36da34..bb72429ad6b0b 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_error_toast.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_error_toast.ts
@@ -8,7 +8,7 @@
import { useCallback } from 'react';
import type { HTTPError } from '../../../../../common/detection_engine/types';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
-import type { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionType } from '../../../../../common/api/detection_engine/rule_management';
import { explainBulkError, summarizeBulkError } from './translations';
interface ShowBulkErrorToastProps {
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_success_toast.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_success_toast.ts
index dfc2ca5dcb918..03113c772818c 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_success_toast.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_show_bulk_success_toast.ts
@@ -8,8 +8,11 @@
import { useCallback } from 'react';
import type { BulkActionSummary } from '..';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
-import type { BulkActionEditPayload } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type {
+ BulkActionEditPayload,
+ BulkActionType,
+} from '../../../../../common/api/detection_engine/rule_management';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { explainBulkEditSuccess, explainBulkSuccess, summarizeBulkSuccess } from './translations';
interface ShowBulkSuccessToastProps {
@@ -24,7 +27,7 @@ export function useShowBulkSuccessToast() {
return useCallback(
({ actionType, summary, editPayload }: ShowBulkSuccessToastProps) => {
const text =
- actionType === BulkActionType.edit
+ actionType === BulkActionTypeEnum.edit
? explainBulkEditSuccess(editPayload ?? [], summary)
: explainBulkSuccess(actionType, summary);
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts
index d44c4effd265f..94a3d47c90ecf 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts
@@ -5,12 +5,11 @@
* 2.0.
*/
-import * as t from 'io-ts';
+import * as z from 'zod';
import type { RuleSnooze } from '@kbn/alerting-plugin/common';
import type { Type } from '@kbn/securitysolution-io-ts-alerting-types';
import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types';
-import { PositiveInteger } from '@kbn/securitysolution-io-ts-types';
import type { RuleSnoozeSettings } from '@kbn/triggers-actions-ui-plugin/public/types';
import type { WarningSchema } from '../../../../common/api/detection_engine';
import type { RuleExecutionStatus } from '../../../../common/api/detection_engine/rule_monitoring';
@@ -49,11 +48,11 @@ export interface PatchRuleProps {
export type Rule = RuleResponse;
-export type PaginationOptions = t.TypeOf;
-export const PaginationOptions = t.type({
- page: PositiveInteger,
- perPage: PositiveInteger,
- total: PositiveInteger,
+export type PaginationOptions = z.infer;
+export const PaginationOptions = z.object({
+ page: z.number().int().min(0),
+ perPage: z.number().int().min(0),
+ total: z.number().int().min(0),
});
export interface FetchRulesProps {
@@ -81,8 +80,8 @@ export interface RulesSnoozeSettingsBatchResponse {
data: RuleSnoozeSettingsResponse[];
}
-export type SortingOptions = t.TypeOf;
-export const SortingOptions = t.type({
+export type SortingOptions = z.infer;
+export const SortingOptions = z.object({
field: FindRulesSortField,
order: SortOrder,
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_dry_run_confirmation.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_dry_run_confirmation.tsx
index 9e3e9c8b602b1..23bb9106d62cf 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_dry_run_confirmation.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_dry_run_confirmation.tsx
@@ -10,7 +10,7 @@ import { EuiConfirmModal } from '@elastic/eui';
import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations';
import { BulkActionRuleErrorsList } from './bulk_action_rule_errors_list';
-import { BulkActionType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import { assertUnreachable } from '../../../../../../common/utility_types';
import type { BulkActionForConfirmation, DryRunResult } from './types';
@@ -20,9 +20,9 @@ const getActionRejectedTitle = (
failedRulesCount: number
) => {
switch (bulkAction) {
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
return i18n.BULK_EDIT_CONFIRMATION_REJECTED_TITLE(failedRulesCount);
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
return i18n.BULK_EXPORT_CONFIRMATION_REJECTED_TITLE(failedRulesCount);
default:
assertUnreachable(bulkAction);
@@ -34,9 +34,9 @@ const getActionConfirmLabel = (
succeededRulesCount: number
) => {
switch (bulkAction) {
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
return i18n.BULK_EDIT_CONFIRMATION_CONFIRM(succeededRulesCount);
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
return i18n.BULK_EXPORT_CONFIRMATION_CONFIRM(succeededRulesCount);
default:
assertUnreachable(bulkAction);
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx
index 05a27a17274a1..5b90a457a6bd4 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.test.tsx
@@ -13,7 +13,7 @@ import { render, screen } from '@testing-library/react';
import { BulkActionRuleErrorsList } from './bulk_action_rule_errors_list';
import { BulkActionsDryRunErrCode } from '../../../../../../common/constants';
import type { DryRunResult } from './types';
-import { BulkActionType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
const Wrapper: FC = ({ children }) => {
return (
@@ -26,7 +26,7 @@ const Wrapper: FC = ({ children }) => {
describe('Component BulkEditRuleErrorsList', () => {
test('should not render component if no errors present', () => {
const { container } = render(
- ,
+ ,
{
wrapper: Wrapper,
}
@@ -46,9 +46,12 @@ describe('Component BulkEditRuleErrorsList', () => {
ruleIds: ['rule:1'],
},
];
- render(, {
- wrapper: Wrapper,
- });
+ render(
+ ,
+ {
+ wrapper: Wrapper,
+ }
+ );
expect(screen.getByText("2 rules can't be edited (test failure)")).toBeInTheDocument();
expect(screen.getByText("1 rule can't be edited (another failure)")).toBeInTheDocument();
@@ -80,9 +83,12 @@ describe('Component BulkEditRuleErrorsList', () => {
ruleIds: ['rule:1', 'rule:2'],
},
];
- render(, {
- wrapper: Wrapper,
- });
+ render(
+ ,
+ {
+ wrapper: Wrapper,
+ }
+ );
expect(screen.getByText(value)).toBeInTheDocument();
});
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx
index 674206446f85c..907e67f658bc4 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_errors_list.tsx
@@ -10,7 +10,7 @@ import { EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { BulkActionsDryRunErrCode } from '../../../../../../common/constants';
-import { BulkActionType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import type { DryRunResult, BulkActionForConfirmation } from './types';
@@ -132,7 +132,7 @@ const BulkActionRuleErrorsListComponent = ({
{ruleErrors.map(({ message, errorCode, ruleIds }) => {
const rulesCount = ruleIds.length;
switch (bulkAction) {
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
return (
);
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
return (
{
switch (editAction) {
- case BulkActionEditType.add_index_patterns:
- case BulkActionEditType.delete_index_patterns:
- case BulkActionEditType.set_index_patterns:
+ case BulkActionEditTypeEnum.add_index_patterns:
+ case BulkActionEditTypeEnum.delete_index_patterns:
+ case BulkActionEditTypeEnum.set_index_patterns:
return ;
- case BulkActionEditType.add_tags:
- case BulkActionEditType.delete_tags:
- case BulkActionEditType.set_tags:
+ case BulkActionEditTypeEnum.add_tags:
+ case BulkActionEditTypeEnum.delete_tags:
+ case BulkActionEditTypeEnum.set_tags:
return ;
- case BulkActionEditType.set_timeline:
+ case BulkActionEditTypeEnum.set_timeline:
return ;
- case BulkActionEditType.add_rule_actions:
- case BulkActionEditType.set_rule_actions:
+ case BulkActionEditTypeEnum.add_rule_actions:
+ case BulkActionEditTypeEnum.set_rule_actions:
return ;
- case BulkActionEditType.set_schedule:
+ case BulkActionEditTypeEnum.set_schedule:
return ;
default:
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/index_patterns_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/index_patterns_form.tsx
index c9d4900e9adc7..e124e23bd0aea 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/index_patterns_form.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/index_patterns_form.tsx
@@ -14,8 +14,8 @@ import * as i18n from '../../../../../../detections/pages/detection_engine/rules
import { DEFAULT_INDEX_KEY } from '../../../../../../../common/constants';
import { useKibana } from '../../../../../../common/lib/kibana';
-import { BulkActionEditType } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import type { BulkActionEditPayload } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionEditTypeEnum } from '../../../../../../../common/api/detection_engine/rule_management';
+import type { BulkActionEditPayload } from '../../../../../../../common/api/detection_engine/rule_management';
import type { FormSchema } from '../../../../../../shared_imports';
import {
@@ -31,9 +31,9 @@ import { BulkEditFormWrapper } from './bulk_edit_form_wrapper';
const CommonUseField = getUseField({ component: Field });
type IndexPatternsEditActions =
- | BulkActionEditType.add_index_patterns
- | BulkActionEditType.delete_index_patterns
- | BulkActionEditType.set_index_patterns;
+ | BulkActionEditTypeEnum['add_index_patterns']
+ | BulkActionEditTypeEnum['delete_index_patterns']
+ | BulkActionEditTypeEnum['set_index_patterns'];
interface IndexPatternsFormData {
index: string[];
@@ -70,7 +70,7 @@ const initialFormData: IndexPatternsFormData = {
};
const getFormConfig = (editAction: IndexPatternsEditActions) =>
- editAction === BulkActionEditType.add_index_patterns
+ editAction === BulkActionEditTypeEnum.add_index_patterns
? {
indexLabel: i18n.BULK_EDIT_FLYOUT_FORM_ADD_INDEX_PATTERNS_LABEL,
indexHelpText: i18n.BULK_EDIT_FLYOUT_FORM_ADD_INDEX_PATTERNS_HELP_TEXT,
@@ -115,13 +115,11 @@ const IndexPatternsFormComponent = ({
return;
}
- const payload = {
+ onConfirm({
value: data.index,
- type: data.overwrite ? BulkActionEditType.set_index_patterns : editAction,
+ type: data.overwrite ? BulkActionEditTypeEnum.set_index_patterns : editAction,
overwrite_data_views: data.overwriteDataViews,
- };
-
- onConfirm(payload);
+ });
};
return (
@@ -140,7 +138,7 @@ const IndexPatternsFormComponent = ({
},
}}
/>
- {editAction === BulkActionEditType.add_index_patterns && (
+ {editAction === BulkActionEditTypeEnum.add_index_patterns && (
)}
- {editAction === BulkActionEditType.add_index_patterns && (
+ {editAction === BulkActionEditTypeEnum.add_index_patterns && (
)}
- {editAction === BulkActionEditType.delete_index_patterns && (
+ {editAction === BulkActionEditTypeEnum.delete_index_patterns && (
= {
const initialFormData: TagsFormData = { tags: [], overwrite: false };
const getFormConfig = (editAction: TagsEditActions) =>
- editAction === BulkActionEditType.add_tags
+ editAction === BulkActionEditTypeEnum.add_tags
? {
tagsLabel: i18n.BULK_EDIT_FLYOUT_FORM_ADD_TAGS_LABEL,
tagsHelpText: i18n.BULK_EDIT_FLYOUT_FORM_ADD_TAGS_HELP_TEXT,
@@ -97,12 +97,10 @@ const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm }: TagsF
return;
}
- const payload = {
+ onConfirm({
value: data.tags,
- type: data.overwrite ? BulkActionEditType.set_tags : editAction,
- };
-
- onConfirm(payload);
+ type: data.overwrite ? BulkActionEditTypeEnum.set_tags : editAction,
+ });
};
return (
@@ -121,7 +119,7 @@ const TagsFormComponent = ({ editAction, rulesCount, onClose, onConfirm }: TagsF
},
}}
/>
- {editAction === BulkActionEditType.add_tags ? (
+ {editAction === BulkActionEditTypeEnum.add_tags ? (
{
const timelineTitle = timelineId ? data.timeline.title : '';
onConfirm({
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_id: timelineId,
timeline_title: timelineTitle,
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/types.ts
index 000a7e37a9cec..409ee722c6383 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/types.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/types.ts
@@ -6,14 +6,14 @@
*/
import type { BulkActionsDryRunErrCode } from '../../../../../../common/constants';
-import type { BulkActionType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
/**
* Only 2 bulk actions are supported for for confirmation dry run modal:
* * export
* * edit
*/
-export type BulkActionForConfirmation = BulkActionType.export | BulkActionType.edit;
+export type BulkActionForConfirmation = BulkActionTypeEnum['export'] | BulkActionTypeEnum['edit'];
/**
* transformed results of dry run
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx
index a7c5e35ff3341..41802a4738b8d 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx
@@ -14,11 +14,14 @@ import { euiThemeVars } from '@kbn/ui-theme';
import React, { useCallback } from 'react';
import { convertRulesFilterToKQL } from '../../../../../../common/detection_engine/rule_management/rule_filtering';
import { DuplicateOptions } from '../../../../../../common/detection_engine/rule_management/constants';
-import type { BulkActionEditPayload } from '../../../../../../common/api/detection_engine/rule_management';
-import {
- BulkActionType,
+import type {
+ BulkActionEditPayload,
BulkActionEditType,
} from '../../../../../../common/api/detection_engine/rule_management';
+import {
+ BulkActionTypeEnum,
+ BulkActionEditTypeEnum,
+} from '../../../../../../common/api/detection_engine/rule_management';
import { isMlRule } from '../../../../../../common/machine_learning/helpers';
import { useAppToasts } from '../../../../../common/hooks/use_app_toasts';
import { BULK_RULE_ACTIONS } from '../../../../../common/lib/apm/user_actions';
@@ -106,7 +109,7 @@ export const useBulkActions = ({
: disabledRulesNoML.map(({ id }) => id);
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
...(isAllSelected ? { query: kql } : { ids: ruleIds }),
});
};
@@ -118,7 +121,7 @@ export const useBulkActions = ({
const enabledIds = selectedRules.filter(({ enabled }) => enabled).map(({ id }) => id);
await executeBulkAction({
- type: BulkActionType.disable,
+ type: BulkActionTypeEnum.disable,
...(isAllSelected ? { query: kql } : { ids: enabledIds }),
});
};
@@ -132,7 +135,7 @@ export const useBulkActions = ({
return;
}
await executeBulkAction({
- type: BulkActionType.duplicate,
+ type: BulkActionTypeEnum.duplicate,
duplicatePayload: {
include_exceptions:
modalDuplicationConfirmationResult === DuplicateOptions.withExceptions ||
@@ -159,7 +162,7 @@ export const useBulkActions = ({
startTransaction({ name: BULK_RULE_ACTIONS.DELETE });
await executeBulkAction({
- type: BulkActionType.delete,
+ type: BulkActionTypeEnum.delete,
...(isAllSelected ? { query: kql } : { ids: selectedRuleIds }),
});
};
@@ -183,7 +186,7 @@ export const useBulkActions = ({
// they can either cancel action or proceed with export of succeeded rules
const hasActionBeenConfirmed = await showBulkActionConfirmation(
transformExportDetailsToDryRunResult(details),
- BulkActionType.export
+ BulkActionTypeEnum.export
);
if (hasActionBeenConfirmed === false) {
return;
@@ -201,7 +204,7 @@ export const useBulkActions = ({
setIsPreflightInProgress(true);
const dryRunResult = await executeBulkActionsDryRun({
- type: BulkActionType.edit,
+ type: BulkActionTypeEnum.edit,
...(isAllSelected
? { query: convertRulesFilterToKQL(filterOptions) }
: { ids: selectedRuleIds }),
@@ -213,7 +216,7 @@ export const useBulkActions = ({
// User has cancelled edit action or there are no custom rules to proceed
const hasActionBeenConfirmed = await showBulkActionConfirmation(
dryRunResult,
- BulkActionType.edit
+ BulkActionTypeEnum.edit
);
if (hasActionBeenConfirmed === false) {
return;
@@ -264,7 +267,7 @@ export const useBulkActions = ({
}, 5 * 1000);
await executeBulkAction({
- type: BulkActionType.edit,
+ type: BulkActionTypeEnum.edit,
...prepareSearchParams({
...(isAllSelected ? { filterOptions } : { selectedRuleIds }),
dryRunResult,
@@ -330,7 +333,7 @@ export const useBulkActions = ({
name: i18n.BULK_ACTION_ADD_RULE_ACTIONS,
'data-test-subj': 'addRuleActionsBulk',
disabled: !hasActionsPrivileges || isEditDisabled,
- onClick: handleBulkEdit(BulkActionEditType.add_rule_actions),
+ onClick: handleBulkEdit(BulkActionEditTypeEnum.add_rule_actions),
toolTipContent: !hasActionsPrivileges
? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES
: undefined,
@@ -342,7 +345,7 @@ export const useBulkActions = ({
name: i18n.BULK_ACTION_SET_SCHEDULE,
'data-test-subj': 'setScheduleBulk',
disabled: isEditDisabled,
- onClick: handleBulkEdit(BulkActionEditType.set_schedule),
+ onClick: handleBulkEdit(BulkActionEditTypeEnum.set_schedule),
toolTipContent: missingActionPrivileges
? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES
: undefined,
@@ -354,7 +357,7 @@ export const useBulkActions = ({
name: i18n.BULK_ACTION_APPLY_TIMELINE_TEMPLATE,
'data-test-subj': 'applyTimelineTemplateBulk',
disabled: isEditDisabled,
- onClick: handleBulkEdit(BulkActionEditType.set_timeline),
+ onClick: handleBulkEdit(BulkActionEditTypeEnum.set_timeline),
toolTipContent: missingActionPrivileges
? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES
: undefined,
@@ -407,7 +410,7 @@ export const useBulkActions = ({
key: i18n.BULK_ACTION_ADD_TAGS,
name: i18n.BULK_ACTION_ADD_TAGS,
'data-test-subj': 'addTagsBulkEditRule',
- onClick: handleBulkEdit(BulkActionEditType.add_tags),
+ onClick: handleBulkEdit(BulkActionEditTypeEnum.add_tags),
disabled: isEditDisabled,
toolTipContent: missingActionPrivileges
? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES
@@ -418,7 +421,7 @@ export const useBulkActions = ({
key: i18n.BULK_ACTION_DELETE_TAGS,
name: i18n.BULK_ACTION_DELETE_TAGS,
'data-test-subj': 'deleteTagsBulkEditRule',
- onClick: handleBulkEdit(BulkActionEditType.delete_tags),
+ onClick: handleBulkEdit(BulkActionEditTypeEnum.delete_tags),
disabled: isEditDisabled,
toolTipContent: missingActionPrivileges
? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES
@@ -435,7 +438,7 @@ export const useBulkActions = ({
key: i18n.BULK_ACTION_ADD_INDEX_PATTERNS,
name: i18n.BULK_ACTION_ADD_INDEX_PATTERNS,
'data-test-subj': 'addIndexPatternsBulkEditRule',
- onClick: handleBulkEdit(BulkActionEditType.add_index_patterns),
+ onClick: handleBulkEdit(BulkActionEditTypeEnum.add_index_patterns),
disabled: isEditDisabled,
toolTipContent: missingActionPrivileges
? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES
@@ -446,7 +449,7 @@ export const useBulkActions = ({
key: i18n.BULK_ACTION_DELETE_INDEX_PATTERNS,
name: i18n.BULK_ACTION_DELETE_INDEX_PATTERNS,
'data-test-subj': 'deleteIndexPatternsBulkEditRule',
- onClick: handleBulkEdit(BulkActionEditType.delete_index_patterns),
+ onClick: handleBulkEdit(BulkActionEditTypeEnum.delete_index_patterns),
disabled: isEditDisabled,
toolTipContent: missingActionPrivileges
? i18n.LACK_OF_KIBANA_ACTIONS_FEATURE_PRIVILEGES
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_confirmation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_confirmation.ts
index 9ce813fc6d9a2..5ef159bed856b 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_confirmation.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions_confirmation.ts
@@ -11,11 +11,23 @@ import { useBoolState } from '../../../../../common/hooks/use_bool_state';
import type { DryRunResult, BulkActionForConfirmation } from './types';
+interface BulkActionsConfirmation {
+ bulkActionsDryRunResult: DryRunResult | undefined;
+ bulkAction: BulkActionForConfirmation | undefined;
+ isBulkActionConfirmationVisible: boolean;
+ showBulkActionConfirmation: (
+ result: DryRunResult | undefined,
+ action: BulkActionForConfirmation
+ ) => Promise;
+ cancelBulkActionConfirmation: () => void;
+ approveBulkActionConfirmation: () => void;
+}
+
/**
* hook that controls bulk actions confirmation modal window and its content
*/
// TODO Why does this hook exist? Consider removing it altogether
-export const useBulkActionsConfirmation = () => {
+export const useBulkActionsConfirmation = (): BulkActionsConfirmation => {
const [bulkAction, setBulkAction] = useState();
const [dryRunResult, setDryRunResult] = useState();
const [isBulkActionConfirmationVisible, showModal, hideModal] = useBoolState();
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_edit_form_flyout.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_edit_form_flyout.ts
index 260e187e46fbe..f2dc15233cb6b 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_edit_form_flyout.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_edit_form_flyout.ts
@@ -10,10 +10,20 @@ import { useAsyncConfirmation } from '../rules_table/use_async_confirmation';
import type {
BulkActionEditPayload,
BulkActionEditType,
-} from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+} from '../../../../../../common/api/detection_engine/rule_management';
import { useBoolState } from '../../../../../common/hooks/use_bool_state';
-export const useBulkEditFormFlyout = () => {
+interface UseBulkEditFormFlyout {
+ bulkEditActionType: BulkActionEditType | undefined;
+ isBulkEditFlyoutVisible: boolean;
+ handleBulkEditFormConfirm: (data: BulkActionEditPayload) => void;
+ handleBulkEditFormCancel: () => void;
+ completeBulkEditForm: (
+ editActionType: BulkActionEditType
+ ) => Promise;
+}
+
+export const useBulkEditFormFlyout = (): UseBulkEditFormFlyout => {
const dataFormRef = useRef(null);
const [actionType, setActionType] = useState();
const [isBulkEditFlyoutVisible, showBulkEditFlyout, hideBulkEditFlyout] = useBoolState();
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.test.ts
index 3adae50d99adf..0549306036fd2 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.test.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.test.ts
@@ -5,19 +5,20 @@
* 2.0.
*/
-import { BulkActionEditType } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionEditType } from '../../../../../../../common/api/detection_engine/rule_management';
+import { BulkActionEditTypeEnum } from '../../../../../../../common/api/detection_engine/rule_management';
import { computeDryRunEditPayload } from './compute_dry_run_edit_payload';
describe('computeDryRunEditPayload', () => {
- test.each([
- [BulkActionEditType.set_index_patterns, []],
- [BulkActionEditType.delete_index_patterns, []],
- [BulkActionEditType.add_index_patterns, []],
- [BulkActionEditType.add_tags, []],
- [BulkActionEditType.delete_index_patterns, []],
- [BulkActionEditType.set_tags, []],
- [BulkActionEditType.set_timeline, { timeline_id: '', timeline_title: '' }],
+ test.each<[BulkActionEditType, unknown]>([
+ [BulkActionEditTypeEnum.set_index_patterns, []],
+ [BulkActionEditTypeEnum.delete_index_patterns, []],
+ [BulkActionEditTypeEnum.add_index_patterns, []],
+ [BulkActionEditTypeEnum.add_tags, []],
+ [BulkActionEditTypeEnum.delete_index_patterns, []],
+ [BulkActionEditTypeEnum.set_tags, []],
+ [BulkActionEditTypeEnum.set_timeline, { timeline_id: '', timeline_title: '' }],
])('should return correct payload for bulk edit action %s', (editAction, value) => {
const payload = computeDryRunEditPayload(editAction);
expect(payload).toHaveLength(1);
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.ts
index d31bbfaa91790..ba5d565e393d0 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/utils/compute_dry_run_edit_payload.ts
@@ -5,8 +5,11 @@
* 2.0.
*/
-import type { BulkActionEditPayload } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import { BulkActionEditType } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type {
+ BulkActionEditPayload,
+ BulkActionEditType,
+} from '../../../../../../../common/api/detection_engine/rule_management';
+import { BulkActionEditTypeEnum } from '../../../../../../../common/api/detection_engine/rule_management';
import { assertUnreachable } from '../../../../../../../common/utility_types';
/**
@@ -17,9 +20,9 @@ import { assertUnreachable } from '../../../../../../../common/utility_types';
*/
export function computeDryRunEditPayload(editAction: BulkActionEditType): BulkActionEditPayload[] {
switch (editAction) {
- case BulkActionEditType.add_index_patterns:
- case BulkActionEditType.delete_index_patterns:
- case BulkActionEditType.set_index_patterns:
+ case BulkActionEditTypeEnum.add_index_patterns:
+ case BulkActionEditTypeEnum.delete_index_patterns:
+ case BulkActionEditTypeEnum.set_index_patterns:
return [
{
type: editAction,
@@ -27,9 +30,9 @@ export function computeDryRunEditPayload(editAction: BulkActionEditType): BulkAc
},
];
- case BulkActionEditType.add_tags:
- case BulkActionEditType.delete_tags:
- case BulkActionEditType.set_tags:
+ case BulkActionEditTypeEnum.add_tags:
+ case BulkActionEditTypeEnum.delete_tags:
+ case BulkActionEditTypeEnum.set_tags:
return [
{
type: editAction,
@@ -37,7 +40,7 @@ export function computeDryRunEditPayload(editAction: BulkActionEditType): BulkAc
},
];
- case BulkActionEditType.set_timeline:
+ case BulkActionEditTypeEnum.set_timeline:
return [
{
type: editAction,
@@ -45,15 +48,15 @@ export function computeDryRunEditPayload(editAction: BulkActionEditType): BulkAc
},
];
- case BulkActionEditType.add_rule_actions:
- case BulkActionEditType.set_rule_actions:
+ case BulkActionEditTypeEnum.add_rule_actions:
+ case BulkActionEditTypeEnum.set_rule_actions:
return [
{
type: editAction,
value: { actions: [] },
},
];
- case BulkActionEditType.set_schedule:
+ case BulkActionEditTypeEnum.set_schedule:
return [
{
type: editAction,
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/rules_management_tour.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/rules_management_tour.tsx
index e27910df0b7e0..fbb81fd0b66f4 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/rules_management_tour.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/rules_management_tour.tsx
@@ -12,7 +12,7 @@ import React, { useCallback, useEffect, useMemo } from 'react';
import useObservable from 'react-use/lib/useObservable';
import { of } from 'rxjs';
import { siemGuideId } from '../../../../../../../common/guided_onboarding/siem_guide_config';
-import { BulkActionType } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../../../common/api/detection_engine/rule_management';
import { useKibana } from '../../../../../../common/lib/kibana';
import { useFindRulesQuery } from '../../../../../rule_management/api/hooks/use_find_rules_query';
import { useExecuteBulkAction } from '../../../../../rule_management/logic/bulk_actions/use_execute_bulk_action';
@@ -113,7 +113,7 @@ export const RulesManagementTour = () => {
const enableDemoRule = useCallback(async () => {
if (demoRule) {
await executeBulkAction({
- type: BulkActionType.enable,
+ type: BulkActionTypeEnum.enable,
ids: [demoRule.id],
});
}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_saved_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_saved_state.ts
index 84c23a248a0db..1a4efe7517ac9 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_saved_state.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_saved_state.ts
@@ -5,41 +5,45 @@
* 2.0.
*/
-import * as t from 'io-ts';
-import { enumeration } from '@kbn/securitysolution-io-ts-types';
-import { SortingOptions, PaginationOptions } from '../../../../rule_management/logic';
-import { TRuleExecutionStatus } from '../../../../../../common/api/detection_engine/rule_monitoring/model/execution_status';
+import * as z from 'zod';
+import { RuleExecutionStatus } from '../../../../../../common/api/detection_engine';
+import { PaginationOptions, SortingOptions } from '../../../../rule_management/logic';
export enum RuleSource {
Prebuilt = 'prebuilt',
Custom = 'custom',
}
-export type RulesTableSavedFilter = t.TypeOf;
-export const RulesTableSavedFilter = t.partial({
- searchTerm: t.string,
- source: enumeration('RuleSource', RuleSource),
- tags: t.array(t.string),
- enabled: t.boolean,
- ruleExecutionStatus: TRuleExecutionStatus,
-});
-
-export type RulesTableSavedSorting = t.TypeOf;
-export const RulesTableSavedSorting = t.partial({
- field: SortingOptions.props.field,
- order: SortingOptions.props.order,
-});
-
-export type RulesTableStorageSavedPagination = t.TypeOf;
-export const RulesTableStorageSavedPagination = t.partial({
- perPage: PaginationOptions.props.perPage,
-});
-
-export type RulesTableUrlSavedPagination = t.TypeOf;
-export const RulesTableUrlSavedPagination = t.partial({
- page: PaginationOptions.props.page,
- perPage: PaginationOptions.props.perPage,
-});
+export const RulesTableSavedFilter = z
+ .object({
+ searchTerm: z.string(),
+ source: z.nativeEnum(RuleSource),
+ tags: z.array(z.string()),
+ enabled: z.boolean(),
+ ruleExecutionStatus: RuleExecutionStatus,
+ })
+ .partial();
+
+export type RulesTableSavedFilter = z.infer;
+
+export const RulesTableSavedSorting = SortingOptions.pick({
+ field: true,
+ order: true,
+}).partial();
+
+export type RulesTableSavedSorting = z.infer;
+
+export const RulesTableStorageSavedPagination = PaginationOptions.pick({
+ perPage: true,
+}).partial();
+
+export type RulesTableStorageSavedPagination = z.infer;
+
+export type RulesTableUrlSavedPagination = z.infer;
+export const RulesTableUrlSavedPagination = PaginationOptions.pick({
+ page: true,
+ perPage: true,
+}).partial();
export type RulesTableStorageSavedState = RulesTableSavedFilter &
RulesTableSavedSorting &
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.ts
index bc1b28ee72a41..3055c9cbdcbba 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.ts
@@ -6,7 +6,7 @@
*/
import type { Storage } from '@kbn/kibana-utils-plugin/public';
-import { validateNonExact } from '@kbn/securitysolution-io-ts-utils';
+import { safeParseResult } from '@kbn/zod-helpers';
import { useGetInitialUrlParamValue } from '../../../../../common/utils/global_query_string/helpers';
import { RULES_TABLE_MAX_PAGE_SIZE } from '../../../../../../common/constants';
import { useKibana } from '../../../../../common/lib/kibana';
@@ -57,8 +57,8 @@ function validateState(
urlState: RulesTableUrlSavedState | null,
storageState: RulesTableStorageSavedState | null
): [RulesTableSavedFilter, RulesTableSavedSorting, RulesTableUrlSavedPagination] {
- const [filterFromUrl] = validateNonExact(urlState, RulesTableSavedFilter);
- const [filterFromStorage] = validateNonExact(storageState, RulesTableSavedFilter);
+ const filterFromUrl = safeParseResult(urlState, RulesTableSavedFilter);
+ const filterFromStorage = safeParseResult(storageState, RulesTableSavedFilter);
// We have to expose filter, sorting and pagination objects by explicitly specifying each field
// since urlState and/or storageState may contain unnecessary fields (e.g. outdated or explicitly added by user)
// and validateNonExact doesn't truncate fields not included in the type RulesTableSavedFilter and etc.
@@ -71,15 +71,15 @@ function validateState(
filterFromUrl?.ruleExecutionStatus ?? filterFromStorage?.ruleExecutionStatus,
};
- const [sortingFromUrl] = validateNonExact(urlState, RulesTableSavedSorting);
- const [sortingFromStorage] = validateNonExact(storageState, RulesTableSavedSorting);
+ const sortingFromUrl = safeParseResult(urlState, RulesTableSavedSorting);
+ const sortingFromStorage = safeParseResult(storageState, RulesTableSavedSorting);
const sorting = {
field: sortingFromUrl?.field ?? sortingFromStorage?.field,
order: sortingFromUrl?.order ?? sortingFromStorage?.order,
- };
+ } as const;
- const [paginationFromUrl] = validateNonExact(urlState, RulesTableUrlSavedPagination);
- const [paginationFromStorage] = validateNonExact(storageState, RulesTableStorageSavedPagination);
+ const paginationFromUrl = safeParseResult(urlState, RulesTableUrlSavedPagination);
+ const paginationFromStorage = safeParseResult(storageState, RulesTableStorageSavedPagination);
const pagination = {
page: paginationFromUrl?.page, // We don't persist page number in the session storage since it may be outdated when restored
perPage: paginationFromUrl?.perPage ?? paginationFromStorage?.perPage,
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx
index 3525793caa3a3..acf43ebf2c36e 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx
@@ -16,10 +16,7 @@ import {
SecurityPageName,
SHOW_RELATED_INTEGRATIONS_SETTING,
} from '../../../../../common/constants';
-import type {
- DurationMetric,
- RuleExecutionSummary,
-} from '../../../../../common/api/detection_engine/rule_monitoring';
+import type { RuleExecutionSummary } from '../../../../../common/api/detection_engine/rule_monitoring';
import { isMlRule } from '../../../../../common/machine_learning/helpers';
import { getEmptyTagValue } from '../../../../common/components/empty_value';
import { RuleSnoozeBadge } from '../../../rule_management/components/rule_snooze_badge';
@@ -402,7 +399,7 @@ export const useMonitoringColumns = ({
tooltipContent={i18n.COLUMN_INDEXING_TIMES_TOOLTIP}
/>
),
- render: (value: DurationMetric | undefined) => (
+ render: (value: number | undefined) => (
{value != null ? value.toFixed() : getEmptyTagValue()}
@@ -419,7 +416,7 @@ export const useMonitoringColumns = ({
tooltipContent={i18n.COLUMN_QUERY_TIMES_TOOLTIP}
/>
),
- render: (value: DurationMetric | undefined) => (
+ render: (value: number | undefined) => (
{value != null ? value.toFixed() : getEmptyTagValue()}
@@ -459,7 +456,7 @@ export const useMonitoringColumns = ({
}
/>
),
- render: (value: DurationMetric | undefined) => (
+ render: (value: number | undefined) => (
{value != null ? moment.duration(value, 'seconds').humanize() : getEmptyTagValue()}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx
index 1d9d6ad45c8fa..04fc59da5e027 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx
@@ -9,7 +9,7 @@ import type { DefaultItemAction } from '@elastic/eui';
import { EuiToolTip } from '@elastic/eui';
import React from 'react';
import { DuplicateOptions } from '../../../../../common/detection_engine/rule_management/constants';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions';
import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction';
import { useKibana } from '../../../../common/lib/kibana';
@@ -75,7 +75,7 @@ export const useRulesTableActions = ({
return;
}
const result = await executeBulkAction({
- type: BulkActionType.duplicate,
+ type: BulkActionTypeEnum.duplicate,
ids: [rule.id],
duplicatePayload: {
include_exceptions:
@@ -123,7 +123,7 @@ export const useRulesTableActions = ({
startTransaction({ name: SINGLE_RULE_ACTIONS.DELETE });
await executeBulkAction({
- type: BulkActionType.delete,
+ type: BulkActionTypeEnum.delete,
ids: [rule.id],
});
},
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/coverage_overview/coverage_overview_dashboard_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/coverage_overview/coverage_overview_dashboard_context.tsx
index 3a2424664f8ab..057a75d9a5a51 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/coverage_overview/coverage_overview_dashboard_context.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/coverage_overview/coverage_overview_dashboard_context.tsx
@@ -15,7 +15,7 @@ import React, {
} from 'react';
import { invariant } from '../../../../../common/utils/invariant';
import {
- BulkActionType,
+ BulkActionTypeEnum,
CoverageOverviewRuleActivity,
CoverageOverviewRuleSource,
} from '../../../../../common/api/detection_engine';
@@ -114,7 +114,7 @@ export const CoverageOverviewDashboardContextProvider = ({
const enableAllDisabled = useCallback(
async (ruleIds: string[]) => {
- await executeBulkAction({ type: BulkActionType.enable, ids: ruleIds });
+ await executeBulkAction({ type: BulkActionTypeEnum.enable, ids: ruleIds });
},
[executeBulkAction]
);
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/__mocks__/api_client.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/__mocks__/api_client.ts
index b5b8f201f0ff3..a70a9bd66671b 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/__mocks__/api_client.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/__mocks__/api_client.ts
@@ -10,8 +10,8 @@ import type {
GetRuleExecutionResultsResponse,
} from '../../../../../common/api/detection_engine/rule_monitoring';
import {
- LogLevel,
- RuleExecutionEventType,
+ LogLevelEnum,
+ RuleExecutionEventTypeEnum,
} from '../../../../../common/api/detection_engine/rule_monitoring';
import type {
@@ -30,8 +30,8 @@ export const api: jest.Mocked = {
{
timestamp: '2021-12-29T10:42:59.996Z',
sequence: 0,
- level: LogLevel.info,
- type: RuleExecutionEventType['status-change'],
+ level: LogLevelEnum.info,
+ type: RuleExecutionEventTypeEnum['status-change'],
execution_id: 'execution-id-1',
message: 'Rule changed status to "succeeded". Rule execution completed without errors',
},
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/api_client.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/api_client.test.ts
index d1317e2f74252..640cc1a86e423 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/api_client.test.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/api/api_client.test.ts
@@ -12,11 +12,12 @@ import type {
GetRuleExecutionResultsResponse,
} from '../../../../common/api/detection_engine/rule_monitoring';
import {
- LogLevel,
- RuleExecutionEventType,
+ LogLevelEnum,
+ RuleExecutionEventTypeEnum,
} from '../../../../common/api/detection_engine/rule_monitoring';
import { api } from './api_client';
+import type { FetchRuleExecutionEventsArgs } from './api_client_interface';
jest.mock('../../../common/lib/kibana');
@@ -74,7 +75,7 @@ describe('Rule Monitoring API Client', () => {
const ISO_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
- it.each([
+ it.each<[string, Omit, Record]>([
[
'search term filter',
{ searchTerm: 'something to search' },
@@ -82,12 +83,12 @@ describe('Rule Monitoring API Client', () => {
],
[
'event types filter',
- { eventTypes: [RuleExecutionEventType.message] },
+ { eventTypes: [RuleExecutionEventTypeEnum.message] },
{ event_types: 'message' },
],
[
'log level filter',
- { logLevels: [LogLevel.warn, LogLevel.error] },
+ { logLevels: [LogLevelEnum.warn, LogLevelEnum.error] },
{ log_levels: 'warn,error' },
],
[
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/event_type_filter/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/event_type_filter/index.tsx
index 2c87a184f5b1c..5edc079ef5c42 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/event_type_filter/index.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/event_type_filter/index.tsx
@@ -7,8 +7,7 @@
import React, { useCallback } from 'react';
-import type { RuleExecutionEventType } from '../../../../../../../common/api/detection_engine/rule_monitoring';
-import { RULE_EXECUTION_EVENT_TYPES } from '../../../../../../../common/api/detection_engine/rule_monitoring';
+import { RuleExecutionEventType } from '../../../../../../../common/api/detection_engine/rule_monitoring';
import { EventTypeIndicator } from '../../indicators/event_type_indicator';
import { MultiselectFilter } from '../multiselect_filter';
@@ -28,7 +27,7 @@ const EventTypeFilterComponent: React.FC = ({ selectedItem
dataTestSubj="eventTypeFilter"
title={i18n.FILTER_TITLE}
- items={RULE_EXECUTION_EVENT_TYPES}
+ items={RuleExecutionEventType.options}
selectedItems={selectedItems}
onSelectionChange={onChange}
renderItem={renderItem}
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/event_type_indicator/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/event_type_indicator/utils.ts
index 07b3b3a6b096a..9e86215228078 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/event_type_indicator/utils.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/event_type_indicator/utils.ts
@@ -6,18 +6,19 @@
*/
import type { IconType } from '@elastic/eui';
-import { RuleExecutionEventType } from '../../../../../../../common/api/detection_engine/rule_monitoring';
+import type { RuleExecutionEventType } from '../../../../../../../common/api/detection_engine/rule_monitoring';
+import { RuleExecutionEventTypeEnum } from '../../../../../../../common/api/detection_engine/rule_monitoring';
import { assertUnreachable } from '../../../../../../../common/utility_types';
import * as i18n from './translations';
export const getBadgeIcon = (type: RuleExecutionEventType): IconType => {
switch (type) {
- case RuleExecutionEventType.message:
+ case RuleExecutionEventTypeEnum.message:
return 'console';
- case RuleExecutionEventType['status-change']:
+ case RuleExecutionEventTypeEnum['status-change']:
return 'dot';
- case RuleExecutionEventType['execution-metrics']:
+ case RuleExecutionEventTypeEnum['execution-metrics']:
return 'gear';
default:
return assertUnreachable(type, 'Unknown rule execution event type');
@@ -26,11 +27,11 @@ export const getBadgeIcon = (type: RuleExecutionEventType): IconType => {
export const getBadgeText = (type: RuleExecutionEventType): string => {
switch (type) {
- case RuleExecutionEventType.message:
+ case RuleExecutionEventTypeEnum.message:
return i18n.TYPE_MESSAGE;
- case RuleExecutionEventType['status-change']:
+ case RuleExecutionEventTypeEnum['status-change']:
return i18n.TYPE_STATUS_CHANGE;
- case RuleExecutionEventType['execution-metrics']:
+ case RuleExecutionEventTypeEnum['execution-metrics']:
return i18n.TYPE_EXECUTION_METRICS;
default:
return assertUnreachable(type, 'Unknown rule execution event type');
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/log_level_indicator/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/log_level_indicator/utils.ts
index 639c648de0241..702d3edddda5b 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/log_level_indicator/utils.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/indicators/log_level_indicator/utils.ts
@@ -7,20 +7,21 @@
import { upperCase } from 'lodash';
import type { IconColor } from '@elastic/eui';
-import { LogLevel } from '../../../../../../../common/api/detection_engine/rule_monitoring';
+import type { LogLevel } from '../../../../../../../common/api/detection_engine/rule_monitoring';
+import { LogLevelEnum } from '../../../../../../../common/api/detection_engine/rule_monitoring';
import { assertUnreachable } from '../../../../../../../common/utility_types';
export const getBadgeColor = (logLevel: LogLevel): IconColor => {
switch (logLevel) {
- case LogLevel.trace:
+ case LogLevelEnum.trace:
return 'hollow';
- case LogLevel.debug:
+ case LogLevelEnum.debug:
return 'hollow';
- case LogLevel.info:
+ case LogLevelEnum.info:
return 'default';
- case LogLevel.warn:
+ case LogLevelEnum.warn:
return 'warning';
- case LogLevel.error:
+ case LogLevelEnum.error:
return 'danger';
default:
return assertUnreachable(logLevel, 'Unknown log level');
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/tables/use_sorting.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/tables/use_sorting.ts
index 39e48c3997478..5fb9c0fb32215 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/tables/use_sorting.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/tables/use_sorting.ts
@@ -11,11 +11,18 @@ import type { SortOrder } from '../../../../../../common/api/detection_engine';
type TableItem = Record;
+interface SortingState {
+ sort: {
+ field: keyof T;
+ direction: SortOrder;
+ };
+}
+
export const useSorting = (defaultField: keyof T, defaultOrder: SortOrder) => {
const [sortField, setSortField] = useState(defaultField);
const [sortOrder, setSortOrder] = useState(defaultOrder);
- const state = useMemo(() => {
+ const state = useMemo>(() => {
return {
sort: {
field: sortField,
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx
index 866e0e44b6c77..5459968b6c497 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx
@@ -10,8 +10,8 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { renderHook, cleanup } from '@testing-library/react-hooks';
import {
- LogLevel,
- RuleExecutionEventType,
+ LogLevelEnum,
+ RuleExecutionEventTypeEnum,
} from '../../../../../common/api/detection_engine/rule_monitoring';
import { useExecutionEvents } from './use_execution_events';
@@ -85,8 +85,8 @@ describe('useExecutionEvents', () => {
{
timestamp: '2021-12-29T10:42:59.996Z',
sequence: 0,
- level: LogLevel.info,
- type: RuleExecutionEventType['status-change'],
+ level: LogLevelEnum.info,
+ type: RuleExecutionEventTypeEnum['status-change'],
execution_id: 'execution-id-1',
message: 'Rule changed status to "succeeded". Rule execution completed without errors',
},
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/constants.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/constants.ts
index d99be0c13e70b..19d6111b5a936 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/constants.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/constants.ts
@@ -5,13 +5,13 @@
* 2.0.
*/
-import { RESPONSE_ACTION_TYPES } from '../../../common/api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../../../common/api/detection_engine/model/rule_response_actions';
export const getActionDetails = (actionTypeId: string) => {
switch (actionTypeId) {
- case RESPONSE_ACTION_TYPES.OSQUERY:
+ case ResponseActionTypesEnum['.osquery']:
return { logo: 'logoOsquery', name: 'Osquery' };
- case RESPONSE_ACTION_TYPES.ENDPOINT:
+ case ResponseActionTypesEnum['.endpoint']:
return { logo: 'logoSecurity', name: 'Endpoint Security' };
// update when new responseActions are provided
default:
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts
index ad3e3f8392eb1..e8afdd91d1ff3 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts
@@ -6,10 +6,9 @@
*/
import type { EnabledFeatures } from '@kbn/spaces-plugin/public/management/edit_space/enabled_features';
-import type { ResponseActionTypes } from '../../../common/api/detection_engine/model/rule_response_actions';
import {
- RESPONSE_ACTION_TYPES,
- SUPPORTED_RESPONSE_ACTION_TYPES,
+ ResponseActionTypes,
+ ResponseActionTypesEnum,
} from '../../../common/api/detection_engine/model/rule_response_actions';
export interface ResponseActionType {
@@ -29,9 +28,9 @@ export const getSupportedResponseActions = (
userPermissions: EnabledFeatures
): ResponseActionType[] =>
actionTypes.reduce((acc: ResponseActionType[], actionType) => {
- const isEndpointAction = actionType.id === RESPONSE_ACTION_TYPES.ENDPOINT;
+ const isEndpointAction = actionType.id === ResponseActionTypesEnum['.endpoint'];
if (!enabledFeatures.endpoint && isEndpointAction) return acc;
- if (SUPPORTED_RESPONSE_ACTION_TYPES.includes(actionType.id))
+ if (ResponseActionTypes.options.includes(actionType.id))
return [
...acc,
{ ...actionType, disabled: isEndpointAction ? !userPermissions.endpoint : undefined },
@@ -39,14 +38,14 @@ export const getSupportedResponseActions = (
return acc;
}, []);
-export const responseActionTypes = [
+export const responseActionTypes: ResponseActionType[] = [
{
- id: RESPONSE_ACTION_TYPES.OSQUERY,
+ id: ResponseActionTypesEnum['.osquery'],
name: 'Osquery',
iconClass: 'logoOsquery',
},
{
- id: RESPONSE_ACTION_TYPES.ENDPOINT,
+ id: ResponseActionTypesEnum['.endpoint'],
name: 'Endpoint Security',
iconClass: 'logoSecurity',
},
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/response_action_type_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/response_action_type_form.tsx
index 7b176b96c2948..97f3e932e81fe 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/response_action_type_form.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/response_action_type_form.tsx
@@ -21,7 +21,7 @@ import styled from 'styled-components';
import { useCheckEndpointPermissions } from './endpoint/check_permissions';
import { EndpointResponseAction } from './endpoint/endpoint_response_action';
import type { RuleResponseAction } from '../../../common/api/detection_engine/model/rule_response_actions';
-import { RESPONSE_ACTION_TYPES } from '../../../common/api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../../../common/api/detection_engine/model/rule_response_actions';
import { OsqueryResponseAction } from './osquery/osquery_response_action';
import { getActionDetails } from './constants';
import { useFormData } from '../../shared_imports';
@@ -48,10 +48,10 @@ const ResponseActionTypeFormComponent = ({ item, onDeleteAction }: ResponseActio
const editDisabled = useCheckEndpointPermissions(action) ?? false;
const getResponseActionTypeForm = useMemo(() => {
- if (action?.actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY) {
+ if (action?.actionTypeId === ResponseActionTypesEnum['.osquery']) {
return ;
}
- if (action?.actionTypeId === RESPONSE_ACTION_TYPES.ENDPOINT) {
+ if (action?.actionTypeId === ResponseActionTypesEnum['.endpoint']) {
return ;
}
// Place for other ResponseActionTypes
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/utils.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/utils.tsx
index 5b1e57e6386f4..22d190d80b9c4 100644
--- a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/utils.tsx
+++ b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/utils.tsx
@@ -11,7 +11,7 @@ import { filter, reduce } from 'lodash';
import type { ECSMapping } from '@kbn/osquery-io-ts-types';
import type { RuleResponseAction } from '../../../common/api/detection_engine/model/rule_response_actions';
-import { RESPONSE_ACTION_TYPES } from '../../../common/api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../../../common/api/detection_engine/model/rule_response_actions';
import { OsqueryParser } from '../../common/components/markdown_editor/plugins/osquery/parser';
interface OsqueryNoteQuery {
@@ -38,7 +38,7 @@ export const getResponseActionsFromNote = (
(acc: { responseActions: RuleResponseAction[] }, { configuration }: OsqueryNoteQuery) => {
const responseActionPath = 'responseActions';
acc[responseActionPath].push({
- actionTypeId: RESPONSE_ACTION_TYPES.OSQUERY,
+ actionTypeId: ResponseActionTypesEnum['.osquery'],
params: {
savedQueryId: undefined,
packId: undefined,
diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx
index 50c8a5bf50d1b..9a351af0803c7 100644
--- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx
@@ -16,7 +16,7 @@ import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';
import { APP_UI_ID, SecurityPageName } from '../../../../../common/constants';
import { DuplicateOptions } from '../../../../../common/detection_engine/rule_management/constants';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { getRulesUrl } from '../../../../common/components/link_to/redirect_to_detection_engine';
import { useBoolState } from '../../../../common/hooks/use_bool_state';
import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions';
@@ -94,7 +94,7 @@ const RuleActionsOverflowComponent = ({
return;
}
const result = await executeBulkAction({
- type: BulkActionType.duplicate,
+ type: BulkActionTypeEnum.duplicate,
ids: [rule.id],
duplicatePayload: {
include_exceptions:
@@ -156,7 +156,7 @@ const RuleActionsOverflowComponent = ({
startTransaction({ name: SINGLE_RULE_ACTIONS.DELETE });
await executeBulkAction({
- type: BulkActionType.delete,
+ type: BulkActionTypeEnum.delete,
ids: [rule.id],
});
diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx
index 7e4881800f738..35434a711768e 100644
--- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_switch/index.tsx
@@ -9,7 +9,7 @@ import type { EuiSwitchEvent } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSwitch } from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
import styled from 'styled-components';
-import { BulkActionType } from '../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management';
import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions';
import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction';
import { useExecuteBulkAction } from '../../../../detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action';
@@ -60,7 +60,7 @@ export const RuleSwitchComponent = ({
await startMlJobsIfNeeded?.();
}
const bulkActionResponse = await executeBulkAction({
- type: enableRule ? BulkActionType.enable : BulkActionType.disable,
+ type: enableRule ? BulkActionTypeEnum.enable : BulkActionTypeEnum.disable,
ids: [id],
});
if (bulkActionResponse?.attributes.results.updated.length) {
diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts
index cc2b01f75da57..6b92583b1ddde 100644
--- a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts
+++ b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts
@@ -20,7 +20,7 @@ import type {
GetRiskEngineStatusResponse,
InitRiskEngineResponse,
DisableRiskEngineResponse,
-} from '../../../server/lib/risk_engine/types';
+} from '../../../server/lib/entity_analytics/risk_engine/types';
import type { RiskScorePreviewRequestSchema } from '../../../common/risk_engine/risk_score_preview/request_schema';
/**
diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts
index 997e93136339e..68b63300061b6 100644
--- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts
+++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_disable_risk_engine_mutation.ts
@@ -11,7 +11,7 @@ import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status';
import type {
EnableRiskEngineResponse,
EnableDisableRiskEngineErrorResponse,
-} from '../../../../server/lib/risk_engine/types';
+} from '../../../../server/lib/entity_analytics/risk_engine/types';
export const DISABLE_RISK_ENGINE_MUTATION_KEY = ['POST', 'DISABLE_RISK_ENGINE'];
diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts
index 3875a79399dcc..40b3f1b4bddb6 100644
--- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts
+++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_enable_risk_engine_mutation.ts
@@ -11,7 +11,7 @@ import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status';
import type {
EnableRiskEngineResponse,
EnableDisableRiskEngineErrorResponse,
-} from '../../../../server/lib/risk_engine/types';
+} from '../../../../server/lib/entity_analytics/risk_engine/types';
export const ENABLE_RISK_ENGINE_MUTATION_KEY = ['POST', 'ENABLE_RISK_ENGINE'];
export const useEnableRiskEngineMutation = (options?: UseMutationOptions<{}>) => {
diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts
index d220885148cac..35b1071b62b80 100644
--- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts
+++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_init_risk_engine_mutation.ts
@@ -11,7 +11,7 @@ import { useInvalidateRiskEngineStatusQuery } from './use_risk_engine_status';
import type {
InitRiskEngineResponse,
InitRiskEngineError,
-} from '../../../../server/lib/risk_engine/types';
+} from '../../../../server/lib/entity_analytics/risk_engine/types';
export const INIT_RISK_ENGINE_STATUS_KEY = ['POST', 'INIT_RISK_ENGINE'];
diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx
index 0eead8683e4f2..bd0b0e262e3cc 100644
--- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx
+++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_enable_section.tsx
@@ -235,11 +235,11 @@ export const RiskScoreEnableSection = () => {
let initRiskEngineErrors: string[] = [];
if (initRiskEngineMutation.isError) {
- const errorBody = initRiskEngineMutation.error.body.message;
+ const errorBody = initRiskEngineMutation.error.body;
if (errorBody?.full_error?.errors) {
initRiskEngineErrors = errorBody.full_error?.errors;
} else {
- initRiskEngineErrors = [errorBody];
+ initRiskEngineErrors = [errorBody.message];
}
}
@@ -266,10 +266,10 @@ export const RiskScoreEnableSection = () => {
{initRiskEngineMutation.isError && }
{disableRiskEngineMutation.isError && (
-
+
)}
{enableRiskEngineMutation.isError && (
-
+
)}
diff --git a/x-pack/plugins/security_solution/public/management/components/console/mocks.tsx b/x-pack/plugins/security_solution/public/management/components/console/mocks.tsx
index ac729f898c6be..d756e6aaea2e5 100644
--- a/x-pack/plugins/security_solution/public/management/components/console/mocks.tsx
+++ b/x-pack/plugins/security_solution/public/management/components/console/mocks.tsx
@@ -10,8 +10,7 @@
import React, { memo, useEffect } from 'react';
import { EuiCode } from '@elastic/eui';
import userEvent from '@testing-library/user-event';
-import { act } from '@testing-library/react';
-import { within } from '@testing-library/dom';
+import { act, within } from '@testing-library/react';
import { convertToTestId } from './components/command_list';
import { Console } from './console';
import type {
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts
index a370f2a89cb6f..fb1285fb89f05 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/form.cy.ts
@@ -15,7 +15,7 @@ import {
visitRuleActions,
} from '../../tasks/response_actions';
import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api_fixtures';
-import { RESPONSE_ACTION_TYPES } from '../../../../../common/api/detection_engine';
+import { ResponseActionTypesEnum } from '../../../../../common/api/detection_engine';
import { login, ROLE } from '../../tasks/login';
describe(
@@ -78,7 +78,7 @@ describe(
cy.getByTestSubj(`command-type-${testedCommand}`).click();
cy.intercept('POST', '/api/detection_engine/rules', (request) => {
const result = {
- action_type_id: RESPONSE_ACTION_TYPES.ENDPOINT,
+ action_type_id: ResponseActionTypesEnum['.endpoint'],
params: {
command: testedCommand,
comment: 'example1',
@@ -127,7 +127,7 @@ describe(
cy.getByTestSubj('ruleEditSubmitButton').click();
cy.wait('@updateResponseAction').should(({ request }) => {
const query = {
- action_type_id: RESPONSE_ACTION_TYPES.ENDPOINT,
+ action_type_id: ResponseActionTypesEnum['.endpoint'],
params: {
command: testedCommand,
comment: newDescription,
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts
index d43037f4d7f97..dad573bb09c2b 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts
@@ -21,8 +21,7 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy';
import { createEndpointHost } from '../../../tasks/create_endpoint_host';
import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data';
-// FLAKY: https://github.com/elastic/kibana/issues/170373
-describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => {
+describe('Response console', { tags: ['@ess', '@serverless'] }, () => {
beforeEach(() => {
login();
});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts
index efb48f6543542..36ebb060454c5 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/serverless/policy_details_with_security_essentials.cy.ts
@@ -9,8 +9,7 @@ import { login } from '../../tasks/login';
import { visitPolicyDetailsPage } from '../../screens/policy_details';
import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy';
-// FLAKY: https://github.com/elastic/kibana/issues/170666
-describe.skip(
+describe(
'When displaying the Policy Details in Security Essentials PLI',
{
tags: ['@serverless'],
@@ -24,7 +23,11 @@ describe.skip(
let loadedPolicyData: IndexedFleetEndpointPolicyResponse;
before(() => {
- cy.task('indexFleetEndpointPolicy', { policyName: 'tests-serverless' }).then((response) => {
+ cy.task(
+ 'indexFleetEndpointPolicy',
+ { policyName: 'tests-serverless' },
+ { timeout: 5 * 60 * 1000 }
+ ).then((response) => {
loadedPolicyData = response as IndexedFleetEndpointPolicyResponse;
});
});
diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts
index 8f1da4a0ec020..bc0f94d712058 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/fleet.ts
@@ -81,15 +81,20 @@ export const yieldEndpointPolicyRevision = (): Cypress.Chainable =>
export const createAgentPolicyTask = (
version: string,
- policyPrefix?: string
+ policyPrefix?: string,
+ timeout?: number
): Cypress.Chainable => {
const policyName = `${policyPrefix || 'Reassign'} ${Math.random().toString(36).substring(2, 7)}`;
- return cy.task('indexFleetEndpointPolicy', {
- policyName,
- endpointPackageVersion: version,
- agentPolicyName: policyName,
- });
+ return cy.task(
+ 'indexFleetEndpointPolicy',
+ {
+ policyName,
+ endpointPackageVersion: version,
+ agentPolicyName: policyName,
+ },
+ { timeout: timeout ?? 5 * 60 * 1000 }
+ );
};
export const enableAgentTamperProtectionFeatureFlagInPolicy = (agentPolicyId: string) => {
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/integration_tests/search_bar.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/integration_tests/search_bar.test.tsx
index ab0a856ff1fa6..f053ee5ef8d68 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/integration_tests/search_bar.test.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/integration_tests/search_bar.test.tsx
@@ -9,10 +9,9 @@ import React from 'react';
import type { AppContextTestRender } from '../../../../../../common/mock/endpoint';
import { createAppRootMockRenderer } from '../../../../../../common/mock/endpoint';
import { endpointPageHttpMock } from '../../../mocks';
-import { act, waitFor, cleanup } from '@testing-library/react';
+import { act, waitFor, cleanup, fireEvent } from '@testing-library/react';
import { getEndpointListPath } from '../../../../../common/routing';
import { AdminSearchBar } from '../search_bar';
-import { fireEvent } from '@testing-library/dom';
import { uiQueryParams } from '../../../store/selectors';
import type { EndpointIndexUIQueryParams } from '../../../types';
diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx
index be028512cb0a8..2870a67e7042c 100644
--- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx
@@ -25,6 +25,7 @@ import { OperatingSystem } from '@kbn/securitysolution-utils';
import { EventFiltersForm } from './form';
import { EndpointDocGenerator } from '../../../../../../common/endpoint/generate_data';
import type { PolicyData } from '../../../../../../common/endpoint/types';
+import { MAX_COMMENT_LENGTH } from '../../../../../../common/constants';
jest.mock('../../../../../common/lib/kibana');
jest.mock('../../../../../common/containers/source');
@@ -466,4 +467,35 @@ describe('Event filter form', () => {
expect(renderResult.findByTestId('duplicate-fields-warning-message')).not.toBeNull();
});
});
+
+ describe('Errors', () => {
+ beforeEach(() => {
+ render();
+ });
+
+ it('should not show warning text when unique fields are added', async () => {
+ rerender();
+
+ const commentInput = renderResult.getByLabelText('Comment Input');
+
+ expect(
+ renderResult.queryByText(
+ `The length of the comment is too long. The maximum length is ${MAX_COMMENT_LENGTH} characters.`
+ )
+ ).toBeNull();
+ act(() => {
+ fireEvent.change(commentInput, {
+ target: {
+ value: [...new Array(MAX_COMMENT_LENGTH + 1).keys()].map((_) => 'a').join(''),
+ },
+ });
+ fireEvent.blur(commentInput);
+ });
+ expect(
+ renderResult.queryByText(
+ `The length of the comment is too long. The maximum length is ${MAX_COMMENT_LENGTH} characters.`
+ )
+ ).not.toBeNull();
+ });
+ });
});
diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx
index 3b4ff4e394a82..e4e1fa7e14638 100644
--- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.tsx
@@ -133,6 +133,7 @@ export const EventFiltersForm: React.FC(!exception.name);
const [newComment, setNewComment] = useState('');
+ const [hasCommentError, setHasCommentError] = useState(false);
const [hasBeenInputNameVisited, setHasBeenInputNameVisited] = useState(false);
const [selectedPolicies, setSelectedPolicies] = useState([]);
const isPlatinumPlus = useLicense().isPlatinumPlus();
@@ -173,10 +174,11 @@ export const EventFiltersForm: React.FC e.value !== '' || e.value.length)
);
- }, [hasNameError, exception.entries]);
+ }, [hasCommentError, hasNameError, exception.entries]);
const processChanged = useCallback(
(updatedItem?: Partial) => {
@@ -340,6 +342,7 @@ export const EventFiltersForm: React.FC
),
[existingComments, handleOnChangeComment, newComment]
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/artifacts/assignable/policy_artifacts_assignable_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/artifacts/assignable/policy_artifacts_assignable_list.test.tsx
index aa57df82276c6..c1f95b1f4d067 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/artifacts/assignable/policy_artifacts_assignable_list.test.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/artifacts/assignable/policy_artifacts_assignable_list.test.tsx
@@ -10,7 +10,7 @@ import { PolicyArtifactsAssignableList } from './policy_artifacts_assignable_lis
import * as reactTestingLibrary from '@testing-library/react';
import type { AppContextTestRender } from '../../../../../../common/mock/endpoint';
import { createAppRootMockRenderer } from '../../../../../../common/mock/endpoint';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import { getMockListResponse } from '../../../test_utils';
describe('Policy artifacts list', () => {
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/advanced_section.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/advanced_section.test.tsx
index 0eb65818b9347..6688c12c7f853 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/advanced_section.test.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/advanced_section.test.tsx
@@ -17,7 +17,7 @@ import type { AdvancedSectionProps } from './advanced_section';
import { AdvancedSection } from './advanced_section';
import userEvent from '@testing-library/user-event';
import { AdvancedPolicySchema } from '../../../models/advanced_policy_schema';
-import { within } from '@testing-library/dom';
+import { within } from '@testing-library/react';
import { set } from 'lodash';
jest.mock('../../../../../../common/hooks/use_license');
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_collection_card.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_collection_card.test.tsx
index eeaa22aa14f6b..54ade4d11b4dd 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_collection_card.test.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/event_collection_card.test.tsx
@@ -18,7 +18,7 @@ import { OperatingSystem } from '@kbn/securitysolution-utils';
import { expectIsViewOnly, exactMatchText } from '../mocks';
import userEvent from '@testing-library/user-event';
import { cloneDeep, set } from 'lodash';
-import { within } from '@testing-library/dom';
+import { within } from '@testing-library/react';
describe('Policy Event Collection Card common component', () => {
let formProps: EventCollectionCardProps;
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx
index 153b24dcf0bf8..cd0a21d99cdfe 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx
@@ -21,7 +21,7 @@ import { buildGlobalQuery } from '../helpers';
import type { QueryBarTimelineComponentProps } from '.';
import { QueryBarTimeline, getDataProviderFilter, TIMELINE_FILTER_DROP_AREA } from '.';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
const mockUiSettingsForFilterManager = coreMock.createStart().uiSettings;
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts
index 73350b48941db..0ec1d5580f40b 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts
@@ -17,7 +17,7 @@ describe('Prebuilt rule asset schema', () => {
const result = PrebuiltRuleAsset.safeParse(payload);
expectParseError(result);
expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
- `"name: Required, description: Required, risk_score: Required, severity: Required, Invalid input, rule_id: Required, version: Required"`
+ `"name: Required, description: Required, risk_score: Required, severity: Required, rule_id: Required, and 26 more"`
);
});
@@ -40,7 +40,7 @@ describe('Prebuilt rule asset schema', () => {
const result = PrebuiltRuleAsset.safeParse(payload);
expectParseError(result);
expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
- `"name: Required, description: Required, risk_score: Required, severity: Required, Invalid input, version: Required"`
+ `"name: Required, description: Required, risk_score: Required, severity: Required, version: Required, and 25 more"`
);
});
@@ -176,7 +176,9 @@ describe('Prebuilt rule asset schema', () => {
const result = PrebuiltRuleAsset.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", index.0: Expected string, received number, index.0: Expected string, received number, type: Invalid literal value, expected \\"saved_query\\", and 20 more"`
+ );
});
test('saved_query type can have filters with it', () => {
@@ -198,7 +200,9 @@ describe('Prebuilt rule asset schema', () => {
const result = PrebuiltRuleAsset.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", filters: Expected array, received string, filters: Expected array, received string, type: Invalid literal value, expected \\"saved_query\\", and 20 more"`
+ );
});
test('language validates with kuery', () => {
@@ -231,7 +235,9 @@ describe('Prebuilt rule asset schema', () => {
const result = PrebuiltRuleAsset.safeParse(payload);
expectParseError(result);
- expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`);
+ expect(stringifyZodError(result.error)).toMatchInlineSnapshot(
+ `"type: Invalid literal value, expected \\"eql\\", language: Invalid literal value, expected \\"eql\\", language: Invalid enum value. Expected 'kuery' | 'lucene', received 'something-made-up', type: Invalid literal value, expected \\"saved_query\\", saved_id: Required, and 19 more"`
+ );
});
test('max_signals cannot be negative', () => {
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts
index e68e84acf6029..f65d788945deb 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts
@@ -34,7 +34,7 @@ import type {
import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz/mocks';
import type { EndpointAuthz } from '../../../../../common/endpoint/types/authz';
-import { riskEngineDataClientMock } from '../../../risk_engine/risk_engine_data_client.mock';
+import { riskEngineDataClientMock } from '../../../entity_analytics/risk_engine/risk_engine_data_client.mock';
export const createMockClients = () => {
const core = coreMock.createRequestHandlerContext();
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.test.ts
index 428010033c5b2..cd01a251a3c75 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.test.ts
@@ -486,7 +486,7 @@ describe('Perform bulk action route', () => {
});
const result = server.validate(request);
expect(result.badRequest).toHaveBeenCalledWith(
- 'Invalid value "undefined" supplied to "action",Invalid value "undefined" supplied to "edit"'
+ 'action: Invalid literal value, expected "delete", action: Invalid literal value, expected "disable", action: Invalid literal value, expected "enable", action: Invalid literal value, expected "export", action: Invalid literal value, expected "duplicate", and 2 more'
);
});
@@ -498,7 +498,7 @@ describe('Perform bulk action route', () => {
});
const result = server.validate(request);
expect(result.badRequest).toHaveBeenCalledWith(
- 'Invalid value "unknown" supplied to "action",Invalid value "undefined" supplied to "edit"'
+ 'action: Invalid literal value, expected "delete", action: Invalid literal value, expected "disable", action: Invalid literal value, expected "enable", action: Invalid literal value, expected "export", action: Invalid literal value, expected "duplicate", and 2 more'
);
});
@@ -531,7 +531,9 @@ describe('Perform bulk action route', () => {
body: { ...getPerformBulkActionSchemaMock(), ids: 'test fake' },
});
const result = server.validate(request);
- expect(result.badRequest).toHaveBeenCalledWith('Invalid value "test fake" supplied to "ids"');
+ expect(result.badRequest).toHaveBeenCalledWith(
+ 'ids: Expected array, received string, action: Invalid literal value, expected "delete", ids: Expected array, received string, ids: Expected array, received string, action: Invalid literal value, expected "enable", and 7 more'
+ );
});
it('rejects payload if there is more than 100 ids in payload', async () => {
@@ -577,7 +579,9 @@ describe('Perform bulk action route', () => {
body: { ...getPerformBulkActionSchemaMock(), ids: [] },
});
const result = server.validate(request);
- expect(result.badRequest).toHaveBeenCalledWith('Invalid value "[]" supplied to "ids"');
+ expect(result.badRequest).toHaveBeenCalledWith(
+ 'ids: Array must contain at least 1 element(s)'
+ );
});
it('rejects payloads if property "edit" actions is empty', async () => {
@@ -588,7 +592,7 @@ describe('Perform bulk action route', () => {
});
const result = server.validate(request);
expect(result.badRequest).toHaveBeenCalledWith(
- expect.stringContaining('Invalid value "[]" supplied to "edit"')
+ expect.stringContaining('edit: Array must contain at least 1 element(s)')
);
});
@@ -601,7 +605,9 @@ describe('Perform bulk action route', () => {
});
const result = server.validate(request);
expect(result.badRequest).toHaveBeenCalledWith(
- expect.stringContaining('Invalid value "invalid" supplied to "dry_run"')
+ expect.stringContaining(
+ "dry_run: Invalid enum value. Expected 'true' | 'false', received 'invalid', dry_run: Expected boolean, received string"
+ )
);
});
});
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts
index 14022e9e44af2..8af5eeaa1a021 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts
@@ -20,22 +20,24 @@ import {
MAX_RULES_TO_UPDATE_IN_PARALLEL,
RULES_TABLE_MAX_PAGE_SIZE,
} from '../../../../../../../common/constants';
-import type { PerformBulkActionResponse } from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type {
+ BulkEditActionResponse,
+ PerformBulkActionResponse,
+} from '../../../../../../../common/api/detection_engine/rule_management';
import {
- BulkActionType,
+ BulkActionTypeEnum,
PerformBulkActionRequestBody,
PerformBulkActionRequestQuery,
-} from '../../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+} from '../../../../../../../common/api/detection_engine/rule_management';
import type {
NormalizedRuleError,
RuleDetailsInError,
- BulkEditActionResponse,
BulkEditActionResults,
BulkEditActionSummary,
} from '../../../../../../../common/api/detection_engine';
import type { SetupPlugins } from '../../../../../../plugin';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
-import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
+import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation';
import { routeLimitedConcurrencyTag } from '../../../../../../utils/route_limited_concurrency_tag';
import type { PromisePoolError, PromisePoolOutcome } from '../../../../../../utils/promise_pool';
import { initPromisePool } from '../../../../../../utils/promise_pool';
@@ -249,8 +251,8 @@ export const performBulkActionRoute = (
version: '2023-10-31',
validate: {
request: {
- body: buildRouteValidation(PerformBulkActionRequestBody),
- query: buildRouteValidation(PerformBulkActionRequestQuery),
+ body: buildRouteValidationWithZod(PerformBulkActionRequestBody),
+ query: buildRouteValidationWithZod(PerformBulkActionRequestQuery),
},
},
},
@@ -272,10 +274,10 @@ export const performBulkActionRoute = (
});
}
- const isDryRun = request.query.dry_run === 'true';
+ const isDryRun = request.query.dry_run;
// dry run is not supported for export, as it doesn't change ES state and has different response format(exported JSON file)
- if (isDryRun && body.action === BulkActionType.export) {
+ if (isDryRun && body.action === BulkActionTypeEnum.export) {
return siemResponse.error({
body: `Export action doesn't support dry_run mode`,
statusCode: 400,
@@ -318,7 +320,7 @@ export const performBulkActionRoute = (
// handling this action before switch statement as bulkEditRules fetch rules within
// rulesClient method, hence there is no need to use fetchRulesByQueryOrIds utility
- if (body.action === BulkActionType.edit && !isDryRun) {
+ if (body.action === BulkActionTypeEnum.edit && !isDryRun) {
const { rules, errors, skipped } = await bulkEditRules({
rulesClient,
filter: query,
@@ -348,7 +350,7 @@ export const performBulkActionRoute = (
let deleted: RuleAlertType[] = [];
switch (body.action) {
- case BulkActionType.enable:
+ case BulkActionTypeEnum.enable:
bulkActionOutcome = await initPromisePool({
concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL,
items: rules,
@@ -375,7 +377,7 @@ export const performBulkActionRoute = (
.map(({ result }) => result)
.filter((rule): rule is RuleAlertType => rule !== null);
break;
- case BulkActionType.disable:
+ case BulkActionTypeEnum.disable:
bulkActionOutcome = await initPromisePool({
concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL,
items: rules,
@@ -403,7 +405,7 @@ export const performBulkActionRoute = (
.filter((rule): rule is RuleAlertType => rule !== null);
break;
- case BulkActionType.delete:
+ case BulkActionTypeEnum.delete:
bulkActionOutcome = await initPromisePool({
concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL,
items: rules,
@@ -427,7 +429,7 @@ export const performBulkActionRoute = (
.filter((rule): rule is RuleAlertType => rule !== null);
break;
- case BulkActionType.duplicate:
+ case BulkActionTypeEnum.duplicate:
bulkActionOutcome = await initPromisePool({
concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL,
items: rules,
@@ -486,7 +488,7 @@ export const performBulkActionRoute = (
.filter((rule): rule is RuleAlertType => rule !== null);
break;
- case BulkActionType.export:
+ case BulkActionTypeEnum.export:
const exported = await getExportByObjectIds(
rulesClient,
exceptionsClient,
@@ -510,7 +512,7 @@ export const performBulkActionRoute = (
// will be processed only when isDryRun === true
// during dry run only validation is getting performed and rule is not saved in ES
- case BulkActionType.edit:
+ case BulkActionTypeEnum.edit:
bulkActionOutcome = await initPromisePool({
concurrency: MAX_RULES_TO_UPDATE_IN_PARALLEL,
items: rules,
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts
index fc3d87d32b432..ca3cde890b738 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts
@@ -191,7 +191,9 @@ describe('Bulk patch rules route', () => {
});
const result = server.validate(request);
- expect(result.badRequest).toHaveBeenCalledWith('0: Invalid input');
+ expect(result.badRequest).toHaveBeenCalledWith(
+ '0.type: Invalid literal value, expected "eql", 0.language: Invalid literal value, expected "eql", 0.type: Invalid literal value, expected "query", 0.type: Invalid literal value, expected "saved_query", 0.type: Invalid literal value, expected "threshold", and 5 more'
+ );
});
test('allows rule type of query and custom from and interval', async () => {
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts
index 5fed0b4e3446a..a1d74b1445508 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts
@@ -236,7 +236,9 @@ describe('Create rule route', () => {
},
});
const result = await server.validate(request);
- expect(result.badRequest).toHaveBeenCalledWith('Invalid input');
+ expect(result.badRequest).toHaveBeenCalledWith(
+ 'type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "saved_query", saved_id: Required, type: Invalid literal value, expected "threshold", and 18 more'
+ );
});
});
});
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.test.ts
index 76d63ddcd54b0..b9a68994a0e58 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.test.ts
@@ -76,7 +76,7 @@ describe('Find rules route', () => {
expect(result.ok).toHaveBeenCalled();
});
- test('rejects unknown query params', async () => {
+ test('ignores unknown query params', async () => {
const request = requestMock.create({
method: 'get',
path: DETECTION_ENGINE_RULES_URL_FIND,
@@ -86,7 +86,7 @@ describe('Find rules route', () => {
});
const result = server.validate(request);
- expect(result.badRequest).toHaveBeenCalledWith('invalid keys "invalid_value"');
+ expect(result.ok).toHaveBeenCalled();
});
});
});
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts
index 76496d26cb856..3cbd164586a9d 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts
@@ -18,7 +18,7 @@ import {
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
import { findRules } from '../../../logic/search/find_rules';
import { buildSiemResponse } from '../../../../routes/utils';
-import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
+import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation';
import { transformFindAlerts } from '../../../utils/utils';
export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
@@ -35,7 +35,7 @@ export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Log
version: '2023-10-31',
validate: {
request: {
- query: buildRouteValidation(FindRulesRequestQuery),
+ query: buildRouteValidationWithZod(FindRulesRequestQuery),
},
},
},
@@ -63,11 +63,7 @@ export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Log
});
const transformed = transformFindAlerts(rules);
- if (transformed == null) {
- return siemResponse.error({ statusCode: 500, body: 'Internal error transforming' });
- } else {
- return response.ok({ body: transformed ?? {} });
- }
+ return response.ok({ body: transformed ?? {} });
} catch (err) {
const error = transformError(err);
return siemResponse.error({
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts
index 677556f314239..1255287cf52f5 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts
@@ -199,7 +199,9 @@ describe('Patch rule route', () => {
});
const result = server.validate(request);
- expect(result.badRequest).toHaveBeenCalledWith('Invalid input');
+ expect(result.badRequest).toHaveBeenCalledWith(
+ 'type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "query", type: Invalid literal value, expected "saved_query", type: Invalid literal value, expected "threshold", and 5 more'
+ );
});
test('allows rule type of query and custom from and interval', async () => {
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts
index e580f5cc11662..f95b10fa6154f 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts
@@ -23,7 +23,7 @@ import {
getUpdateRulesSchemaMock,
} from '../../../../../../../common/api/detection_engine/model/rule_schema/mocks';
import { getQueryRuleParams } from '../../../../rule_schema/mocks';
-import { RESPONSE_ACTION_TYPES } from '../../../../../../../common/api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../../../../../../../common/api/detection_engine/model/rule_response_actions';
jest.mock('../../../../../machine_learning/authz');
@@ -245,7 +245,7 @@ describe('Update rule route', () => {
...getQueryRuleParams(),
responseActions: [
{
- actionTypeId: RESPONSE_ACTION_TYPES.ENDPOINT,
+ actionTypeId: ResponseActionTypesEnum['.endpoint'],
params: {
command: 'isolate',
comment: '',
@@ -283,7 +283,9 @@ describe('Update rule route', () => {
},
});
const result = await server.validate(request);
- expect(result.badRequest).toHaveBeenCalledWith('Invalid input');
+ expect(result.badRequest).toHaveBeenCalledWith(
+ 'type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "saved_query", saved_id: Required, type: Invalid literal value, expected "threshold", and 18 more'
+ );
});
});
});
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.test.ts
index e598715e8f9ec..e214b7dc3b341 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.test.ts
@@ -5,13 +5,16 @@
* 2.0.
*/
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import { bulkEditActionToRulesClientOperation } from './action_to_rules_client_operation';
describe('bulkEditActionToRulesClientOperation', () => {
test('should transform tags bulk edit actions correctly', () => {
expect(
- bulkEditActionToRulesClientOperation({ type: BulkActionEditType.add_tags, value: ['test'] })
+ bulkEditActionToRulesClientOperation({
+ type: BulkActionEditTypeEnum.add_tags,
+ value: ['test'],
+ })
).toEqual([
{
field: 'tags',
@@ -22,7 +25,7 @@ describe('bulkEditActionToRulesClientOperation', () => {
});
expect(
- bulkEditActionToRulesClientOperation({ type: BulkActionEditType.set_tags, value: ['test'] })
+ bulkEditActionToRulesClientOperation({ type: BulkActionEditTypeEnum.set_tags, value: ['test'] })
).toEqual([
{
field: 'tags',
@@ -32,7 +35,10 @@ describe('bulkEditActionToRulesClientOperation', () => {
]);
expect(
- bulkEditActionToRulesClientOperation({ type: BulkActionEditType.delete_tags, value: ['test'] })
+ bulkEditActionToRulesClientOperation({
+ type: BulkActionEditTypeEnum.delete_tags,
+ value: ['test'],
+ })
).toEqual([
{
field: 'tags',
@@ -44,7 +50,7 @@ describe('bulkEditActionToRulesClientOperation', () => {
test('should transform schedule bulk edit correctly', () => {
expect(
bulkEditActionToRulesClientOperation({
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
interval: '100m',
lookback: '10m',
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.ts
index dfd4ee64c0787..eac694f97944b 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/action_to_rules_client_operation.ts
@@ -8,8 +8,8 @@
import type { BulkEditOperation } from '@kbn/alerting-plugin/server';
import { transformNormalizedRuleToAlertAction } from '../../../../../../common/detection_engine/transform_actions';
-import type { BulkActionEditForRuleAttributes } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionEditForRuleAttributes } from '../../../../../../common/api/detection_engine/rule_management';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import { assertUnreachable } from '../../../../../../common/utility_types';
import { transformToActionFrequency } from '../../normalization/rule_actions';
@@ -23,7 +23,7 @@ export const bulkEditActionToRulesClientOperation = (
): BulkEditOperation[] => {
switch (action.type) {
// tags actions
- case BulkActionEditType.add_tags:
+ case BulkActionEditTypeEnum.add_tags:
return [
{
field: 'tags',
@@ -32,7 +32,7 @@ export const bulkEditActionToRulesClientOperation = (
},
];
- case BulkActionEditType.delete_tags:
+ case BulkActionEditTypeEnum.delete_tags:
return [
{
field: 'tags',
@@ -41,7 +41,7 @@ export const bulkEditActionToRulesClientOperation = (
},
];
- case BulkActionEditType.set_tags:
+ case BulkActionEditTypeEnum.set_tags:
return [
{
field: 'tags',
@@ -51,7 +51,7 @@ export const bulkEditActionToRulesClientOperation = (
];
// rule actions
- case BulkActionEditType.add_rule_actions:
+ case BulkActionEditTypeEnum.add_rule_actions:
return [
{
field: 'actions',
@@ -62,7 +62,7 @@ export const bulkEditActionToRulesClientOperation = (
},
];
- case BulkActionEditType.set_rule_actions:
+ case BulkActionEditTypeEnum.set_rule_actions:
return [
{
field: 'actions',
@@ -74,7 +74,7 @@ export const bulkEditActionToRulesClientOperation = (
];
// schedule actions
- case BulkActionEditType.set_schedule:
+ case BulkActionEditTypeEnum.set_schedule:
return [
{
field: 'schedule',
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/bulk_edit_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/bulk_edit_rules.ts
index 76034819b508d..fd2f1644480c0 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/bulk_edit_rules.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/bulk_edit_rules.ts
@@ -7,7 +7,7 @@
import type { RulesClient } from '@kbn/alerting-plugin/server';
-import type { BulkActionEditPayload } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionEditPayload } from '../../../../../../common/api/detection_engine/rule_management';
import type { MlAuthz } from '../../../../machine_learning/authz';
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.test.ts
index 0337558099532..93044fc0fed18 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.test.ts
@@ -6,7 +6,7 @@
*/
import { addItemsToArray, deleteItemsFromArray, ruleParamsModifier } from './rule_params_modifier';
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import type { RuleAlertType } from '../../../rule_schema';
describe('addItemsToArray', () => {
@@ -47,7 +47,7 @@ describe('ruleParamsModifier', () => {
test('should increment version if rule is custom (immutable === false)', () => {
const { modifiedParams } = ruleParamsModifier(ruleParamsMock, [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['my-index-*'],
},
]);
@@ -57,7 +57,7 @@ describe('ruleParamsModifier', () => {
test('should not increment version if rule is prebuilt (immutable === true)', () => {
const { modifiedParams } = ruleParamsModifier({ ...ruleParamsMock, immutable: true }, [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['my-index-*'],
},
]);
@@ -130,7 +130,7 @@ describe('ruleParamsModifier', () => {
{ ...ruleParamsMock, index: existingIndexPatterns } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: indexPatternsToAdd,
},
]
@@ -194,7 +194,7 @@ describe('ruleParamsModifier', () => {
{ ...ruleParamsMock, index: existingIndexPatterns } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: indexPatternsToDelete,
},
]
@@ -249,7 +249,7 @@ describe('ruleParamsModifier', () => {
{ ...ruleParamsMock, index: existingIndexPatterns } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: indexPatternsToOverwrite,
},
]
@@ -267,7 +267,7 @@ describe('ruleParamsModifier', () => {
{ dataViewId: testDataViewId } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['index-2-*'],
},
]
@@ -281,7 +281,7 @@ describe('ruleParamsModifier', () => {
{ dataViewId: 'test-data-view', index: ['test-*'] } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: ['index'],
overwrite_data_views: true,
},
@@ -296,7 +296,7 @@ describe('ruleParamsModifier', () => {
{ dataViewId: 'test-data-view', index: ['test-*'] } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['index'],
overwrite_data_views: true,
},
@@ -311,7 +311,7 @@ describe('ruleParamsModifier', () => {
{ dataViewId: 'test-data-view', index: ['test-*', 'index'] } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['index'],
overwrite_data_views: true,
},
@@ -327,7 +327,7 @@ describe('ruleParamsModifier', () => {
{ dataViewId: 'test-data-view', index: undefined } as RuleAlertType['params'],
[
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['index'],
overwrite_data_views: true,
},
@@ -342,7 +342,7 @@ describe('ruleParamsModifier', () => {
expect(() =>
ruleParamsModifier({ type: 'machine_learning' } as RuleAlertType['params'], [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['my-index-*'],
},
])
@@ -355,7 +355,7 @@ describe('ruleParamsModifier', () => {
expect(() =>
ruleParamsModifier({ type: 'machine_learning' } as RuleAlertType['params'], [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['my-index-*'],
},
])
@@ -368,7 +368,7 @@ describe('ruleParamsModifier', () => {
expect(() =>
ruleParamsModifier({ type: 'machine_learning' } as RuleAlertType['params'], [
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: ['my-index-*'],
},
])
@@ -381,7 +381,7 @@ describe('ruleParamsModifier', () => {
expect(() =>
ruleParamsModifier({ type: 'esql' } as RuleAlertType['params'], [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['my-index-*'],
},
])
@@ -392,7 +392,7 @@ describe('ruleParamsModifier', () => {
expect(() =>
ruleParamsModifier({ type: 'esql' } as RuleAlertType['params'], [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['my-index-*'],
},
])
@@ -403,7 +403,7 @@ describe('ruleParamsModifier', () => {
expect(() =>
ruleParamsModifier({ type: 'esql' } as RuleAlertType['params'], [
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: ['my-index-*'],
},
])
@@ -417,7 +417,7 @@ describe('ruleParamsModifier', () => {
test('should set timeline', () => {
const { modifiedParams, isParamsUpdateSkipped } = ruleParamsModifier(ruleParamsMock, [
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_id: '91832785-286d-4ebe-b884-1a208d111a70',
timeline_title: 'Test timeline',
@@ -438,7 +438,7 @@ describe('ruleParamsModifier', () => {
const FROM_IN_SECONDS = (INTERVAL_IN_MINUTES + LOOKBACK_IN_MINUTES) * 60;
const { modifiedParams, isParamsUpdateSkipped } = ruleParamsModifier(ruleParamsMock, [
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
interval: `${INTERVAL_IN_MINUTES}m`,
lookback: `${LOOKBACK_IN_MINUTES}m`,
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.ts
index a519aee713bec..2994d2bf7f157 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/rule_params_modifier.ts
@@ -12,8 +12,8 @@ import type { RuleAlertType } from '../../../rule_schema';
import type {
BulkActionEditForRuleParams,
BulkActionEditPayloadIndexPatterns,
-} from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+} from '../../../../../../common/api/detection_engine/rule_management';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import { invariant } from '../../../../../../common/utils/invariant';
export const addItemsToArray = (arr: T[], items: T[]): T[] =>
@@ -52,11 +52,11 @@ const shouldSkipIndexPatternsBulkAction = (
return true;
}
- if (action.type === BulkActionEditType.add_index_patterns) {
+ if (action.type === BulkActionEditTypeEnum.add_index_patterns) {
return hasIndexPatterns(indexPatterns, action);
}
- if (action.type === BulkActionEditType.delete_index_patterns) {
+ if (action.type === BulkActionEditTypeEnum.delete_index_patterns) {
return hasNotIndexPattern(indexPatterns, action);
}
@@ -80,7 +80,7 @@ const applyBulkActionEditToRuleParams = (
switch (action.type) {
// index_patterns actions
// index pattern is not present in machine learning rule type, so we throw error on it
- case BulkActionEditType.add_index_patterns: {
+ case BulkActionEditTypeEnum.add_index_patterns: {
invariant(
ruleParams.type !== 'machine_learning',
"Index patterns can't be added. Machine learning rule doesn't have index patterns property"
@@ -102,7 +102,7 @@ const applyBulkActionEditToRuleParams = (
ruleParams.index = addItemsToArray(ruleParams.index ?? [], action.value);
break;
}
- case BulkActionEditType.delete_index_patterns: {
+ case BulkActionEditTypeEnum.delete_index_patterns: {
invariant(
ruleParams.type !== 'machine_learning',
"Index patterns can't be deleted. Machine learning rule doesn't have index patterns property"
@@ -129,7 +129,7 @@ const applyBulkActionEditToRuleParams = (
}
break;
}
- case BulkActionEditType.set_index_patterns: {
+ case BulkActionEditTypeEnum.set_index_patterns: {
invariant(
ruleParams.type !== 'machine_learning',
"Index patterns can't be overwritten. Machine learning rule doesn't have index patterns property"
@@ -152,7 +152,7 @@ const applyBulkActionEditToRuleParams = (
break;
}
// timeline actions
- case BulkActionEditType.set_timeline: {
+ case BulkActionEditTypeEnum.set_timeline: {
ruleParams = {
...ruleParams,
timelineId: action.value.timeline_id || undefined,
@@ -162,7 +162,7 @@ const applyBulkActionEditToRuleParams = (
break;
}
// update look-back period in from and meta.from fields
- case BulkActionEditType.set_schedule: {
+ case BulkActionEditTypeEnum.set_schedule: {
const interval = parseInterval(action.value.interval) ?? moment.duration(0);
const parsedFrom = parseInterval(action.value.lookback) ?? moment.duration(0);
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.test.ts
index 5bde6c29e6082..cdaa6ed1afb80 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.test.ts
@@ -5,20 +5,20 @@
* 2.0.
*/
-import type { BulkActionEditPayload } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionEditPayload } from '../../../../../../common/api/detection_engine/rule_management';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import { splitBulkEditActions } from './split_bulk_edit_actions';
const bulkEditActions: BulkActionEditPayload[] = [
- { type: BulkActionEditType.add_index_patterns, value: ['test'] },
- { type: BulkActionEditType.set_index_patterns, value: ['test'] },
- { type: BulkActionEditType.delete_index_patterns, value: ['test'] },
- { type: BulkActionEditType.add_tags, value: ['test'] },
- { type: BulkActionEditType.delete_tags, value: ['test'] },
- { type: BulkActionEditType.set_tags, value: ['test'] },
+ { type: BulkActionEditTypeEnum.add_index_patterns, value: ['test'] },
+ { type: BulkActionEditTypeEnum.set_index_patterns, value: ['test'] },
+ { type: BulkActionEditTypeEnum.delete_index_patterns, value: ['test'] },
+ { type: BulkActionEditTypeEnum.add_tags, value: ['test'] },
+ { type: BulkActionEditTypeEnum.delete_tags, value: ['test'] },
+ { type: BulkActionEditTypeEnum.set_tags, value: ['test'] },
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: { timeline_id: 'a-1', timeline_title: 'Test title' },
},
];
@@ -28,16 +28,16 @@ describe('splitBulkEditActions', () => {
const { attributesActions, paramsActions } = splitBulkEditActions(bulkEditActions);
expect(attributesActions).toEqual([
- { type: BulkActionEditType.add_tags, value: ['test'] },
- { type: BulkActionEditType.delete_tags, value: ['test'] },
- { type: BulkActionEditType.set_tags, value: ['test'] },
+ { type: BulkActionEditTypeEnum.add_tags, value: ['test'] },
+ { type: BulkActionEditTypeEnum.delete_tags, value: ['test'] },
+ { type: BulkActionEditTypeEnum.set_tags, value: ['test'] },
]);
expect(paramsActions).toEqual([
- { type: BulkActionEditType.add_index_patterns, value: ['test'] },
- { type: BulkActionEditType.set_index_patterns, value: ['test'] },
- { type: BulkActionEditType.delete_index_patterns, value: ['test'] },
+ { type: BulkActionEditTypeEnum.add_index_patterns, value: ['test'] },
+ { type: BulkActionEditTypeEnum.set_index_patterns, value: ['test'] },
+ { type: BulkActionEditTypeEnum.delete_index_patterns, value: ['test'] },
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: { timeline_id: 'a-1', timeline_title: 'Test title' },
},
]);
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.ts
index 2896acbea0e85..da626722155ed 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/split_bulk_edit_actions.ts
@@ -5,12 +5,12 @@
* 2.0.
*/
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import type {
BulkActionEditPayload,
BulkActionEditForRuleAttributes,
BulkActionEditForRuleParams,
-} from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+} from '../../../../../../common/api/detection_engine/rule_management';
/**
* Split bulk edit actions in 2 chunks: actions applied to params and
@@ -29,15 +29,15 @@ export const splitBulkEditActions = (actions: BulkActionEditPayload[]) => {
return actions.reduce((acc, action) => {
switch (action.type) {
- case BulkActionEditType.set_schedule:
+ case BulkActionEditTypeEnum.set_schedule:
acc.attributesActions.push(action);
acc.paramsActions.push(action);
break;
- case BulkActionEditType.add_tags:
- case BulkActionEditType.set_tags:
- case BulkActionEditType.delete_tags:
- case BulkActionEditType.add_rule_actions:
- case BulkActionEditType.set_rule_actions:
+ case BulkActionEditTypeEnum.add_tags:
+ case BulkActionEditTypeEnum.set_tags:
+ case BulkActionEditTypeEnum.delete_tags:
+ case BulkActionEditTypeEnum.add_rule_actions:
+ case BulkActionEditTypeEnum.set_rule_actions:
acc.attributesActions.push(action);
break;
default:
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/utils.ts
index 214fc16b40a49..d624d9033f299 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/utils.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/utils.ts
@@ -4,7 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
/**
* helper utility that defines whether bulk edit action is related to index patterns, i.e. one of:
@@ -14,7 +15,7 @@ import { BulkActionEditType } from '../../../../../../common/api/detection_engin
*/
export const isIndexPatternsBulkEditAction = (editAction: BulkActionEditType) =>
[
- BulkActionEditType.add_index_patterns,
- BulkActionEditType.delete_index_patterns,
- BulkActionEditType.set_index_patterns,
+ BulkActionEditTypeEnum.add_index_patterns,
+ BulkActionEditTypeEnum.delete_index_patterns,
+ BulkActionEditTypeEnum.set_index_patterns,
].includes(editAction);
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts
index fc8d13c27c567..4a1aef9ed28d7 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/bulk_actions/validations.ts
@@ -10,8 +10,8 @@ import { invariant } from '../../../../../../common/utils/invariant';
import { isMlRule } from '../../../../../../common/machine_learning/helpers';
import { isEsqlRule } from '../../../../../../common/detection_engine/utils';
import { BulkActionsDryRunErrCode } from '../../../../../../common/constants';
-import type { BulkActionEditPayload } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
-import { BulkActionEditType } from '../../../../../../common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route';
+import type { BulkActionEditPayload } from '../../../../../../common/api/detection_engine/rule_management';
+import { BulkActionEditTypeEnum } from '../../../../../../common/api/detection_engine/rule_management';
import type { RuleAlertType } from '../../../rule_schema';
import { isIndexPatternsBulkEditAction } from './utils';
import { throwDryRunError } from './dry_run';
@@ -100,7 +100,9 @@ export const validateBulkEditRule = async ({
*/
const istEditApplicableToImmutableRule = (edit: BulkActionEditPayload[]): boolean => {
return edit.every(({ type }) =>
- [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].includes(type)
+ [BulkActionEditTypeEnum.set_rule_actions, BulkActionEditTypeEnum.add_rule_actions].includes(
+ type
+ )
);
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/find_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/find_rules.ts
index 8fb5f348ae224..892610df03bea 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/find_rules.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/find_rules.ts
@@ -5,42 +5,29 @@
* 2.0.
*/
-import * as t from 'io-ts';
-
import type { FindResult, RulesClient } from '@kbn/alerting-plugin/server';
-import { NonEmptyString, UUID } from '@kbn/securitysolution-io-ts-types';
-import type { FindRulesSortFieldOrUndefined } from '../../../../../../common/api/detection_engine/rule_management';
+import type { FindRulesSortField } from '../../../../../../common/api/detection_engine/rule_management';
-import type {
- FieldsOrUndefined,
- PageOrUndefined,
- PerPageOrUndefined,
- QueryFilterOrUndefined,
- SortOrderOrUndefined,
-} from '../../../../../../common/api/detection_engine';
+import type { Page, PerPage, SortOrder } from '../../../../../../common/api/detection_engine';
import type { RuleParams } from '../../../rule_schema';
import { enrichFilterWithRuleTypeMapping } from './enrich_filter_with_rule_type_mappings';
import { transformSortField } from './transform_sort_field';
-type HasReferences = t.TypeOf;
-const HasReferences = t.type({
- type: NonEmptyString,
- id: UUID,
-});
-
-type HasReferencesOrUndefined = t.TypeOf;
-const HasReferencesOrUndefined = t.union([HasReferences, t.undefined]);
+interface HasReferences {
+ type: string;
+ id: string;
+}
export interface FindRuleOptions {
rulesClient: RulesClient;
- filter: QueryFilterOrUndefined;
- fields: FieldsOrUndefined;
- sortField: FindRulesSortFieldOrUndefined;
- sortOrder: SortOrderOrUndefined;
- page: PageOrUndefined;
- perPage: PerPageOrUndefined;
- hasReference?: HasReferencesOrUndefined;
+ filter: string | undefined;
+ fields: string[] | undefined;
+ sortField: FindRulesSortField | undefined;
+ sortOrder: SortOrder | undefined;
+ page: Page | undefined;
+ perPage: PerPage | undefined;
+ hasReference?: HasReferences | undefined;
}
export const findRules = ({
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/transform_sort_field.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/transform_sort_field.ts
index 53573879d07df..b55e51882345a 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/transform_sort_field.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/search/transform_sort_field.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import type { FindRulesSortFieldOrUndefined } from '../../../../../../common/api/detection_engine/rule_management';
+import type { FindRulesSortField } from '../../../../../../common/api/detection_engine/rule_management';
import { assertUnreachable } from '../../../../../../common/utility_types';
/**
@@ -37,7 +37,7 @@ import { assertUnreachable } from '../../../../../../common/utility_types';
* @param sortField Sort field parameter from the request
* @returns Sort field matching the Alerting framework schema
*/
-export function transformSortField(sortField: FindRulesSortFieldOrUndefined): string | undefined {
+export function transformSortField(sortField?: FindRulesSortField): string | undefined {
if (!sortField) {
return undefined;
}
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts
index 07b9c9d0cbcd8..a513e8468d577 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts
@@ -113,7 +113,8 @@ describe('validate', () => {
const validatedOrError = transformValidateBulkError('rule-1', ruleAlert);
const expected: BulkError = {
error: {
- message: 'Invalid input',
+ message:
+ 'name: Required, type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", name: Required, name: Required, and 22 more',
status_code: 500,
},
rule_id: 'rule-1',
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts
index c01f09f1b0534..cf6054c689cdd 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.test.ts
@@ -9,8 +9,8 @@ import { serverMock, requestContextMock, requestMock } from '../../../../routes/
import {
GET_RULE_EXECUTION_EVENTS_URL,
- LogLevel,
- RuleExecutionEventType,
+ LogLevelEnum,
+ RuleExecutionEventTypeEnum,
} from '../../../../../../../common/api/detection_engine/rule_monitoring';
import { getRuleExecutionEventsResponseMock } from '../../../../../../../common/api/detection_engine/rule_monitoring/mocks';
import type { GetExecutionEventsArgs } from '../../../logic/rule_execution_log';
@@ -35,8 +35,8 @@ describe('getRuleExecutionEventsRoute', () => {
ruleId: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
},
query: {
- event_types: `${RuleExecutionEventType['status-change']}`,
- log_levels: `${LogLevel.debug},${LogLevel.info}`,
+ event_types: `${RuleExecutionEventTypeEnum['status-change']}`,
+ log_levels: `${LogLevelEnum.debug},${LogLevelEnum.info}`,
page: 3,
},
});
@@ -44,8 +44,8 @@ describe('getRuleExecutionEventsRoute', () => {
it('passes request arguments to rule execution log', async () => {
const expectedArgs: GetExecutionEventsArgs = {
ruleId: '04128c15-0d1b-4716-a4c5-46997ac7f3bd',
- eventTypes: [RuleExecutionEventType['status-change']],
- logLevels: [LogLevel.debug, LogLevel.info],
+ eventTypes: [RuleExecutionEventTypeEnum['status-change']],
+ logLevels: [LogLevelEnum.debug, LogLevelEnum.info],
sortOrder: 'desc',
page: 3,
perPage: 20,
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts
index 1049cbb5c89e1..4a01a6550cabc 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts
@@ -7,7 +7,7 @@
import { transformError } from '@kbn/securitysolution-es-utils';
import type { IKibanaResponse } from '@kbn/core/server';
-import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation';
+import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation';
import { buildSiemResponse } from '../../../../routes/utils';
import type { SecuritySolutionPluginRouter } from '../../../../../../types';
@@ -36,8 +36,8 @@ export const getRuleExecutionEventsRoute = (router: SecuritySolutionPluginRouter
version: '1',
validate: {
request: {
- params: buildRouteValidation(GetRuleExecutionEventsRequestParams),
- query: buildRouteValidation(GetRuleExecutionEventsRequestQuery),
+ params: buildRouteValidationWithZod(GetRuleExecutionEventsRequestParams),
+ query: buildRouteValidationWithZod(GetRuleExecutionEventsRequestQuery),
},
},
},
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/detection_engine_health/event_log/aggregations/rule_execution_stats.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/detection_engine_health/event_log/aggregations/rule_execution_stats.ts
index 4151355419586..5b667770ffa5d 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/detection_engine_health/event_log/aggregations/rule_execution_stats.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/detection_engine_health/event_log/aggregations/rule_execution_stats.ts
@@ -5,31 +5,32 @@
* 2.0.
*/
-import { mapValues } from 'lodash';
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import { mapValues } from 'lodash';
import type {
AggregatedMetric,
+ HealthOverviewStats,
+ LogLevel,
NumberOfDetectedGaps,
NumberOfExecutions,
NumberOfLoggedMessages,
- HealthOverviewStats,
- TopMessages,
RuleExecutionStatus,
+ TopMessages,
} from '../../../../../../../../common/api/detection_engine/rule_monitoring';
import {
- RuleExecutionEventType,
+ LogLevelEnum,
+ RuleExecutionEventTypeEnum,
RuleExecutionStatusEnum,
- LogLevel,
} from '../../../../../../../../common/api/detection_engine/rule_monitoring';
-import { DEFAULT_PERCENTILES } from '../../../utils/es_aggregations';
-import type { RawData } from '../../../utils/normalization';
-import * as f from '../../../event_log/event_log_fields';
import {
ALERTING_PROVIDER,
RULE_EXECUTION_LOG_PROVIDER,
} from '../../../event_log/event_log_constants';
+import * as f from '../../../event_log/event_log_fields';
+import { DEFAULT_PERCENTILES } from '../../../utils/es_aggregations';
+import type { RawData } from '../../../utils/normalization';
export type RuleExecutionStatsAggregationLevel = 'whole-interval' | 'histogram';
@@ -74,7 +75,7 @@ export const getRuleExecutionStatsAggregation = (
bool: {
filter: [
{ term: { [f.EVENT_PROVIDER]: RULE_EXECUTION_LOG_PROVIDER } },
- { term: { [f.EVENT_ACTION]: RuleExecutionEventType['status-change'] } },
+ { term: { [f.EVENT_ACTION]: RuleExecutionEventTypeEnum['status-change'] } },
],
must_not: [
{
@@ -101,7 +102,7 @@ export const getRuleExecutionStatsAggregation = (
bool: {
filter: [
{ term: { [f.EVENT_PROVIDER]: RULE_EXECUTION_LOG_PROVIDER } },
- { term: { [f.EVENT_ACTION]: RuleExecutionEventType['execution-metrics'] } },
+ { term: { [f.EVENT_ACTION]: RuleExecutionEventTypeEnum['execution-metrics'] } },
],
},
},
@@ -144,8 +145,8 @@ export const getRuleExecutionStatsAggregation = (
{
terms: {
[f.EVENT_ACTION]: [
- RuleExecutionEventType['status-change'],
- RuleExecutionEventType.message,
+ RuleExecutionEventTypeEnum['status-change'],
+ RuleExecutionEventTypeEnum.message,
],
},
},
@@ -162,7 +163,7 @@ export const getRuleExecutionStatsAggregation = (
? {
errors: {
filter: {
- term: { [f.LOG_LEVEL]: LogLevel.error },
+ term: { [f.LOG_LEVEL]: LogLevelEnum.error },
},
aggs: {
topErrors: {
@@ -176,7 +177,7 @@ export const getRuleExecutionStatsAggregation = (
},
warnings: {
filter: {
- term: { [f.LOG_LEVEL]: LogLevel.warn },
+ term: { [f.LOG_LEVEL]: LogLevelEnum.warn },
},
aggs: {
topWarnings: {
@@ -263,11 +264,11 @@ const normalizeNumberOfLoggedMessages = (
return {
total: Number(messageContainingEvents.doc_count || 0),
by_level: {
- error: getMessageCount(LogLevel.error),
- warn: getMessageCount(LogLevel.warn),
- info: getMessageCount(LogLevel.info),
- debug: getMessageCount(LogLevel.debug),
- trace: getMessageCount(LogLevel.trace),
+ error: getMessageCount(LogLevelEnum.error),
+ warn: getMessageCount(LogLevelEnum.warn),
+ info: getMessageCount(LogLevelEnum.info),
+ debug: getMessageCount(LogLevelEnum.debug),
+ trace: getMessageCount(LogLevelEnum.trace),
},
};
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/event_log/register_event_log_provider.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/event_log/register_event_log_provider.ts
index 61a321c427205..6c1accab273ad 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/event_log/register_event_log_provider.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/event_log/register_event_log_provider.ts
@@ -12,6 +12,6 @@ import { RULE_EXECUTION_LOG_PROVIDER } from './event_log_constants';
export const registerEventLogProvider = (eventLogService: IEventLogService) => {
eventLogService.registerProviderActions(
RULE_EXECUTION_LOG_PROVIDER,
- Object.keys(RuleExecutionEventType)
+ RuleExecutionEventType.options
);
};
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts
index 101884b284ebc..8e9a2970f5dbf 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts
@@ -16,9 +16,9 @@ import type {
import type {
RuleExecutionSettings,
RuleExecutionStatus,
+ LogLevel,
} from '../../../../../../../common/api/detection_engine/rule_monitoring';
import {
- LogLevel,
logLevelFromExecutionStatus,
LogLevelSetting,
logLevelToNumber,
@@ -38,6 +38,7 @@ import type {
StatusChangeArgs,
} from './client_interface';
import type { RuleExecutionMetrics } from '../../../../../../../common/api/detection_engine/rule_monitoring/model';
+import { LogLevelEnum } from '../../../../../../../common/api/detection_engine/rule_monitoring/model';
export const createRuleExecutionLogClientForExecutors = (
settings: RuleExecutionSettings,
@@ -59,23 +60,23 @@ export const createRuleExecutionLogClientForExecutors = (
},
trace(...messages: string[]): void {
- writeMessage(messages, LogLevel.trace);
+ writeMessage(messages, LogLevelEnum.trace);
},
debug(...messages: string[]): void {
- writeMessage(messages, LogLevel.debug);
+ writeMessage(messages, LogLevelEnum.debug);
},
info(...messages: string[]): void {
- writeMessage(messages, LogLevel.info);
+ writeMessage(messages, LogLevelEnum.info);
},
warn(...messages: string[]): void {
- writeMessage(messages, LogLevel.warn);
+ writeMessage(messages, LogLevelEnum.warn);
},
error(...messages: string[]): void {
- writeMessage(messages, LogLevel.error);
+ writeMessage(messages, LogLevelEnum.error);
},
async logStatusChange(args: StatusChangeArgs): Promise {
@@ -107,19 +108,19 @@ export const createRuleExecutionLogClientForExecutors = (
const writeMessageToConsole = (message: string, logLevel: LogLevel, logMeta: ExtMeta): void => {
switch (logLevel) {
- case LogLevel.trace:
+ case LogLevelEnum.trace:
logger.trace(`${message} ${baseLogSuffix}`, logMeta);
break;
- case LogLevel.debug:
+ case LogLevelEnum.debug:
logger.debug(`${message} ${baseLogSuffix}`, logMeta);
break;
- case LogLevel.info:
+ case LogLevelEnum.info:
logger.info(`${message} ${baseLogSuffix}`, logMeta);
break;
- case LogLevel.warn:
+ case LogLevelEnum.warn:
logger.warn(`${message} ${baseLogSuffix}`, logMeta);
break;
- case LogLevel.error:
+ case LogLevelEnum.error:
logger.error(`${message} ${baseLogSuffix}`, logMeta);
break;
default:
@@ -152,7 +153,7 @@ export const createRuleExecutionLogClientForExecutors = (
const writeExceptionToConsole = (e: unknown, message: string, logMeta: ExtMeta): void => {
const logReason = e instanceof Error ? e.stack ?? e.message : String(e);
- writeMessageToConsole(`${message}. Reason: ${logReason}`, LogLevel.error, logMeta);
+ writeMessageToConsole(`${message}. Reason: ${logReason}`, LogLevelEnum.error, logMeta);
};
const writeStatusChangeToConsole = (args: NormalizedStatusChangeArgs, logMeta: ExtMeta): void => {
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_reader.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_reader.ts
index fae8b6cfe9f5c..669f3d7e5ee04 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_reader.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_reader.ts
@@ -9,7 +9,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type { IEventLogClient, IValidatedEvent } from '@kbn/event-log-plugin/server';
import { MAX_EXECUTION_EVENTS_DISPLAYED } from '@kbn/securitysolution-rules';
-import { prepareKQLStringParam } from '../../../../../../../common/utils/kql';
import type {
GetRuleExecutionEventsResponse,
GetRuleExecutionResultsResponse,
@@ -17,10 +16,11 @@ import type {
} from '../../../../../../../common/api/detection_engine/rule_monitoring';
import {
LogLevel,
- logLevelFromString,
+ LogLevelEnum,
RuleExecutionEventType,
- ruleExecutionEventTypeFromString,
+ RuleExecutionEventTypeEnum,
} from '../../../../../../../common/api/detection_engine/rule_monitoring';
+import { prepareKQLStringParam } from '../../../../../../../common/utils/kql';
import { assertUnreachable } from '../../../../../../../common/utility_types';
import { invariant } from '../../../../../../../common/utils/invariant';
@@ -38,11 +38,11 @@ import {
} from './aggregations/execution_results';
import type { ExecutionUuidAggResult } from './aggregations/execution_results/types';
-import * as f from '../../event_log/event_log_fields';
import {
RULE_EXECUTION_LOG_PROVIDER,
RULE_SAVED_OBJECT_TYPE,
} from '../../event_log/event_log_constants';
+import * as f from '../../event_log/event_log_fields';
export interface IEventLogReader {
getExecutionEvents(args: GetExecutionEventsArgs): Promise;
@@ -211,25 +211,27 @@ const normalizeEventSequence = (event: RawEvent): number => {
const normalizeLogLevel = (event: RawEvent): LogLevel => {
const value = event.log?.level;
if (!value) {
- return LogLevel.debug;
+ return LogLevelEnum.debug;
}
- return logLevelFromString(value) ?? LogLevel.trace;
+ const result = LogLevel.safeParse(value);
+ return result.success ? result.data : LogLevelEnum.trace;
};
const normalizeEventType = (event: RawEvent): RuleExecutionEventType => {
const value = event.event?.action;
invariant(value, 'Required "event.action" field is not found');
- return ruleExecutionEventTypeFromString(value) ?? RuleExecutionEventType.message;
+ const result = RuleExecutionEventType.safeParse(value);
+ return result.success ? result.data : RuleExecutionEventTypeEnum.message;
};
const normalizeEventMessage = (event: RawEvent, type: RuleExecutionEventType): string => {
- if (type === RuleExecutionEventType.message) {
+ if (type === RuleExecutionEventTypeEnum.message) {
return event.message || '';
}
- if (type === RuleExecutionEventType['status-change']) {
+ if (type === RuleExecutionEventTypeEnum['status-change']) {
invariant(
event.kibana?.alert?.rule?.execution?.status,
'Required "kibana.alert.rule.execution.status" field is not found'
@@ -241,7 +243,7 @@ const normalizeEventMessage = (event: RawEvent, type: RuleExecutionEventType): s
return `Rule changed status to "${status}". ${message}`;
}
- if (type === RuleExecutionEventType['execution-metrics']) {
+ if (type === RuleExecutionEventTypeEnum['execution-metrics']) {
invariant(
event.kibana?.alert?.rule?.execution?.metrics,
'Required "kibana.alert.rule.execution.metrics" field is not found'
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts
index 89696e7175a30..b0963546100e2 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts
@@ -8,17 +8,20 @@
import { SavedObjectsUtils } from '@kbn/core/server';
import type { IEventLogService } from '@kbn/event-log-plugin/server';
import { SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server';
+import type { LogLevel } from '../../../../../../../common/api/detection_engine/rule_monitoring';
import {
- LogLevel,
logLevelFromExecutionStatus,
logLevelToNumber,
- RuleExecutionEventType,
ruleExecutionStatusToNumber,
} from '../../../../../../../common/api/detection_engine/rule_monitoring';
import type {
RuleExecutionMetrics,
RuleExecutionStatus,
} from '../../../../../../../common/api/detection_engine/rule_monitoring/model';
+import {
+ LogLevelEnum,
+ RuleExecutionEventTypeEnum,
+} from '../../../../../../../common/api/detection_engine/rule_monitoring/model';
import {
RULE_SAVED_OBJECT_TYPE,
RULE_EXECUTION_LOG_PROVIDER,
@@ -74,7 +77,7 @@ export const createEventLogWriter = (eventLogService: IEventLogService): IEventL
},
event: {
kind: 'event',
- action: RuleExecutionEventType.message,
+ action: RuleExecutionEventTypeEnum.message,
sequence: sequence++,
severity: logLevelToNumber(args.logLevel),
},
@@ -116,7 +119,7 @@ export const createEventLogWriter = (eventLogService: IEventLogService): IEventL
},
event: {
kind: 'event',
- action: RuleExecutionEventType['status-change'],
+ action: RuleExecutionEventTypeEnum['status-change'],
sequence: sequence++,
severity: logLevelToNumber(logLevel),
},
@@ -148,7 +151,7 @@ export const createEventLogWriter = (eventLogService: IEventLogService): IEventL
},
logExecutionMetrics: (args: ExecutionMetricsArgs): void => {
- const logLevel = LogLevel.debug;
+ const logLevel = LogLevelEnum.debug;
eventLogger.logEvent({
'@timestamp': nowISO(),
rule: {
@@ -159,7 +162,7 @@ export const createEventLogWriter = (eventLogService: IEventLogService): IEventL
},
event: {
kind: 'metric',
- action: RuleExecutionEventType['execution-metrics'],
+ action: RuleExecutionEventTypeEnum['execution-metrics'],
sequence: sequence++,
severity: logLevelToNumber(logLevel),
},
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts
index fcec7e98c06c2..672434bfc94d0 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts
@@ -7,7 +7,7 @@
import { getScheduleNotificationResponseActionsService } from './schedule_notification_response_actions';
import type { RuleResponseAction } from '../../../../common/api/detection_engine/model/rule_response_actions';
-import { RESPONSE_ACTION_TYPES } from '../../../../common/api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../../../../common/api/detection_engine/model/rule_response_actions';
describe('ScheduleNotificationResponseActions', () => {
const signalOne = { agent: { id: 'agent-id-1' }, _id: 'alert-id-1', user: { id: 'S-1-5-20' } };
@@ -68,7 +68,7 @@ describe('ScheduleNotificationResponseActions', () => {
it('should handle osquery response actions with query', async () => {
const responseActions: RuleResponseAction[] = [
{
- actionTypeId: RESPONSE_ACTION_TYPES.OSQUERY,
+ actionTypeId: ResponseActionTypesEnum['.osquery'],
params: {
...defaultQueryParams,
query: simpleQuery,
@@ -86,7 +86,7 @@ describe('ScheduleNotificationResponseActions', () => {
it('should handle osquery response actions with packs', async () => {
const responseActions: RuleResponseAction[] = [
{
- actionTypeId: RESPONSE_ACTION_TYPES.OSQUERY,
+ actionTypeId: ResponseActionTypesEnum['.osquery'],
params: {
...defaultPackParams,
queries: [
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts
index 25efe01d15f05..a02fafe69d8f6 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts
@@ -8,7 +8,7 @@
import { each } from 'lodash';
import type { EndpointAppContextService } from '../../../endpoint/endpoint_app_context_services';
import type { SetupPlugins } from '../../../plugin_contract';
-import { RESPONSE_ACTION_TYPES } from '../../../../common/api/detection_engine/model/rule_response_actions';
+import { ResponseActionTypesEnum } from '../../../../common/api/detection_engine/model/rule_response_actions';
import { osqueryResponseAction } from './osquery_response_action';
import { endpointResponseAction } from './endpoint_response_action';
import type { ScheduleNotificationActions } from '../rule_types/types';
@@ -29,14 +29,14 @@ export const getScheduleNotificationResponseActionsService =
each(responseActions, (responseAction) => {
if (
- responseAction.actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY &&
+ responseAction.actionTypeId === ResponseActionTypesEnum['.osquery'] &&
osqueryCreateActionService
) {
osqueryResponseAction(responseAction, osqueryCreateActionService, {
alerts,
});
}
- if (responseAction.actionTypeId === RESPONSE_ACTION_TYPES.ENDPOINT) {
+ if (responseAction.actionTypeId === ResponseActionTypesEnum['.endpoint']) {
endpointResponseAction(responseAction, endpointAppContextService, {
alerts,
});
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_and_persist_risk_scores.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.mock.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/calculate_and_persist_risk_scores.mock.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.mock.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_and_persist_risk_scores.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/calculate_and_persist_risk_scores.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_and_persist_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/calculate_and_persist_risk_scores.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_and_persist_risk_scores.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.mock.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.mock.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.mock.ts
index 183a00eb0fe5c..c81d1336c162b 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.mock.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.mock.ts
@@ -9,7 +9,7 @@ import {
ALERT_RISK_SCORE,
ALERT_RULE_NAME,
} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names';
-import { RiskCategories } from '../../../common/risk_engine';
+import { RiskCategories } from '../../../../common/risk_engine';
import type {
CalculateRiskScoreAggregations,
CalculateScoresResponse,
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.ts
index a5c22b867b72f..ecacf95020251 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/calculate_risk_scores.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/calculate_risk_scores.ts
@@ -22,9 +22,9 @@ import type {
IdentifierType,
RiskWeights,
RiskScore,
-} from '../../../common/risk_engine';
-import { RiskCategories } from '../../../common/risk_engine';
-import { withSecuritySpan } from '../../utils/with_security_span';
+} from '../../../../common/risk_engine';
+import { RiskCategories } from '../../../../common/risk_engine';
+import { withSecuritySpan } from '../../../utils/with_security_span';
import { getAfterKeyForIdentifierType, getFieldForIdentifierAgg } from './helpers';
import {
buildCategoryCountDeclarations,
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/configurations.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/configurations.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/configurations.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/configurations.ts
index 6f9a49bb47bbb..35547187e4ddc 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/configurations.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/configurations.ts
@@ -5,8 +5,8 @@
* 2.0.
*/
import type { FieldMap } from '@kbn/alerts-as-data-utils';
-import type { IdentifierType } from '../../../common/risk_engine';
-import { RiskScoreEntity, riskScoreBaseIndexName } from '../../../common/risk_engine';
+import type { IdentifierType } from '../../../../common/risk_engine';
+import { RiskScoreEntity, riskScoreBaseIndexName } from '../../../../common/risk_engine';
import type { IIndexPatternString } from './utils/create_datastream';
const commonRiskFields: FieldMap = {
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/get_risk_inputs_index.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.mock.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/get_risk_inputs_index.mock.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.mock.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/get_risk_inputs_index.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/get_risk_inputs_index.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/get_risk_inputs_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/get_risk_inputs_index.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/get_risk_inputs_index.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/helpers.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/helpers.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/helpers.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.ts
index 90a7b0c54c275..09836ff94fe2d 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/helpers.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/helpers.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import type { AfterKey, AfterKeys, IdentifierType } from '../../../common/risk_engine';
+import type { AfterKey, AfterKeys, IdentifierType } from '../../../../common/risk_engine';
import type { CalculateAndPersistScoresResponse } from './types';
export const getFieldForIdentifierAgg = (identifierType: IdentifierType): string =>
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.mock.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.mock.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.mock.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.test.ts
similarity index 99%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.test.ts
index 8dc2da15c2e18..619952859fc0f 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.test.ts
@@ -67,7 +67,7 @@ jest.mock('./utils/create_datastream', () => ({
createDataStream: jest.fn(),
}));
-jest.mock('../risk_score/transform/helpers/transforms', () => ({
+jest.mock('../../risk_score/transform/helpers/transforms', () => ({
createAndStartTransform: jest.fn(),
}));
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.ts
index 269f4b6dad9fd..ea564ffe2395c 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_client.ts
@@ -26,13 +26,13 @@ import {
import { createDataStream } from './utils/create_datastream';
import type { RiskEngineDataWriter as Writer } from './risk_engine_data_writer';
import { RiskEngineDataWriter } from './risk_engine_data_writer';
-import type { InitRiskEngineResult } from '../../../common/risk_engine';
+import type { InitRiskEngineResult } from '../../../../common/risk_engine';
import {
RiskEngineStatus,
getRiskScoreLatestIndex,
MAX_SPACES_COUNT,
RiskScoreEntity,
-} from '../../../common/risk_engine';
+} from '../../../../common/risk_engine';
import {
getLegacyTransforms,
getLatestTransformId,
@@ -48,7 +48,7 @@ import {
import { getRiskInputsIndex } from './get_risk_inputs_index';
import { removeRiskScoringTask, startRiskScoringTask } from './tasks';
import { createIndex } from './utils/create_index';
-import { bulkDeleteSavedObjects } from '../risk_score/prebuilt_saved_objects/helpers/bulk_delete_saved_objects';
+import { bulkDeleteSavedObjects } from '../../risk_score/prebuilt_saved_objects/helpers/bulk_delete_saved_objects';
interface InitOpts {
namespace: string;
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_writer.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_writer.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_writer.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_writer.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.ts
index a897dd0462f69..8e859449bb32d 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_writer.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_engine_data_writer.ts
@@ -7,7 +7,7 @@
import type { BulkOperationContainer } from '@elastic/elasticsearch/lib/api/types';
import type { Logger, ElasticsearchClient } from '@kbn/core/server';
-import type { IdentifierType, RiskScore } from '../../../common/risk_engine';
+import type { IdentifierType, RiskScore } from '../../../../common/risk_engine';
interface WriterBulkResponse {
errors: string[];
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_score_service.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.mock.ts
similarity index 94%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_score_service.mock.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.mock.ts
index 54fd66c7d3e97..68b5b55dbda42 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_score_service.mock.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.mock.ts
@@ -6,7 +6,7 @@
*/
import type { RiskScoreService } from './risk_score_service';
-import type { RiskScore } from '../../../common/risk_engine';
+import type { RiskScore } from '../../../../common/risk_engine';
const createRiskScoreMock = (overrides: Partial = {}): RiskScore => ({
'@timestamp': '2023-02-15T00:15:19.231Z',
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_score_service.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_score_service.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_score_service.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_weights.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.test.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_weights.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.test.ts
index 0bc25121771bd..40b3ee800b1bd 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_weights.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.test.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { RiskWeightTypes, RiskCategories } from '../../../common/risk_engine';
+import { RiskWeightTypes, RiskCategories } from '../../../../common/risk_engine';
import {
buildCategoryAssignment,
buildCategoryWeights,
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_weights.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.ts
similarity index 96%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/risk_weights.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.ts
index 34ab491b74b04..225887f2dce55 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_weights.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/risk_weights.ts
@@ -12,8 +12,8 @@ import type {
RiskCategoryRiskWeight,
RiskWeight,
RiskWeights,
-} from '../../../common/risk_engine';
-import { RiskCategories, RiskWeightTypes } from '../../../common/risk_engine';
+} from '../../../../common/risk_engine';
+import { RiskCategories, RiskWeightTypes } from '../../../../common/risk_engine';
const RISK_CATEGORIES = Object.values(RiskCategories);
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/index.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/index.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/index.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_disable_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.test.ts
similarity index 88%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_disable_route.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.test.ts
index e7c162ddd08e8..23e58896199a9 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_disable_route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.test.ts
@@ -8,15 +8,15 @@
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
import { riskEngineDisableRoute } from './risk_engine_disable_route';
-import { RISK_ENGINE_DISABLE_URL } from '../../../../common/constants';
+import { RISK_ENGINE_DISABLE_URL } from '../../../../../common/constants';
import {
serverMock,
requestContextMock,
requestMock,
-} from '../../detection_engine/routes/__mocks__';
+} from '../../../detection_engine/routes/__mocks__';
import { riskEngineDataClientMock } from '../risk_engine_data_client.mock';
-describe('risk score calculation route', () => {
+describe('risk score disable route', () => {
let server: ReturnType;
let context: ReturnType;
let mockTaskManagerStart: ReturnType;
@@ -78,7 +78,7 @@ describe('risk score calculation route', () => {
const response = await server.inject(request, context);
expect(response.status).toEqual(500);
- expect(response.body.message.message).toEqual('something went wrong');
+ expect(response.body.message).toEqual('something went wrong');
});
});
@@ -94,10 +94,8 @@ describe('risk score calculation route', () => {
expect(response.status).toEqual(400);
expect(response.body).toEqual({
- message: {
- message:
- 'Task Manager is unavailable, but is required to disable the risk engine. Please enable the taskManager plugin and try again.',
- },
+ message:
+ 'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.',
status_code: 400,
});
});
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_disable_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.ts
similarity index 80%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_disable_route.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.ts
index b5ae6287c40fd..dde7ddbee9e83 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_disable_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_disable_route.ts
@@ -8,9 +8,10 @@
import type { StartServicesAccessor } from '@kbn/core/server';
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
-import { RISK_ENGINE_DISABLE_URL, APP_ID } from '../../../../common/constants';
-import type { StartPlugins } from '../../../plugin';
-import type { SecuritySolutionPluginRouter } from '../../../types';
+import { RISK_ENGINE_DISABLE_URL, APP_ID } from '../../../../../common/constants';
+import type { StartPlugins } from '../../../../plugin';
+import type { SecuritySolutionPluginRouter } from '../../../../types';
+import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations';
export const riskEngineDisableRoute = (
router: SecuritySolutionPluginRouter,
@@ -34,10 +35,7 @@ export const riskEngineDisableRoute = (
if (!taskManager) {
return siemResponse.error({
statusCode: 400,
- body: {
- message:
- 'Task Manager is unavailable, but is required to disable the risk engine. Please enable the taskManager plugin and try again.',
- },
+ body: TASK_MANAGER_UNAVAILABLE_ERROR,
});
}
@@ -50,6 +48,7 @@ export const riskEngineDisableRoute = (
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
+ bypassErrorFormat: true,
});
}
});
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_enable_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.test.ts
similarity index 88%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_enable_route.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.test.ts
index 8ef30ae60e368..79a6c88c4fadf 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_enable_route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.test.ts
@@ -8,15 +8,15 @@
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
import { riskEngineEnableRoute } from './risk_engine_enable_route';
-import { RISK_ENGINE_ENABLE_URL } from '../../../../common/constants';
+import { RISK_ENGINE_ENABLE_URL } from '../../../../../common/constants';
import {
serverMock,
requestContextMock,
requestMock,
-} from '../../detection_engine/routes/__mocks__';
+} from '../../../detection_engine/routes/__mocks__';
import { riskEngineDataClientMock } from '../risk_engine_data_client.mock';
-describe('risk score calculation route', () => {
+describe('risk score enable route', () => {
let server: ReturnType;
let context: ReturnType;
let mockTaskManagerStart: ReturnType;
@@ -78,7 +78,7 @@ describe('risk score calculation route', () => {
const response = await server.inject(request, context);
expect(response.status).toEqual(500);
- expect(response.body.message.message).toEqual('something went wrong');
+ expect(response.body.message).toEqual('something went wrong');
});
});
@@ -94,10 +94,8 @@ describe('risk score calculation route', () => {
expect(response.status).toEqual(400);
expect(response.body).toEqual({
- message: {
- message:
- 'Task Manager is unavailable, but is required to enable the risk engine. Please enable the taskManager plugin and try again.',
- },
+ message:
+ 'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.',
status_code: 400,
});
});
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_enable_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.ts
similarity index 80%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_enable_route.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.ts
index af5eb77374bba..bebc8b7236bb8 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_enable_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_enable_route.ts
@@ -8,9 +8,10 @@
import type { StartServicesAccessor } from '@kbn/core/server';
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
-import { RISK_ENGINE_ENABLE_URL, APP_ID } from '../../../../common/constants';
-import type { StartPlugins } from '../../../plugin';
-import type { SecuritySolutionPluginRouter } from '../../../types';
+import { RISK_ENGINE_ENABLE_URL, APP_ID } from '../../../../../common/constants';
+import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations';
+import type { StartPlugins } from '../../../../plugin';
+import type { SecuritySolutionPluginRouter } from '../../../../types';
export const riskEngineEnableRoute = (
router: SecuritySolutionPluginRouter,
@@ -29,14 +30,10 @@ export const riskEngineEnableRoute = (
const [_, { taskManager }] = await getStartServices();
const securitySolution = await context.securitySolution;
const riskEngineClient = securitySolution.getRiskEngineDataClient();
-
if (!taskManager) {
return siemResponse.error({
statusCode: 400,
- body: {
- message:
- 'Task Manager is unavailable, but is required to enable the risk engine. Please enable the taskManager plugin and try again.',
- },
+ body: TASK_MANAGER_UNAVAILABLE_ERROR,
});
}
@@ -49,6 +46,7 @@ export const riskEngineEnableRoute = (
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
+ bypassErrorFormat: true,
});
}
});
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_init_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_init_route.ts
similarity index 86%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_init_route.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_init_route.ts
index 2a0a5fafc70b0..e5b719dfbc42f 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_init_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_init_route.ts
@@ -8,10 +8,10 @@
import type { StartServicesAccessor } from '@kbn/core/server';
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
-import { RISK_ENGINE_INIT_URL, APP_ID } from '../../../../common/constants';
-import type { StartPlugins } from '../../../plugin';
-
-import type { SecuritySolutionPluginRouter } from '../../../types';
+import { RISK_ENGINE_INIT_URL, APP_ID } from '../../../../../common/constants';
+import type { StartPlugins } from '../../../../plugin';
+import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations';
+import type { SecuritySolutionPluginRouter } from '../../../../types';
export const riskEngineInitRoute = (
router: SecuritySolutionPluginRouter,
@@ -36,10 +36,7 @@ export const riskEngineInitRoute = (
if (!taskManager) {
return siemResponse.error({
statusCode: 400,
- body: {
- message:
- 'Task Manager is unavailable, but is required to initialize the risk engine. Please enable the taskManager plugin and try again.',
- },
+ body: TASK_MANAGER_UNAVAILABLE_ERROR,
});
}
@@ -67,6 +64,7 @@ export const riskEngineInitRoute = (
message: initResultResponse.errors.join('\n'),
full_error: initResultResponse,
},
+ bypassErrorFormat: true,
});
}
return response.ok({ body: { result: initResultResponse } });
@@ -76,6 +74,7 @@ export const riskEngineInitRoute = (
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
+ bypassErrorFormat: true,
});
}
});
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_status_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_status_route.ts
similarity index 89%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_status_route.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_status_route.ts
index d741ee5dd23ff..a7d649c0d7784 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_engine_status_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_engine_status_route.ts
@@ -7,9 +7,9 @@
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
-import { RISK_ENGINE_STATUS_URL, APP_ID } from '../../../../common/constants';
+import { RISK_ENGINE_STATUS_URL, APP_ID } from '../../../../../common/constants';
-import type { SecuritySolutionPluginRouter } from '../../../types';
+import type { SecuritySolutionPluginRouter } from '../../../../types';
export const riskEngineStatusRoute = (router: SecuritySolutionPluginRouter) => {
router.versioned
@@ -44,6 +44,7 @@ export const riskEngineStatusRoute = (router: SecuritySolutionPluginRouter) => {
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
+ bypassErrorFormat: true,
});
}
});
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_calculation_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.test.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_calculation_route.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.test.ts
index 2792727ae74f1..7cf7b5304a01d 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_calculation_route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.test.ts
@@ -9,12 +9,12 @@ import { riskScoreCalculationRoute } from './risk_score_calculation_route';
import { loggerMock } from '@kbn/logging-mocks';
-import { RISK_SCORE_CALCULATION_URL } from '../../../../common/constants';
+import { RISK_SCORE_CALCULATION_URL } from '../../../../../common/constants';
import {
serverMock,
requestContextMock,
requestMock,
-} from '../../detection_engine/routes/__mocks__';
+} from '../../../detection_engine/routes/__mocks__';
import { riskScoreServiceFactory } from '../risk_score_service';
import { riskScoreServiceMock } from '../risk_score_service.mock';
import { getRiskInputsIndex } from '../get_risk_inputs_index';
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_calculation_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.ts
similarity index 88%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_calculation_route.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.ts
index 1b02c4a10fd25..cfbd80afb0d5f 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_calculation_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_calculation_route.ts
@@ -12,10 +12,10 @@ import {
APP_ID,
DEFAULT_RISK_SCORE_PAGE_SIZE,
RISK_SCORE_CALCULATION_URL,
-} from '../../../../common/constants';
-import { riskScoreCalculationRequestSchema } from '../../../../common/risk_engine/risk_score_calculation/request_schema';
-import type { SecuritySolutionPluginRouter } from '../../../types';
-import { buildRouteValidation } from '../../../utils/build_validation/route_validation';
+} from '../../../../../common/constants';
+import { riskScoreCalculationRequestSchema } from '../../../../../common/risk_engine/risk_score_calculation/request_schema';
+import type { SecuritySolutionPluginRouter } from '../../../../types';
+import { buildRouteValidation } from '../../../../utils/build_validation/route_validation';
import { riskScoreServiceFactory } from '../risk_score_service';
import { getRiskInputsIndex } from '../get_risk_inputs_index';
@@ -89,6 +89,7 @@ export const riskScoreCalculationRoute = (router: SecuritySolutionPluginRouter,
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
+ bypassErrorFormat: true,
});
}
}
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_preview_route.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.test.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_preview_route.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.test.ts
index 72963995594a8..ba87e94c3ccc2 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_preview_route.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.test.ts
@@ -7,13 +7,13 @@
import { loggerMock } from '@kbn/logging-mocks';
-import { RISK_SCORE_PREVIEW_URL } from '../../../../common/constants';
-import { RiskCategories, RiskWeightTypes } from '../../../../common/risk_engine';
+import { RISK_SCORE_PREVIEW_URL } from '../../../../../common/constants';
+import { RiskCategories, RiskWeightTypes } from '../../../../../common/risk_engine';
import {
serverMock,
requestContextMock,
requestMock,
-} from '../../detection_engine/routes/__mocks__';
+} from '../../../detection_engine/routes/__mocks__';
import { getRiskInputsIndex } from '../get_risk_inputs_index';
import { riskScoreServiceFactory } from '../risk_score_service';
import { riskScoreServiceMock } from '../risk_score_service.mock';
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_preview_route.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.ts
similarity index 89%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_preview_route.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.ts
index 9a1a5f2b83d7c..05f80c526a927 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/routes/risk_score_preview_route.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/risk_score_preview_route.ts
@@ -13,10 +13,10 @@ import {
APP_ID,
DEFAULT_RISK_SCORE_PAGE_SIZE,
RISK_SCORE_PREVIEW_URL,
-} from '../../../../common/constants';
-import { riskScorePreviewRequestSchema } from '../../../../common/risk_engine/risk_score_preview/request_schema';
-import type { SecuritySolutionPluginRouter } from '../../../types';
-import { buildRouteValidation } from '../../../utils/build_validation/route_validation';
+} from '../../../../../common/constants';
+import { riskScorePreviewRequestSchema } from '../../../../../common/risk_engine/risk_score_preview/request_schema';
+import type { SecuritySolutionPluginRouter } from '../../../../types';
+import { buildRouteValidation } from '../../../../utils/build_validation/route_validation';
import { riskScoreServiceFactory } from '../risk_score_service';
import { getRiskInputsIndex } from '../get_risk_inputs_index';
@@ -91,6 +91,7 @@ export const riskScorePreviewRoute = (router: SecuritySolutionPluginRouter, logg
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
+ bypassErrorFormat: true,
});
}
}
diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/translations.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/translations.ts
new file mode 100644
index 0000000000000..648ec23ea6b3c
--- /dev/null
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/routes/translations.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const TASK_MANAGER_UNAVAILABLE_ERROR = i18n.translate(
+ 'xpack.securitySolution.api.riskEngine.taskManagerUnavailable',
+ {
+ defaultMessage:
+ 'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.',
+ }
+);
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/saved_object/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/saved_object/index.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/saved_object/index.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/saved_object/index.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/saved_object/risk_engine_configuration_type.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/saved_object/risk_engine_configuration_type.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/saved_object/risk_engine_configuration_type.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/saved_object/risk_engine_configuration_type.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/schema/risk_score_apis.yml b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/schema/risk_score_apis.yml
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/schema/risk_score_apis.yml
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/schema/risk_score_apis.yml
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/constants.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/constants.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/constants.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/constants.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/helpers.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/helpers.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/helpers.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.ts
index dfacb8b78f30a..b2db9b348b55e 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/helpers.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/helpers.ts
@@ -14,7 +14,7 @@ import {
} from '@kbn/core/server';
import { addSpaceIdToPath } from '@kbn/spaces-plugin/server';
-import type { Range } from '../../../../common/risk_engine';
+import type { Range } from '../../../../../common/risk_engine';
export const convertDateToISOString = (dateString: string): string => {
const date = datemath.parse(dateString);
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/index.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/index.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/index.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/risk_scoring_task.mock.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.mock.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/risk_scoring_task.mock.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.mock.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/risk_scoring_task.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/risk_scoring_task.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/risk_scoring_task.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts
similarity index 96%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/risk_scoring_task.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts
index b0482b43b5c13..525f2247b63bd 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/risk_scoring_task.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/risk_scoring_task.ts
@@ -18,8 +18,8 @@ import type {
TaskManagerStartContract,
} from '@kbn/task-manager-plugin/server';
import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server';
-import type { AfterKeys, IdentifierType } from '../../../../common/risk_engine';
-import type { StartPlugins } from '../../../plugin';
+import type { AfterKeys, IdentifierType } from '../../../../../common/risk_engine';
+import type { StartPlugins } from '../../../../plugin';
import { type RiskScoreService, riskScoreServiceFactory } from '../risk_score_service';
import { RiskEngineDataClient } from '../risk_engine_data_client';
import { isRiskScoreCalculationComplete } from '../helpers';
@@ -30,12 +30,12 @@ import {
} from './state';
import { INTERVAL, SCOPE, TIMEOUT, TYPE, VERSION } from './constants';
import { buildScopedInternalSavedObjectsClientUnsafe, convertRangeToISO } from './helpers';
-import { RiskScoreEntity } from '../../../../common/risk_engine/types';
+import { RiskScoreEntity } from '../../../../../common/risk_engine/types';
import {
RISK_SCORE_EXECUTION_SUCCESS_EVENT,
RISK_SCORE_EXECUTION_ERROR_EVENT,
RISK_SCORE_EXECUTION_CANCELLATION_EVENT,
-} from '../../telemetry/event_based/events';
+} from '../../../telemetry/event_based/events';
const logFactory =
(logger: Logger, taskId: string) =>
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/tasks/state.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/state.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/tasks/state.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/tasks/state.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/types.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/types.ts
similarity index 92%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/types.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/types.ts
index 1e9751ff1388e..f5aeaf4f56428 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/types.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/types.ts
@@ -14,7 +14,7 @@ import type {
Range,
RiskEngineStatus,
RiskScore,
-} from '../../../common/risk_engine';
+} from '../../../../common/risk_engine';
export interface CalculateScoresParams {
afterKeys: AfterKeys;
@@ -78,19 +78,15 @@ export interface InitRiskEngineResponse {
export interface InitRiskEngineError {
body: {
- message: {
- message: string;
- full_error: InitRiskEngineResultResponse | undefined;
- } & string;
+ message: string;
+ full_error: InitRiskEngineResultResponse | undefined;
};
}
export interface EnableDisableRiskEngineErrorResponse {
body: {
- message: {
- message: string;
- full_error: string;
- };
+ message: string;
+ full_error: string;
};
}
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/create_datastream.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_datastream.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/utils/create_datastream.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_datastream.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/create_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_index.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/utils/create_index.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/create_index.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/retry_transient_es_errors.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/utils/retry_transient_es_errors.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/retry_transient_es_errors.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/utils/retry_transient_es_errors.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/retry_transient_es_errors.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/saved_object_configuration.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/saved_object_configuration.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/utils/saved_object_configuration.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/saved_object_configuration.ts
index 8d1562d805e57..e39f2f73e5df2 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/saved_object_configuration.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/saved_object_configuration.ts
@@ -6,7 +6,7 @@
*/
import type { SavedObject, SavedObjectsClientContract } from '@kbn/core/server';
-import { getAlertsIndex } from '../../../../common/utils/risk_score_modules';
+import { getAlertsIndex } from '../../../../../common/utils/risk_score_modules';
import type { RiskEngineConfiguration } from '../types';
import { riskEngineConfigurationTypeName } from '../saved_object';
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/transforms.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.test.ts
similarity index 100%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/utils/transforms.test.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.test.ts
diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/transforms.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.ts
similarity index 97%
rename from x-pack/plugins/security_solution/server/lib/risk_engine/utils/transforms.ts
rename to x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.ts
index d1a544233339e..b78ea9ccfa644 100644
--- a/x-pack/plugins/security_solution/server/lib/risk_engine/utils/transforms.ts
+++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_engine/utils/transforms.ts
@@ -14,11 +14,11 @@ import type {
TransformPutTransformRequest,
TransformGetTransformStatsTransformStats,
} from '@elastic/elasticsearch/lib/api/types';
-import { RiskScoreEntity } from '../../../../common/search_strategy';
+import { RiskScoreEntity } from '../../../../../common/search_strategy';
import {
getRiskScorePivotTransformId,
getRiskScoreLatestTransformId,
-} from '../../../../common/utils/risk_score_modules';
+} from '../../../../../common/utils/risk_score_modules';
export const getLegacyTransforms = async ({
namespace,
diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts
index adbf06cc1da99..66f22e0c44bef 100644
--- a/x-pack/plugins/security_solution/server/plugin.ts
+++ b/x-pack/plugins/security_solution/server/plugin.ts
@@ -107,7 +107,7 @@ import {
} from '../common/endpoint/constants';
import { AppFeaturesService } from './lib/app_features_service/app_features_service';
-import { registerRiskScoringTask } from './lib/risk_engine/tasks/risk_scoring_task';
+import { registerRiskScoringTask } from './lib/entity_analytics/risk_engine/tasks/risk_scoring_task';
import { registerProtectionUpdatesNoteRoutes } from './endpoint/routes/protection_updates_note';
import { latestRiskScoreIndexPattern, allRiskScoreIndexPattern } from '../common/risk_engine';
import { isEndpointPackageV2 } from '../common/endpoint/utils/package_v2';
diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts
index be810fd5ae41e..fde473d2a253e 100644
--- a/x-pack/plugins/security_solution/server/request_context_factory.ts
+++ b/x-pack/plugins/security_solution/server/request_context_factory.ts
@@ -25,7 +25,7 @@ import type {
import type { Immutable } from '../common/endpoint/types';
import type { EndpointAuthz } from '../common/endpoint/types/authz';
import type { EndpointAppContextService } from './endpoint/endpoint_app_context_services';
-import { RiskEngineDataClient } from './lib/risk_engine/risk_engine_data_client';
+import { RiskEngineDataClient } from './lib/entity_analytics/risk_engine/risk_engine_data_client';
export interface IRequestContextFactory {
create(
diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts
index d3786ea8acb88..b5b6a5c205e95 100644
--- a/x-pack/plugins/security_solution/server/routes/index.ts
+++ b/x-pack/plugins/security_solution/server/routes/index.ts
@@ -80,8 +80,8 @@ import {
riskEngineInitRoute,
riskEngineEnableRoute,
riskEngineStatusRoute,
-} from '../lib/risk_engine/routes';
-import { riskScoreCalculationRoute } from '../lib/risk_engine/routes/risk_score_calculation_route';
+} from '../lib/entity_analytics/risk_engine/routes';
+import { riskScoreCalculationRoute } from '../lib/entity_analytics/risk_engine/routes/risk_score_calculation_route';
export const initRoutes = (
router: SecuritySolutionPluginRouter,
diff --git a/x-pack/plugins/security_solution/server/saved_objects.ts b/x-pack/plugins/security_solution/server/saved_objects.ts
index 3f91bcf149ac6..0b1fec5677488 100644
--- a/x-pack/plugins/security_solution/server/saved_objects.ts
+++ b/x-pack/plugins/security_solution/server/saved_objects.ts
@@ -14,7 +14,7 @@ import { legacyType as legacyRuleActionsType } from './lib/detection_engine/rule
import { prebuiltRuleAssetType } from './lib/detection_engine/prebuilt_rules';
import { type as signalsMigrationType } from './lib/detection_engine/migrations/saved_objects';
import { manifestType } from './endpoint/lib/artifacts/saved_object_mappings';
-import { riskEngineConfigurationType } from './lib/risk_engine/saved_object';
+import { riskEngineConfigurationType } from './lib/entity_analytics/risk_engine/saved_object';
const types = [
noteType,
diff --git a/x-pack/plugins/security_solution/server/types.ts b/x-pack/plugins/security_solution/server/types.ts
index 8326d13ad03a7..c979cc25c172b 100644
--- a/x-pack/plugins/security_solution/server/types.ts
+++ b/x-pack/plugins/security_solution/server/types.ts
@@ -29,7 +29,7 @@ import type {
import type { FrameworkRequest } from './lib/framework';
import type { EndpointAuthz } from '../common/endpoint/types/authz';
import type { EndpointInternalFleetServicesInterface } from './endpoint/services/fleet';
-import type { RiskEngineDataClient } from './lib/risk_engine/risk_engine_data_client';
+import type { RiskEngineDataClient } from './lib/entity_analytics/risk_engine/risk_engine_data_client';
export { AppClient };
diff --git a/x-pack/plugins/serverless_observability/kibana.jsonc b/x-pack/plugins/serverless_observability/kibana.jsonc
index 0c68668e473ea..692d721c20a30 100644
--- a/x-pack/plugins/serverless_observability/kibana.jsonc
+++ b/x-pack/plugins/serverless_observability/kibana.jsonc
@@ -3,7 +3,7 @@
"id": "@kbn/serverless-observability",
"owner": [
"@elastic/appex-sharedux",
- "@elastic/apm-ui"
+ "@elastic/obs-ux-management-team"
],
"description": "Serverless customizations for observability.",
"plugin": {
diff --git a/x-pack/plugins/serverless_search/public/application/components/languages/javascript.ts b/x-pack/plugins/serverless_search/public/application/components/languages/javascript.ts
index 1302bebff7137..72d865f1030bc 100644
--- a/x-pack/plugins/serverless_search/public/application/components/languages/javascript.ts
+++ b/x-pack/plugins/serverless_search/public/application/components/languages/javascript.ts
@@ -20,12 +20,15 @@ const searchResult = await client.search({
console.log(searchResult.hits.hits)
`,
- configureClient: ({ url, apiKey }) => `const { Client } = require('@elastic/elasticsearch');
+ configureClient: ({
+ url,
+ apiKey,
+ }) => `const { Client } = require('@elastic/elasticsearch-serverless');
const client = new Client({
-node: '${url}',
-auth: {
+ node: '${url}',
+ auth: {
apiKey: '${apiKey}'
-}
+ }
});`,
docLink: docLinks.jsClient,
github: {
@@ -44,34 +47,34 @@ const dataset = [
{"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227},
{"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268},
{"name": "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311}
- ];
+];
// Index with the bulk helper
const result = await client.helpers.bulk({
-datasource: dataset,
-onDocument (doc) {
- return { index: { _index: 'my-index-name' }};
-}
+ datasource: dataset,
+ onDocument (doc) {
+ return { index: { _index: 'my-index-name' }};
+ }
});
console.log(result);
/**
{
-total: 6,
-failed: 0,
-retry: 0,
-successful: 6,
-noop: 0,
-time: 191,
-bytes: 787,
-aborted: false
+ total: 6,
+ failed: 0,
+ retry: 0,
+ successful: 6,
+ noop: 0,
+ time: 191,
+ bytes: 787,
+ aborted: false
}
*/`,
ingestDataIndex: ({
apiKey,
url,
indexName,
- }) => `const { Client } = require('@elastic/elasticsearch');
+ }) => `const { Client } = require('@elastic/elasticsearch-serverless');
const client = new Client({
node: '${url}',
auth: {
@@ -91,7 +94,7 @@ const result = await client.helpers.bulk({
});
console.log(result);
`,
- installClient: 'npm install @elastic/elasticsearch@8',
+ installClient: 'npm install @elastic/elasticsearch-serverless',
name: i18n.translate('xpack.serverlessSearch.languages.javascript', {
defaultMessage: 'JavaScript',
}),
@@ -100,20 +103,20 @@ console.log(result);
console.log(resp);
/**
{
-name: 'instance-0000000000',
-cluster_name: 'd9dcd35d12fe46dfaa28ec813f65d57b',
-cluster_uuid: 'iln8jaivThSezhTkzp0Knw',
-version: {
- build_flavor: 'default',
- build_type: 'docker',
- build_hash: 'c94b4700cda13820dad5aa74fae6db185ca5c304',
- build_date: '2022-10-24T16:54:16.433628434Z',
- build_snapshot: false,
- lucene_version: '9.4.1',
- minimum_wire_compatibility_version: '7.17.0',
- minimum_index_compatibility_version: '7.0.0'
-},
-tagline: 'You Know, for Search'
+ name: 'instance-0000000000',
+ cluster_name: 'd9dcd35d12fe46dfaa28ec813f65d57b',
+ cluster_uuid: 'iln8jaivThSezhTkzp0Knw',
+ version: {
+ build_flavor: 'default',
+ build_type: 'docker',
+ build_hash: 'c94b4700cda13820dad5aa74fae6db185ca5c304',
+ build_date: '2022-10-24T16:54:16.433628434Z',
+ build_snapshot: false,
+ lucene_version: '9.4.1',
+ minimum_wire_compatibility_version: '7.17.0',
+ minimum_index_compatibility_version: '7.0.0'
+ },
+ tagline: 'You Know, for Search'
}
*/`,
};
diff --git a/x-pack/plugins/serverless_search/public/layout/nav.tsx b/x-pack/plugins/serverless_search/public/layout/nav.tsx
index 3aaa1ae62884c..7d4b2fd7d0fd1 100644
--- a/x-pack/plugins/serverless_search/public/layout/nav.tsx
+++ b/x-pack/plugins/serverless_search/public/layout/nav.tsx
@@ -15,6 +15,7 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import type { ServerlessPluginStart } from '@kbn/serverless/public';
import type { CloudStart } from '@kbn/cloud-plugin/public';
+import { CONNECTORS_LABEL } from '../../common/i18n_string';
const navigationTree: NavigationTreeDefinition = {
body: [
@@ -37,79 +38,60 @@ const navigationTree: NavigationTreeDefinition = {
getIsActive: ({ pathNameSerialized, prepend }) => {
return pathNameSerialized.startsWith(prepend('/app/dev_tools'));
},
+ spaceBefore: 'l',
},
{
- id: 'explore',
- title: i18n.translate('xpack.serverlessSearch.nav.explore', {
- defaultMessage: 'Explore',
+ link: 'discover',
+ spaceBefore: 'm',
+ },
+ {
+ link: 'dashboards',
+ getIsActive: ({ pathNameSerialized, prepend }) => {
+ return pathNameSerialized.startsWith(prepend('/app/dashboards'));
+ },
+ },
+ {
+ link: 'visualize',
+ title: i18n.translate('xpack.serverlessSearch.nav.visualize', {
+ defaultMessage: 'Visualizations',
}),
- children: [
- {
- link: 'discover',
- },
- {
- link: 'dashboards',
- getIsActive: ({ pathNameSerialized, prepend }) => {
- return pathNameSerialized.startsWith(prepend('/app/dashboards'));
- },
- },
- {
- link: 'visualize',
- title: i18n.translate('xpack.serverlessSearch.nav.visualize', {
- defaultMessage: 'Visualizations',
- }),
- getIsActive: ({ pathNameSerialized, prepend }) => {
- return (
- pathNameSerialized.startsWith(prepend('/app/visualize')) ||
- pathNameSerialized.startsWith(prepend('/app/lens')) ||
- pathNameSerialized.startsWith(prepend('/app/maps'))
- );
- },
- },
- {
- link: 'management:triggersActions',
- title: i18n.translate('xpack.serverlessSearch.nav.alerts', {
- defaultMessage: 'Alerts',
- }),
- },
- ],
+ getIsActive: ({ pathNameSerialized, prepend }) => {
+ return (
+ pathNameSerialized.startsWith(prepend('/app/visualize')) ||
+ pathNameSerialized.startsWith(prepend('/app/lens')) ||
+ pathNameSerialized.startsWith(prepend('/app/maps'))
+ );
+ },
},
{
- id: 'content',
- title: i18n.translate('xpack.serverlessSearch.nav.content', {
- defaultMessage: 'Content',
+ link: 'management:triggersActions',
+ title: i18n.translate('xpack.serverlessSearch.nav.alerts', {
+ defaultMessage: 'Alerts',
}),
- children: [
- {
- title: i18n.translate('xpack.serverlessSearch.nav.content.indices', {
- defaultMessage: 'Index Management',
- }),
- link: 'management:index_management',
- breadcrumbStatus:
- 'hidden' /* management sub-pages set their breadcrumbs themselves */,
- },
- {
- title: i18n.translate('xpack.serverlessSearch.nav.content.pipelines', {
- defaultMessage: 'Pipelines',
- }),
- link: 'management:ingest_pipelines',
- breadcrumbStatus:
- 'hidden' /* management sub-pages set their breadcrumbs themselves */,
- },
- ],
},
{
- id: 'security',
- title: i18n.translate('xpack.serverlessSearch.nav.security', {
- defaultMessage: 'Security',
+ title: i18n.translate('xpack.serverlessSearch.nav.content.indices', {
+ defaultMessage: 'Index Management',
}),
- children: [
- {
- link: 'management:api_keys',
- breadcrumbStatus:
- 'hidden' /* management sub-pages set their breadcrumbs themselves */,
- },
- ],
+ link: 'management:index_management',
+ breadcrumbStatus: 'hidden' /* management sub-pages set their breadcrumbs themselves */,
+ spaceBefore: 'm',
+ },
+ {
+ title: i18n.translate('xpack.serverlessSearch.nav.content.pipelines', {
+ defaultMessage: 'Pipelines',
+ }),
+ link: 'management:ingest_pipelines',
+ breadcrumbStatus: 'hidden' /* management sub-pages set their breadcrumbs themselves */,
+ },
+ {
+ title: CONNECTORS_LABEL,
+ link: 'serverlessConnectors',
+ },
+ {
+ link: 'management:api_keys',
+ breadcrumbStatus: 'hidden' /* management sub-pages set their breadcrumbs themselves */,
+ spaceBefore: 'm',
},
],
},
diff --git a/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.test.tsx b/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.test.tsx
index 989c4fd45cfbc..b729824478e2c 100644
--- a/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.test.tsx
+++ b/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.test.tsx
@@ -10,7 +10,7 @@ import React from 'react';
import { AppContextTestRender, createAppRootMockRenderer } from '../../test';
import { DetailPanelAlertTab } from '.';
import { mockAlerts } from '../../../common/mocks/constants/session_view_process.mock';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import { INVESTIGATED_ALERT_TEST_ID, VIEW_MODE_TOGGLE, ALERTS_TAB_EMPTY_STATE_TEST_ID } from '.';
import {
ALERT_LIST_ITEM_TEST_ID,
diff --git a/x-pack/plugins/session_view/public/components/session_view_search_bar/index.test.tsx b/x-pack/plugins/session_view/public/components/session_view_search_bar/index.test.tsx
index 8b3498f2a11b8..4bfd695530b43 100644
--- a/x-pack/plugins/session_view/public/components/session_view_search_bar/index.test.tsx
+++ b/x-pack/plugins/session_view/public/components/session_view_search_bar/index.test.tsx
@@ -10,7 +10,7 @@ import { processMock } from '../../../common/mocks/constants/session_view_proces
import { AppContextTestRender, createAppRootMockRenderer } from '../../test';
import { SessionViewSearchBar } from '.';
import userEvent from '@testing-library/user-event';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
describe('SessionViewSearchBar component', () => {
let render: () => ReturnType;
diff --git a/x-pack/plugins/spaces/server/capabilities/index.ts b/x-pack/plugins/spaces/server/capabilities/index.ts
index 745015b50042f..801564d9990b8 100644
--- a/x-pack/plugins/spaces/server/capabilities/index.ts
+++ b/x-pack/plugins/spaces/server/capabilities/index.ts
@@ -18,5 +18,7 @@ export const setupCapabilities = (
logger: Logger
) => {
core.capabilities.registerProvider(capabilitiesProvider);
- core.capabilities.registerSwitcher(setupCapabilitiesSwitcher(core, getSpacesService, logger));
+ core.capabilities.registerSwitcher(setupCapabilitiesSwitcher(core, getSpacesService, logger), {
+ capabilityPath: '*',
+ });
};
diff --git a/x-pack/plugins/stack_connectors/README.md b/x-pack/plugins/stack_connectors/README.md
index dc4265e92e042..40199153902c0 100644
--- a/x-pack/plugins/stack_connectors/README.md
+++ b/x-pack/plugins/stack_connectors/README.md
@@ -6,6 +6,7 @@ The `stack_connectors` plugin provides connector types shipped with Kibana, buil
Table of Contents
+- [Stack Connectors](#stack-connectors)
- [Connector Types](#connector-types)
- [ServiceNow ITSM](#servicenow-itsm)
- [`params`](#params)
@@ -41,13 +42,17 @@ Table of Contents
- [Swimlane](#swimlane)
- [`params`](#params-5)
- [| severity | The severity of the incident. | string _(optional)_ |](#-severity-----the-severity-of-the-incident-----string-optional-)
+ - [Ospgenie](#ospgenie)
+ - [`params`](#params-6)
+ - [PagerDuty](#pagerduty)
+ - [`params`](#params-7)
- [Developing New Connector Types](#developing-new-connector-types)
- - [licensing](#licensing)
- - [plugin location](#plugin-location)
- - [documentation](#documentation)
- - [tests](#tests)
- - [connector type config and secrets](#connector-type-config-and-secrets)
- - [user interface](#user-interface)
+ - [Licensing](#licensing)
+ - [Plugin location](#plugin-location)
+ - [Documentation](#documentation)
+ - [Tests](#tests)
+ - [Connector type config and secrets](#connector-type-config-and-secrets)
+ - [User interface](#user-interface)
# Connector Types
@@ -346,9 +351,9 @@ for the full list of properties.
`subActionParams (createAlert)`
-| Property | Description | Type |
-| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- |
-| message | The alert message. | string |
+| Property | Description | Type |
+| -------- | ------------------ | ------ |
+| message | The alert message. | string |
The optional parameters `alias`, `description`, `responders`, `visibleTo`, `actions`, `tags`, `details`, `entity`, `source`, `priority`, `user`, and `note` are supported. See the [Opsgenie API documentation](https://docs.opsgenie.com/docs/alert-api#create-alert) for more information on their types.
@@ -358,6 +363,28 @@ No parameters are required. For the definition of the optional parameters see th
---
+## PagerDuty
+
+The [PagerDuty user documentation `params`](https://www.elastic.co/guide/en/kibana/master/pagerduty-action-type.html) lists configuration properties for the `params`. For more details on these properties, see [PagerDuty v2 event parameters](https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgx-send-an-alert-event) .
+
+### `params`
+
+| Property | Description | Type |
+| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
+| eventAction | The type of event. | `trigger` \| `resolve` \| `acknowledge` |
+| dedupKey | All actions sharing this key will be associated with the same PagerDuty alert. This value is used to correlate trigger and resolution. The maximum length is 255 characters. | string |
+| summary | An optional text summary of the event. The maximum length is 1024 characters. | string _(optional)_ |
+| source | An optional value indicating the affected system, preferably a hostname or fully qualified domain name. Defaults to the Kibana saved object id of the action. | string _(optional)_ |
+| severity | The perceived severity of on the affected system. Default: `info`. | `critical` \| `error` \| `warning` \| `info` |
+| timestamp | An optional ISO-8601 format date-time, indicating the time the event was detected or generated. | date _(optional)_ |
+| component | An optional value indicating the component of the source machine that is responsible for the event, for example `mysql` or `eth0`. | string _(optional)_ |
+| group | An optional value indicating the logical grouping of components of a service, for example `app-stack`. | string _(optional)_ |
+| class | An optional value indicating the class/type of the event, for example `ping failure` or `cpu load`. | string _(optional)_ |
+| links | List of links to add to the event | Array<{ href: string; text: string }> _(optional)_ |
+| customDetails | Additional details to add to the event. | object |
+
+---
+
# Developing New Connector Types
When creating a new connector type, your plugin will eventually call `server.plugins.actions.setup.registerType()` to register the type with the `actions` plugin, but there are some additional things to think about about and implement.
diff --git a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/swimlane_connectors.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/swimlane_connectors.test.tsx
index 643d43d8b10b3..cb6652052d65e 100644
--- a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/swimlane_connectors.test.tsx
+++ b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/swimlane_connectors.test.tsx
@@ -7,14 +7,12 @@
import React from 'react';
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
-import { act } from 'react-dom/test-utils';
import SwimlaneActionConnectorFields from './swimlane_connectors';
import { useGetApplication } from './use_get_application';
import { applicationFields, mappings } from './mocks';
import { ConnectorFormTestProvider } from '../lib/test_utils';
-import { waitFor } from '@testing-library/dom';
+import { waitFor, render, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { render } from '@testing-library/react';
jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana');
jest.mock('./use_get_application');
diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts
index 10752e53ae72a..86cdca4740f6d 100644
--- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts
+++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts
@@ -316,6 +316,25 @@ describe('execute()', () => {
component: 'the-component',
group: 'the-group',
class: 'the-class',
+ customDetails: {
+ myString: 'foo',
+ myNumber: 10,
+ myArray: ['foo', 'baz'],
+ myBoolean: true,
+ myObject: {
+ myNestedObject: 'foo',
+ },
+ },
+ links: [
+ {
+ href: 'http://example.com',
+ text: 'a link',
+ },
+ {
+ href: 'http://example.com',
+ text: 'a second link',
+ },
+ ],
};
postPagerdutyMock.mockImplementation(() => {
@@ -340,9 +359,31 @@ describe('execute()', () => {
"data": Object {
"dedup_key": "a-dedup-key",
"event_action": "trigger",
+ "links": Array [
+ Object {
+ "href": "http://example.com",
+ "text": "a link",
+ },
+ Object {
+ "href": "http://example.com",
+ "text": "a second link",
+ },
+ ],
"payload": Object {
"class": "the-class",
"component": "the-component",
+ "custom_details": Object {
+ "myArray": Array [
+ "foo",
+ "baz",
+ ],
+ "myBoolean": true,
+ "myNumber": 10,
+ "myObject": Object {
+ "myNestedObject": "foo",
+ },
+ "myString": "foo",
+ },
"group": "the-group",
"severity": "critical",
"source": "the-source",
@@ -383,6 +424,25 @@ describe('execute()', () => {
component: 'the-component',
group: 'the-group',
class: 'the-class',
+ customDetails: {
+ myString: 'foo',
+ myNumber: 10,
+ myArray: ['foo', 'baz'],
+ myBoolean: true,
+ myObject: {
+ myNestedObject: 'foo',
+ },
+ },
+ links: [
+ {
+ href: 'http://example.com',
+ text: 'a link',
+ },
+ {
+ href: 'http://example.com',
+ text: 'a second link',
+ },
+ ],
};
postPagerdutyMock.mockImplementation(() => {
@@ -441,6 +501,25 @@ describe('execute()', () => {
component: 'the-component',
group: 'the-group',
class: 'the-class',
+ customDetails: {
+ myString: 'foo',
+ myNumber: 10,
+ myArray: ['foo', 'baz'],
+ myBoolean: true,
+ myObject: {
+ myNestedObject: 'foo',
+ },
+ },
+ links: [
+ {
+ href: 'http://example.com',
+ text: 'a link',
+ },
+ {
+ href: 'http://example.com',
+ text: 'a second link',
+ },
+ ],
};
postPagerdutyMock.mockImplementation(() => {
diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts
index 76a19836b0cda..6d2ee36e6439a 100644
--- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts
+++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts
@@ -79,6 +79,9 @@ const PayloadSeveritySchema = schema.oneOf([
schema.literal('info'),
]);
+const LinksSchema = schema.arrayOf(schema.object({ href: schema.string(), text: schema.string() }));
+const customDetailsSchema = schema.recordOf(schema.string(), schema.any());
+
const ParamsSchema = schema.object(
{
eventAction: schema.maybe(EventActionSchema),
@@ -90,6 +93,8 @@ const ParamsSchema = schema.object(
component: schema.maybe(schema.string()),
group: schema.maybe(schema.string()),
class: schema.maybe(schema.string()),
+ links: schema.maybe(LinksSchema),
+ customDetails: schema.maybe(customDetailsSchema),
},
{ validate: validateParams }
);
@@ -292,7 +297,9 @@ interface PagerDutyPayload {
component?: string;
group?: string;
class?: string;
+ custom_details?: Record;
};
+ links?: Array<{ href: string; text: string }>;
}
function getBodyForEventAction(actionId: string, params: ActionParamsType): PagerDutyPayload {
@@ -301,6 +308,7 @@ function getBodyForEventAction(actionId: string, params: ActionParamsType): Page
const data: PagerDutyPayload = {
event_action: eventAction,
};
+
if (params.dedupKey) {
data.dedup_key = params.dedupKey;
}
@@ -318,7 +326,12 @@ function getBodyForEventAction(actionId: string, params: ActionParamsType): Page
severity: params.severity || 'info',
...(validatedTimestamp ? { timestamp: moment(validatedTimestamp).toISOString() } : {}),
...omitBy(pick(params, ['component', 'group', 'class']), isUndefined),
+ ...(params.customDetails ? { custom_details: params.customDetails } : {}),
};
+ if (params.links) {
+ data.links = params.links;
+ }
+
return data;
}
diff --git a/x-pack/plugins/synthetics/kibana.jsonc b/x-pack/plugins/synthetics/kibana.jsonc
index d03d0d384938f..9e85c2ec6c604 100644
--- a/x-pack/plugins/synthetics/kibana.jsonc
+++ b/x-pack/plugins/synthetics/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/synthetics-plugin",
- "owner": "@elastic/uptime",
+ "owner": "@elastic/obs-ux-infra_services-team",
"description": "This plugin visualizes data from Synthetics and Heartbeat, and integrates with other Observability solutions.",
"plugin": {
"id": "synthetics",
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx
index a78710dd9994e..1a0ec3002655a 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx
@@ -10,7 +10,7 @@ import { SyntheticsDatePicker } from './synthetics_date_picker';
import { startPlugins } from '../../../utils/testing/__mocks__/synthetics_plugin_start_mock';
import { createMemoryHistory } from 'history';
import { render } from '../../../utils/testing';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
describe('SyntheticsDatePicker component', () => {
jest.setTimeout(10_000);
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/simple_monitor_form.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/simple_monitor_form.test.tsx
index 9c392b6a409f0..322cc2c653ef9 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/simple_monitor_form.test.tsx
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/getting_started/simple_monitor_form.test.tsx
@@ -12,10 +12,9 @@ import {
WEBSITE_URL_HELP_TEXT,
WEBSITE_URL_LABEL,
} from './simple_monitor_form';
-import { screen } from '@testing-library/react';
import { render } from '../../utils/testing';
import React from 'react';
-import { act, fireEvent, waitFor } from '@testing-library/react';
+import { act, fireEvent, waitFor, screen } from '@testing-library/react';
import { syntheticsTestSubjects } from '../../../../../common/constants/data_test_subjects';
import { apiService } from '../../../../utils/api_service';
import * as reduxHooks from 'react-redux';
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_marker/waterfall_marker_icon.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_marker/waterfall_marker_icon.test.tsx
index 3ebbb2b1c6b57..a91da97ce3a5c 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_marker/waterfall_marker_icon.test.tsx
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_marker/waterfall_marker_icon.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { fireEvent, waitFor } from '@testing-library/dom';
+import { fireEvent, waitFor } from '@testing-library/react';
import { WaterfallMarkerIcon } from './waterfall_marker_icon';
import { TestWrapper } from './waterfall_marker_test_helper';
import { render } from '../../../../../utils/testing';
diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx
index 27452ce3254c2..552229fe47346 100644
--- a/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx
+++ b/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/rtl_helpers.tsx
@@ -6,12 +6,14 @@
*/
import React, { ReactElement, ReactNode } from 'react';
+import { i18n } from '@kbn/i18n';
import { of } from 'rxjs';
// eslint-disable-next-line import/no-extraneous-dependencies
import {
render as reactTestLibRender,
MatcherFunction,
RenderOptions,
+ configure,
} from '@testing-library/react';
import { Router } from '@kbn/shared-ux-router';
import { Route } from '@kbn/shared-ux-router';
@@ -21,8 +23,6 @@ import { createMemoryHistory, History } from 'history';
import { CoreStart } from '@kbn/core/public';
import { I18nProvider } from '@kbn/i18n-react';
import { coreMock } from '@kbn/core/public/mocks';
-// eslint-disable-next-line import/no-extraneous-dependencies
-import { configure } from '@testing-library/dom';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public';
import { KibanaContextProvider, KibanaServices } from '@kbn/kibana-react-plugin/public';
@@ -161,7 +161,13 @@ export const mockCore: () => Partial = () => {
exploratoryView: {
createExploratoryViewUrl: jest.fn(),
getAppDataView: jest.fn(),
- ExploratoryViewEmbeddable: () => Embeddable exploratory view
,
+ ExploratoryViewEmbeddable: () => (
+
+ {i18n.translate('xpack.synthetics.core.div.embeddableExploratoryViewLabel', {
+ defaultMessage: 'Embeddable exploratory view',
+ })}
+
+ ),
},
};
diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/add_monitor_project.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/add_monitor_project.ts
index e3ca890d1712e..f878e8bb40c70 100644
--- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/add_monitor_project.ts
+++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/add_monitor_project.ts
@@ -102,8 +102,11 @@ export const validatePermissions = async (
const elasticManagedLocationsEnabled =
Boolean(
- (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime
- .elasticManagedLocationsEnabled
+ (
+ await server.coreStart?.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'uptime.*',
+ })
+ ).uptime.elasticManagedLocationsEnabled
) ?? true;
if (!elasticManagedLocationsEnabled) {
return ELASTIC_MANAGED_LOCATIONS_DISABLED;
diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts
index c6ff9852b6777..d9e9b918e3fff 100644
--- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts
+++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts
@@ -251,8 +251,11 @@ export const validatePermissions = async (
const elasticManagedLocationsEnabled =
Boolean(
- (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime
- .elasticManagedLocationsEnabled
+ (
+ await server.coreStart?.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'uptime.*',
+ })
+ ).uptime.elasticManagedLocationsEnabled
) ?? true;
if (!elasticManagedLocationsEnabled) {
return ELASTIC_MANAGED_LOCATIONS_DISABLED;
diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_api_key.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_api_key.ts
index 0dab70565aeea..53cd56fc24bf6 100644
--- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_api_key.ts
+++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_api_key.ts
@@ -34,8 +34,11 @@ export const getAPIKeySyntheticsRoute: SyntheticsRestApiRouteFactory = () => ({
if (accessToElasticManagedLocations) {
const elasticManagedLocationsEnabled =
Boolean(
- (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime
- .elasticManagedLocationsEnabled
+ (
+ await server.coreStart?.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'uptime.*',
+ })
+ ).uptime.elasticManagedLocationsEnabled
) ?? true;
if (!elasticManagedLocationsEnabled) {
return response.customError({
diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts
index 549c812eec27f..b693718e7a63b 100644
--- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts
+++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts
@@ -52,7 +52,11 @@ export const getSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({
} else {
// only user with write permissions can decrypt the monitor
const canSave =
- (await coreStart?.capabilities.resolveCapabilities(request)).uptime.save ?? false;
+ (
+ await coreStart?.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'uptime.*',
+ })
+ ).uptime.save ?? false;
if (!canSave) {
return response.forbidden();
}
diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/inspect_monitor.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/inspect_monitor.ts
index 0cbdda79c18eb..78f445190d2e9 100644
--- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/inspect_monitor.ts
+++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/inspect_monitor.ts
@@ -54,8 +54,13 @@ export const inspectSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () =
);
const canSave =
- Boolean((await server.coreStart?.capabilities.resolveCapabilities(request)).uptime.save) ??
- false;
+ Boolean(
+ (
+ await server.coreStart?.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'uptime.*',
+ })
+ ).uptime.save
+ ) ?? false;
try {
const newMonitorId = id ?? uuidV4();
diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/params.ts b/x-pack/plugins/synthetics/server/routes/settings/params/params.ts
index 8f9f4f76efd89..01f2dd6465dfd 100644
--- a/x-pack/plugins/synthetics/server/routes/settings/params/params.ts
+++ b/x-pack/plugins/synthetics/server/routes/settings/params/params.ts
@@ -37,7 +37,11 @@ export const getSyntheticsParamsRoute: SyntheticsRestApiRouteFactory<
const encryptedSavedObjectsClient = server.encryptedSavedObjects.getClient();
const canSave =
- (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime.save ?? false;
+ (
+ await server.coreStart?.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'uptime.*',
+ })
+ ).uptime.save ?? false;
if (canSave) {
if (paramId) {
diff --git a/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts b/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts
index 24660c537a238..a9142170c9e26 100644
--- a/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts
+++ b/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts
@@ -23,8 +23,11 @@ export const getServiceLocationsRoute: SyntheticsRestApiRouteFactory = () => ({
}): Promise => {
const elasticManagedLocationsEnabled =
Boolean(
- (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime
- .elasticManagedLocationsEnabled
+ (
+ await server.coreStart?.capabilities.resolveCapabilities(request, {
+ capabilityPath: 'uptime.*',
+ })
+ ).uptime.elasticManagedLocationsEnabled
) ?? true;
if (elasticManagedLocationsEnabled) {
diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx
index 370d7c2da05d5..4f9eacc38ecc5 100644
--- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx
+++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx
@@ -5,14 +5,13 @@
* 2.0.
*/
-import { render, fireEvent, screen, waitFor } from '@testing-library/react';
+import { render, fireEvent, screen, waitFor, within } from '@testing-library/react';
import React from 'react';
import moment from 'moment-timezone';
import { TransformListRow } from '../../../../common';
import { ExpandedRow } from './expanded_row';
import transformListRow from '../../../../common/__mocks__/transform_list_row.json';
-import { within } from '@testing-library/dom';
jest.mock('../../../../../shared_imports');
jest.mock('../../../../app_dependencies');
diff --git a/x-pack/plugins/transform/server/capabilities.ts b/x-pack/plugins/transform/server/capabilities.ts
index 5fd542d428a70..58d47cbb5ca41 100644
--- a/x-pack/plugins/transform/server/capabilities.ts
+++ b/x-pack/plugins/transform/server/capabilities.ts
@@ -127,50 +127,55 @@ export const setupCapabilities = (
};
});
- core.capabilities.registerSwitcher(async (request, capabilities, useDefaultCapabilities) => {
- if (useDefaultCapabilities) {
- return {};
- }
-
- const isSecurityPluginEnabled = securitySetup?.license.isEnabled() ?? false;
- const startServices = await core.getStartServices();
- const [, { security: securityStart }] = startServices;
+ core.capabilities.registerSwitcher(
+ async (request, capabilities, useDefaultCapabilities) => {
+ if (useDefaultCapabilities) {
+ return {};
+ }
+
+ const isSecurityPluginEnabled = securitySetup?.license.isEnabled() ?? false;
+ const startServices = await core.getStartServices();
+ const [, { security: securityStart }] = startServices;
+
+ // If security is not enabled or not available, transform should have full permission
+ if (!isSecurityPluginEnabled || !securityStart) {
+ return {
+ transform: getInitialTransformCapabilities(true),
+ };
+ }
+
+ const checkPrivileges = securityStart.authz.checkPrivilegesDynamicallyWithRequest(request);
+
+ const { hasAllRequested, privileges } = await checkPrivileges({
+ elasticsearch: {
+ cluster: APP_CLUSTER_PRIVILEGES,
+ index: {},
+ },
+ });
+
+ const clusterPrivileges: Record = Array.isArray(
+ privileges?.elasticsearch?.cluster
+ )
+ ? privileges.elasticsearch.cluster.reduce>((acc, p) => {
+ acc[p.privilege] = p.authorized;
+ return acc;
+ }, {})
+ : {};
+
+ const hasOneIndexWithAllPrivileges = false;
+
+ const transformCapabilities = getPrivilegesAndCapabilities(
+ clusterPrivileges,
+ hasOneIndexWithAllPrivileges,
+ hasAllRequested
+ ).capabilities;
- // If security is not enabled or not available, transform should have full permission
- if (!isSecurityPluginEnabled || !securityStart) {
return {
- transform: getInitialTransformCapabilities(true),
+ transform: transformCapabilities as Record>,
};
+ },
+ {
+ capabilityPath: 'transform.*',
}
-
- const checkPrivileges = securityStart.authz.checkPrivilegesDynamicallyWithRequest(request);
-
- const { hasAllRequested, privileges } = await checkPrivileges({
- elasticsearch: {
- cluster: APP_CLUSTER_PRIVILEGES,
- index: {},
- },
- });
-
- const clusterPrivileges: Record = Array.isArray(
- privileges?.elasticsearch?.cluster
- )
- ? privileges.elasticsearch.cluster.reduce>((acc, p) => {
- acc[p.privilege] = p.authorized;
- return acc;
- }, {})
- : {};
-
- const hasOneIndexWithAllPrivileges = false;
-
- const transformCapabilities = getPrivilegesAndCapabilities(
- clusterPrivileges,
- hasOneIndexWithAllPrivileges,
- hasAllRequested
- ).capabilities;
-
- return {
- transform: transformCapabilities as Record>,
- };
- });
+ );
};
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index c06aff873c9bf..d00b542c58131 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -9023,7 +9023,6 @@
"xpack.apm.mobile.charts.nct": "Type de connexion réseau",
"xpack.apm.mobile.charts.noResultsFound": "Résultat introuvable",
"xpack.apm.mobile.charts.osVersion": "Version du système d'exploitation",
- "xpack.apm.mobile.coming.soon": "Bientôt disponible",
"xpack.apm.mobile.filters.appVersion": "Version de l'application",
"xpack.apm.mobile.filters.device": "Appareil",
"xpack.apm.mobile.filters.nct": "NCT",
@@ -37250,16 +37249,13 @@
"xpack.serverlessSearch.languages.ruby.githubLabel": "elasticsearch-serverless-ruby",
"xpack.serverlessSearch.learnMore": "En savoir plus",
"xpack.serverlessSearch.nav.alerts": "Alertes",
- "xpack.serverlessSearch.nav.content": "Contenu",
"xpack.serverlessSearch.nav.content.indices": "Gestion des index",
"xpack.serverlessSearch.nav.content.pipelines": "Pipelines",
"xpack.serverlessSearch.nav.devTools": "Outils de développement",
- "xpack.serverlessSearch.nav.explore": "Explorer",
"xpack.serverlessSearch.nav.gettingStarted": "Premiers pas",
"xpack.serverlessSearch.nav.mngt": "Gestion",
"xpack.serverlessSearch.nav.performance": "Performances",
"xpack.serverlessSearch.nav.projectSettings": "Paramètres de projet",
- "xpack.serverlessSearch.nav.security": "Sécurité",
"xpack.serverlessSearch.next": "Suivant",
"xpack.serverlessSearch.optional": "Facultatif",
"xpack.serverlessSearch.overview.footer.description": "Votre point de terminaison Elasticsearch est configuré et vous avez effectué quelques requêtes de base. Vous voilà prêt à approfondir les outils et les cas d'utilisation avancés.",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 5f27f5b60da13..1ce0c2df38db5 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -9038,7 +9038,6 @@
"xpack.apm.mobile.charts.nct": "ネットワーク接続タイプ",
"xpack.apm.mobile.charts.noResultsFound": "結果が見つかりませんでした",
"xpack.apm.mobile.charts.osVersion": "OSバージョン",
- "xpack.apm.mobile.coming.soon": "まもなくリリース",
"xpack.apm.mobile.filters.appVersion": "アプリバージョン",
"xpack.apm.mobile.filters.device": "デバイス",
"xpack.apm.mobile.filters.nct": "NCT",
@@ -37248,16 +37247,13 @@
"xpack.serverlessSearch.languages.ruby.githubLabel": "elasticsearch-serverless-ruby",
"xpack.serverlessSearch.learnMore": "詳細",
"xpack.serverlessSearch.nav.alerts": "アラート",
- "xpack.serverlessSearch.nav.content": "コンテンツ",
"xpack.serverlessSearch.nav.content.indices": "インデックス管理",
"xpack.serverlessSearch.nav.content.pipelines": "パイプライン",
"xpack.serverlessSearch.nav.devTools": "開発ツール",
- "xpack.serverlessSearch.nav.explore": "探索",
"xpack.serverlessSearch.nav.gettingStarted": "はじめて使う",
"xpack.serverlessSearch.nav.mngt": "管理",
"xpack.serverlessSearch.nav.performance": "パフォーマンス",
"xpack.serverlessSearch.nav.projectSettings": "プロジェクト設定",
- "xpack.serverlessSearch.nav.security": "セキュリティ",
"xpack.serverlessSearch.next": "次へ",
"xpack.serverlessSearch.optional": "オプション",
"xpack.serverlessSearch.overview.footer.description": "Elasticsearchエンドポイントが設定され、いくつかの基本的なクエリが作成されました。これで、より高度なツールやユースケースを使いこなす準備が整いました。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 7c8328a39f987..2fd8d38a579a5 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -9037,7 +9037,6 @@
"xpack.apm.mobile.charts.nct": "网络连接类型",
"xpack.apm.mobile.charts.noResultsFound": "找不到结果",
"xpack.apm.mobile.charts.osVersion": "操作系统版本",
- "xpack.apm.mobile.coming.soon": "即将推出",
"xpack.apm.mobile.filters.appVersion": "应用版本",
"xpack.apm.mobile.filters.device": "设备",
"xpack.apm.mobile.filters.nct": "NCT",
@@ -37244,16 +37243,13 @@
"xpack.serverlessSearch.languages.ruby.githubLabel": "elasticsearch-serverless-ruby",
"xpack.serverlessSearch.learnMore": "了解详情",
"xpack.serverlessSearch.nav.alerts": "告警",
- "xpack.serverlessSearch.nav.content": "内容",
"xpack.serverlessSearch.nav.content.indices": "索引管理",
"xpack.serverlessSearch.nav.content.pipelines": "管道",
"xpack.serverlessSearch.nav.devTools": "开发工具",
- "xpack.serverlessSearch.nav.explore": "浏览",
"xpack.serverlessSearch.nav.gettingStarted": "入门",
"xpack.serverlessSearch.nav.mngt": "管理",
"xpack.serverlessSearch.nav.performance": "性能",
"xpack.serverlessSearch.nav.projectSettings": "项目设置",
- "xpack.serverlessSearch.nav.security": "安全",
"xpack.serverlessSearch.next": "下一步",
"xpack.serverlessSearch.optional": "可选",
"xpack.serverlessSearch.overview.footer.description": "已设置您的 Elasticsearch 终端,并且您已提出一些基本查询。现在您已准备就绪,可以更深入地了解更多高级工具和用例。",
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx
index bf792e29ed604..c4e3ec261e6e3 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
import { renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useGetQueryDelaySettings } from './use_get_query_delay_settings';
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx
index b9f33ab40c6fc..6ea281765496f 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx
@@ -11,7 +11,7 @@ import { RuleStatus } from '../../types';
import { useKibana } from '../../common/lib/kibana';
import { IToasts } from '@kbn/core-notifications-browser';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
jest.mock('../../common/lib/kibana');
jest.mock('../lib/rule_api/aggregate_kuery_filter', () => ({
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx
index 1342746223889..1a2c07eaaa9cf 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx
@@ -15,7 +15,7 @@ import { RuleStatus } from '../../types';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useKibana } from '../../common/lib/kibana';
import { IToasts } from '@kbn/core-notifications-browser';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
jest.mock('../../common/lib/kibana');
jest.mock('../lib/rule_api/rules_kuery_filter', () => ({
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx
index 7e36b5e4290ad..bb2dab67c0d4e 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx
@@ -10,7 +10,7 @@ import { useLoadTagsQuery } from './use_load_tags_query';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useKibana } from '../../common/lib/kibana';
import { IToasts } from '@kbn/core-notifications-browser';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
const MOCK_TAGS = ['a', 'b', 'c'];
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx
index 6a36a32ed2522..e431a4c2cf7aa 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { act, renderHook } from '@testing-library/react-hooks/dom';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { useUpdateRuleSettings } from './use_update_rules_settings';
const mockAddDanger = jest.fn();
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form.test.tsx
index 95e7b0c85ab55..cf12e2ce38af4 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form.test.tsx
@@ -9,7 +9,7 @@ import React, { lazy } from 'react';
import { ConnectorForm } from './connector_form';
import { actionTypeRegistryMock } from '../../action_type_registry.mock';
import userEvent from '@testing-library/user-event';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { act } from '@testing-library/react';
import { AppMockRenderer, createAppMockRenderer } from '../test_utils';
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields.test.tsx
index c2a6a86bb446b..45937cee8b22a 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields.test.tsx
@@ -10,7 +10,7 @@ import { coreMock } from '@kbn/core/public/mocks';
import { FormTestProvider } from '../../components/test_utils';
import { ConnectorFormFields } from './connector_form_fields';
import { actionTypeRegistryMock } from '../../action_type_registry.mock';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { AppMockRenderer, createAppMockRenderer } from '../test_utils';
describe('ConnectorFormFields', () => {
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/create_connector_flyout/index.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/create_connector_flyout/index.test.tsx
index 9cc4603025ff3..554fb9aff3c30 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/create_connector_flyout/index.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/create_connector_flyout/index.test.tsx
@@ -9,8 +9,7 @@ import React, { lazy } from 'react';
import { actionTypeRegistryMock } from '../../../action_type_registry.mock';
import userEvent from '@testing-library/user-event';
-import { waitFor } from '@testing-library/dom';
-import { act } from '@testing-library/react';
+import { waitFor, act } from '@testing-library/react';
import CreateConnectorFlyout from '.';
import { betaBadgeProps } from '../beta_badge_props';
import { AppMockRenderer, createAppMockRenderer } from '../../test_utils';
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/edit_connector_flyout/index.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/edit_connector_flyout/index.test.tsx
index e687189ed0205..a108de1dc6f6c 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/edit_connector_flyout/index.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/edit_connector_flyout/index.test.tsx
@@ -9,8 +9,7 @@ import React, { lazy } from 'react';
import { actionTypeRegistryMock } from '../../../action_type_registry.mock';
import userEvent from '@testing-library/user-event';
-import { waitFor } from '@testing-library/dom';
-import { act } from '@testing-library/react';
+import { waitFor, act } from '@testing-library/react';
import EditConnectorFlyout from '.';
import { ActionConnector, EditConnectorTabs, GenericValidationResult } from '../../../../types';
import { betaBadgeProps } from '../beta_badge_props';
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx
index 5f027e9b57fd0..945028df8118f 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx
@@ -7,7 +7,7 @@
import { renderHook } from '@testing-library/react-hooks';
import * as api from './apis/bulk_get_cases';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { useKibana } from '../../../../common/lib/kibana';
import { useBulkGetCases } from './use_bulk_get_cases';
import { AppMockRenderer, createAppMockRenderer } from '../../test_utils';
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts
index e5b45a25b5dea..b46424c286c00 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts
+++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts
@@ -6,7 +6,7 @@
*/
import { renderHook } from '@testing-library/react-hooks';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
import { MaintenanceWindowStatus } from '@kbn/alerting-plugin/common';
import * as api from './apis/bulk_get_maintenance_windows';
import { coreMock } from '@kbn/core/public/mocks';
diff --git a/x-pack/plugins/uptime/kibana.jsonc b/x-pack/plugins/uptime/kibana.jsonc
index df0b2e13839cf..c07d0dc342a74 100644
--- a/x-pack/plugins/uptime/kibana.jsonc
+++ b/x-pack/plugins/uptime/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/uptime-plugin",
- "owner": "@elastic/uptime",
+ "owner": "@elastic/obs-ux-infra_services-team",
"description": "This plugin visualizes data from Heartbeat, and integrates with other Observability solutions.",
"plugin": {
"id": "uptime",
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/common/uptime_date_picker.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/common/uptime_date_picker.test.tsx
index 1510fe28f1721..66fd680d3fdfe 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/components/common/uptime_date_picker.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/components/common/uptime_date_picker.test.tsx
@@ -10,7 +10,7 @@ import { UptimeDatePicker } from './uptime_date_picker';
import { startPlugins } from '../../lib/__mocks__/uptime_plugin_start_mock';
import { createMemoryHistory } from 'history';
import { render } from '../../lib/helper/rtl_helpers';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
describe('UptimeDatePicker component', () => {
jest.setTimeout(10_000);
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall.test.tsx
index 28e82930f3341..7761fe4206fda 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall.test.tsx
@@ -11,7 +11,7 @@ import { renderLegendItem } from '../../step_detail/waterfall/waterfall_chart_wr
import { render } from '../../../../../lib/helper/rtl_helpers';
import 'jest-canvas-mock';
-import { waitFor } from '@testing-library/dom';
+import { waitFor } from '@testing-library/react';
describe('waterfall', () => {
it('sets the correct height in case of full height', () => {
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall_marker_icon.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall_marker_icon.test.tsx
index 4241a7238ecd6..4bfe9d2dccfdd 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall_marker_icon.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/synthetics/waterfall/components/waterfall_marker_icon.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { fireEvent, waitFor } from '@testing-library/dom';
+import { fireEvent, waitFor } from '@testing-library/react';
import { render } from '../../../../../lib/helper/rtl_helpers';
import { WaterfallMarkerIcon } from './waterfall_marker_icon';
import { TestWrapper } from './waterfall_marker_test_helper';
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_status_alert/alert_monitor_status.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_status_alert/alert_monitor_status.test.tsx
index 6dbef12159a18..c547b66748ffc 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_status_alert/alert_monitor_status.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_status_alert/alert_monitor_status.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { screen } from '@testing-library/dom';
+import { screen } from '@testing-library/react';
import {
AlertMonitorStatusComponent,
AlertMonitorStatusProps,
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx
index 29f0dd189594c..3774e94e190b8 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/define_connectors.test.tsx
@@ -7,8 +7,7 @@
import React from 'react';
import { DefineAlertConnectors } from './define_connectors';
-import { screen } from '@testing-library/react';
-import { fireEvent } from '@testing-library/dom';
+import { screen, fireEvent } from '@testing-library/react';
import { ENABLE_STATUS_ALERT } from './translations';
import { render } from '../../../../lib/helper/rtl_helpers';
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.test.tsx
index 416dd8e963e9b..2f18c3e89f147 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/monitor_list/columns/enable_alert.test.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import { EnableMonitorAlert } from './enable_alert';
-import { fireEvent } from '@testing-library/dom';
+import { fireEvent } from '@testing-library/react';
import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../common/constants';
import { makePing } from '../../../../../../common/runtime_types/ping';
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/synthetics/check_steps/use_expanded_row.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/synthetics/check_steps/use_expanded_row.test.tsx
index f79a93eee53e4..a139abe5d86a0 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/components/synthetics/check_steps/use_expanded_row.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/components/synthetics/check_steps/use_expanded_row.test.tsx
@@ -8,7 +8,7 @@
import React from 'react';
import ReactRouterDom from 'react-router-dom';
import { Route } from '@kbn/shared-ux-router';
-import { fireEvent, screen } from '@testing-library/dom';
+import { fireEvent, screen } from '@testing-library/react';
import { renderHook, act as hooksAct } from '@testing-library/react-hooks';
import { createMemoryHistory } from 'history';
import { EuiButtonIcon } from '@elastic/eui';
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/lib/helper/rtl_helpers.tsx b/x-pack/plugins/uptime/public/legacy_uptime/lib/helper/rtl_helpers.tsx
index b2f96c4bac8a3..0b23c089385d7 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/lib/helper/rtl_helpers.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/lib/helper/rtl_helpers.tsx
@@ -12,6 +12,7 @@ import {
render as reactTestLibRender,
MatcherFunction,
RenderOptions,
+ configure,
} from '@testing-library/react';
import { Router } from '@kbn/shared-ux-router';
import { Route } from '@kbn/shared-ux-router';
@@ -21,8 +22,6 @@ import { createMemoryHistory, History } from 'history';
import { CoreStart } from '@kbn/core/public';
import { I18nProvider } from '@kbn/i18n-react';
import { coreMock } from '@kbn/core/public/mocks';
-// eslint-disable-next-line import/no-extraneous-dependencies
-import { configure } from '@testing-library/dom';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public';
import { KibanaContextProvider, KibanaServices } from '@kbn/kibana-react-plugin/public';
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/pages/settings.test.tsx b/x-pack/plugins/uptime/public/legacy_uptime/pages/settings.test.tsx
index 5c8fb95448fca..a8144f540a03e 100644
--- a/x-pack/plugins/uptime/public/legacy_uptime/pages/settings.test.tsx
+++ b/x-pack/plugins/uptime/public/legacy_uptime/pages/settings.test.tsx
@@ -8,7 +8,7 @@ import React from 'react';
import { isValidCertVal, SettingsPage } from './settings';
import { render } from '../lib/helper/rtl_helpers';
-import { fireEvent, waitFor } from '@testing-library/dom';
+import { fireEvent, waitFor } from '@testing-library/react';
import * as alertApi from '../state/api/alerts';
import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants';
diff --git a/x-pack/plugins/ux/kibana.jsonc b/x-pack/plugins/ux/kibana.jsonc
index af8d92f151786..e35cddbabbba6 100644
--- a/x-pack/plugins/ux/kibana.jsonc
+++ b/x-pack/plugins/ux/kibana.jsonc
@@ -1,7 +1,7 @@
{
"type": "plugin",
"id": "@kbn/ux-plugin",
- "owner": "@elastic/uptime",
+ "owner": "@elastic/obs-ux-infra_services-team",
"plugin": {
"id": "ux",
"server": true,
diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts
index 81a3c2ef966b9..7148ac962c728 100644
--- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts
+++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts
@@ -175,6 +175,47 @@ export default function pagerdutyTest({ getService }: FtrProviderContext) {
});
});
+ it('should execute successfully with links and customDetails', async () => {
+ const { body: result } = await supertest
+ .post(`/api/actions/connector/${simulatedActionId}/_execute`)
+ .set('kbn-xsrf', 'foo')
+ .send({
+ params: {
+ summary: 'just a test',
+ customDetails: {
+ myString: 'foo',
+ myNumber: 10,
+ myArray: ['foo', 'baz'],
+ myBoolean: true,
+ myObject: {
+ myNestedObject: 'foo',
+ },
+ },
+ links: [
+ {
+ href: 'http://example.com',
+ text: 'a link',
+ },
+ {
+ href: 'http://example.com',
+ text: 'a second link',
+ },
+ ],
+ },
+ })
+ .expect(200);
+
+ expect(proxyHaveBeenCalled).to.equal(true);
+ expect(result).to.eql({
+ status: 'ok',
+ connector_id: simulatedActionId,
+ data: {
+ message: 'Event processed',
+ status: 'success',
+ },
+ });
+ });
+
it('should handle a 40x pagerduty error', async () => {
const { body: result } = await supertest
.post(`/api/actions/connector/${simulatedActionId}/_execute`)
diff --git a/x-pack/test/api_integration/apis/metrics_ui/constants.ts b/x-pack/test/api_integration/apis/metrics_ui/constants.ts
index 7fd25f09875b4..13fd1acf7b199 100644
--- a/x-pack/test/api_integration/apis/metrics_ui/constants.ts
+++ b/x-pack/test/api_integration/apis/metrics_ui/constants.ts
@@ -40,7 +40,7 @@ export const DATES = {
},
logs_and_metrics_with_aws: {
min: 1564083185000,
- max: 1564083493080,
+ max: 1564083705100,
},
},
'alert-test-data': {
diff --git a/x-pack/test/apm_api_integration/tests/mobile/mobile_stats.spec.ts b/x-pack/test/apm_api_integration/tests/mobile/mobile_stats.spec.ts
index edc852d97ad2a..f7bb8f328d220 100644
--- a/x-pack/test/apm_api_integration/tests/mobile/mobile_stats.spec.ts
+++ b/x-pack/test/apm_api_integration/tests/mobile/mobile_stats.spec.ts
@@ -10,7 +10,7 @@ import { apm, timerange } from '@kbn/apm-synthtrace-client';
import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace';
import { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api';
import { ENVIRONMENT_ALL } from '@kbn/apm-plugin/common/environment_filter_values';
-import { sumBy, meanBy } from 'lodash';
+import { meanBy, sumBy } from 'lodash';
import { FtrProviderContext } from '../../common/ftr_provider_context';
type MobileStats = APIReturnType<'GET /internal/apm/mobile-services/{serviceName}/stats'>;
@@ -101,6 +101,7 @@ async function generateData({
galaxy10.startNewSession();
huaweiP2.startNewSession();
return [
+ galaxy10.appMetrics({ 'application.launch.time': 100 }).timestamp(timestamp),
galaxy10
.transaction('Start View - View Appearing', 'Android Activity')
.errors(galaxy10.crash({ message: 'error C' }).timestamp(timestamp))
@@ -224,6 +225,14 @@ export default function ApiTest({ getService }: FtrProviderContext) {
);
expect(value).to.be(timeseriesMean);
});
+ it('returns same launch times', () => {
+ const { value, timeseries } = response.currentPeriod.launchTimes;
+ const timeseriesMean = meanBy(
+ timeseries.filter((bucket) => bucket.y !== null),
+ 'y'
+ );
+ expect(value).to.be(timeseriesMean);
+ });
});
describe('when filters are applied', () => {
@@ -237,6 +246,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(response.currentPeriod.sessions.value).to.eql(0);
expect(response.currentPeriod.requests.value).to.eql(0);
expect(response.currentPeriod.crashRate.value).to.eql(0);
+ expect(response.currentPeriod.launchTimes.value).to.eql(null);
expect(response.currentPeriod.sessions.timeseries.every((item) => item.y === 0)).to.eql(
true
@@ -247,6 +257,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(response.currentPeriod.crashRate.timeseries.every((item) => item.y === 0)).to.eql(
true
);
+ expect(
+ response.currentPeriod.launchTimes.timeseries.every((item) => item.y === null)
+ ).to.eql(true);
});
it('returns the correct values when single filter is applied', async () => {
@@ -259,6 +272,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(response.currentPeriod.sessions.value).to.eql(3);
expect(response.currentPeriod.requests.value).to.eql(0);
expect(response.currentPeriod.crashRate.value).to.eql(3);
+ expect(response.currentPeriod.launchTimes.value).to.eql(null);
});
it('returns the correct values when multiple filters are applied', async () => {
@@ -269,6 +283,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
expect(response.currentPeriod.sessions.value).to.eql(3);
expect(response.currentPeriod.requests.value).to.eql(3);
expect(response.currentPeriod.crashRate.value).to.eql(1);
+ expect(response.currentPeriod.launchTimes.value).to.eql(100);
});
});
});
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts
index 382e902424b5f..6404da38cdde7 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_rules_bulk.ts
@@ -446,7 +446,9 @@ export default ({ getService }: FtrProviderContext): void => {
.send([{ ...getSimpleRule(), investigation_fields: ['foo'] }])
.expect(400);
- expect(body.message).to.eql('[request body]: 0: Invalid input');
+ expect(body.message).to.eql(
+ '[request body]: 0.investigation_fields: Expected object, received array, 0.type: Invalid literal value, expected "eql", 0.language: Invalid literal value, expected "eql", 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, and 22 more'
+ );
});
});
});
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts
index 350ac868ac90e..ae0bfaa8940e8 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/index.ts
@@ -30,10 +30,5 @@ export default ({ loadTestFile }: FtrProviderContext): void => {
loadTestFile(require.resolve('./runtime'));
loadTestFile(require.resolve('./throttle'));
loadTestFile(require.resolve('./ignore_fields'));
- loadTestFile(require.resolve('./risk_engine/init_and_status_apis'));
- loadTestFile(require.resolve('./risk_engine/risk_score_preview'));
- loadTestFile(require.resolve('./risk_engine/risk_score_calculation'));
- loadTestFile(require.resolve('./risk_engine/risk_scoring_task_execution'));
- loadTestFile(require.resolve('./risk_engine/telemetry_usage'));
});
};
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts
index 1b2fcee9c7143..b2000305a4dbb 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts
@@ -719,7 +719,9 @@ export default ({ getService }: FtrProviderContext) => {
})
.expect(400);
- expect(body.message).to.eql('[request body]: Invalid input');
+ expect(body.message).to.eql(
+ '[request body]: investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, and 3 more'
+ );
});
it('should patch a rule with a legacy investigation field and transform response', async () => {
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts
index 4e7010a37dd49..91c18b2cfa6cc 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts
@@ -542,7 +542,9 @@ export default ({ getService }: FtrProviderContext) => {
])
.expect(400);
- expect(body.message).to.eql('[request body]: 0: Invalid input');
+ expect(body.message).to.eql(
+ '[request body]: 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, and 3 more'
+ );
});
it('should patch a rule with a legacy investigation field and transform field in response', async () => {
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts
index e9234d47a1816..2529e794089a9 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action.ts
@@ -16,8 +16,8 @@ import {
} from '@kbn/security-solution-plugin/common/constants';
import type { RuleResponse } from '@kbn/security-solution-plugin/common/api/detection_engine';
import {
- BulkActionType,
- BulkActionEditType,
+ BulkActionTypeEnum,
+ BulkActionEditTypeEnum,
} from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management';
import { getCreateExceptionListDetectionSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock';
import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants';
@@ -106,7 +106,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, getSimpleRule());
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.export })
+ .send({ query: '', action: BulkActionTypeEnum.export })
.expect(200)
.expect('Content-Type', 'application/ndjson')
.expect('Content-Disposition', 'attachment; filename="rules_export.ndjson"')
@@ -177,7 +177,7 @@ export default ({ getService }: FtrProviderContext): void => {
};
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.export })
+ .send({ query: '', action: BulkActionTypeEnum.export })
.expect(200)
.expect('Content-Type', 'application/ndjson')
.expect('Content-Disposition', 'attachment; filename="rules_export.ndjson"')
@@ -234,7 +234,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, testRule);
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.delete })
+ .send({ query: '', action: BulkActionTypeEnum.delete })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -269,7 +269,7 @@ export default ({ getService }: FtrProviderContext): void => {
expect(sidecarActionsResults.hits.hits[0]?._source?.references[0].id).to.eql(rule1.id);
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.delete })
+ .send({ query: '', action: BulkActionTypeEnum.delete })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -290,7 +290,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, getSimpleRule(ruleId));
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.enable })
+ .send({ query: '', action: BulkActionTypeEnum.enable })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -326,7 +326,7 @@ export default ({ getService }: FtrProviderContext): void => {
expect(sidecarActionsResults.hits.hits[0]?._source?.references[0].id).to.eql(rule1.id);
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.enable })
+ .send({ query: '', action: BulkActionTypeEnum.enable })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -363,7 +363,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, getSimpleRule(ruleId, true));
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.disable })
+ .send({ query: '', action: BulkActionTypeEnum.disable })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -399,7 +399,7 @@ export default ({ getService }: FtrProviderContext): void => {
expect(sidecarActionsResults.hits.hits[0]?._source?.references[0].id).to.eql(rule1.id);
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.disable })
+ .send({ query: '', action: BulkActionTypeEnum.disable })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -437,7 +437,7 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.duplicate,
+ action: BulkActionTypeEnum.duplicate,
duplicate: { include_exceptions: false, include_expired_exceptions: false },
})
.expect(200);
@@ -516,7 +516,7 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.duplicate,
+ action: BulkActionTypeEnum.duplicate,
duplicate: { include_exceptions: true, include_expired_exceptions: true },
})
.expect(200);
@@ -622,7 +622,7 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.duplicate,
+ action: BulkActionTypeEnum.duplicate,
duplicate: { include_exceptions: true, include_expired_exceptions: false },
})
.expect(200);
@@ -696,7 +696,7 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.duplicate,
+ action: BulkActionTypeEnum.duplicate,
duplicate: { include_exceptions: false, include_expired_exceptions: false },
})
.expect(200);
@@ -778,10 +778,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_tags,
+ type: BulkActionEditTypeEnum.set_tags,
value: tagsToOverwrite,
},
],
@@ -835,10 +835,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.delete_tags,
+ type: BulkActionEditTypeEnum.delete_tags,
value: tagsToDelete,
},
],
@@ -891,10 +891,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_tags,
+ type: BulkActionEditTypeEnum.add_tags,
value: addedTags,
},
],
@@ -925,21 +925,21 @@ export default ({ getService }: FtrProviderContext): void => {
existingTags: ['tag1', 'tag2', 'tag3'],
tagsToUpdate: [],
resultingTags: ['tag1', 'tag2', 'tag3'],
- operation: BulkActionEditType.delete_tags,
+ operation: BulkActionEditTypeEnum.delete_tags,
},
{
caseName: '0 existing tags - 2 tags = 0 tags',
existingTags: [],
tagsToUpdate: ['tag4', 'tag5'],
resultingTags: [],
- operation: BulkActionEditType.delete_tags,
+ operation: BulkActionEditTypeEnum.delete_tags,
},
{
caseName: '3 existing tags - 2 other tags (none of them) = 3 tags',
existingTags: ['tag1', 'tag2', 'tag3'],
tagsToUpdate: ['tag4', 'tag5'],
resultingTags: ['tag1', 'tag2', 'tag3'],
- operation: BulkActionEditType.delete_tags,
+ operation: BulkActionEditTypeEnum.delete_tags,
},
// Add no-ops
{
@@ -947,14 +947,14 @@ export default ({ getService }: FtrProviderContext): void => {
existingTags: ['tag1', 'tag2', 'tag3'],
tagsToUpdate: ['tag1', 'tag2'],
resultingTags: ['tag1', 'tag2', 'tag3'],
- operation: BulkActionEditType.add_tags,
+ operation: BulkActionEditTypeEnum.add_tags,
},
{
caseName: '3 existing tags + 0 tags = 3 tags',
existingTags: ['tag1', 'tag2', 'tag3'],
tagsToUpdate: [],
resultingTags: ['tag1', 'tag2', 'tag3'],
- operation: BulkActionEditType.add_tags,
+ operation: BulkActionEditTypeEnum.add_tags,
},
];
@@ -968,8 +968,8 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
type: operation,
value: tagsToUpdate,
@@ -1007,10 +1007,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: ['initial-index-*'],
},
],
@@ -1042,10 +1042,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['index3-*'],
},
],
@@ -1079,10 +1079,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['index2-*'],
},
],
@@ -1113,10 +1113,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [mlRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['index-*'],
},
],
@@ -1143,10 +1143,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [esqlRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['index-*'],
},
],
@@ -1176,10 +1176,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['simple-index-*'],
},
],
@@ -1209,10 +1209,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: [],
},
],
@@ -1244,21 +1244,21 @@ export default ({ getService }: FtrProviderContext): void => {
existingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
indexPatternsToUpdate: [],
resultingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
- operation: BulkActionEditType.delete_index_patterns,
+ operation: BulkActionEditTypeEnum.delete_index_patterns,
},
{
caseName: '0 existing indeces - 2 indeces = 0 indeces',
existingIndexPatterns: [],
indexPatternsToUpdate: ['index1-*', 'index2-*'],
resultingIndexPatterns: [],
- operation: BulkActionEditType.delete_index_patterns,
+ operation: BulkActionEditTypeEnum.delete_index_patterns,
},
{
caseName: '3 existing indeces - 2 other indeces (none of them) = 3 indeces',
existingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
indexPatternsToUpdate: ['index8-*', 'index9-*'],
resultingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
- operation: BulkActionEditType.delete_index_patterns,
+ operation: BulkActionEditTypeEnum.delete_index_patterns,
},
// Add no-ops
{
@@ -1266,14 +1266,14 @@ export default ({ getService }: FtrProviderContext): void => {
existingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
indexPatternsToUpdate: ['index1-*', 'index2-*'],
resultingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
- operation: BulkActionEditType.add_index_patterns,
+ operation: BulkActionEditTypeEnum.add_index_patterns,
},
{
caseName: '3 existing indeces + 0 indeces = 3 indeces',
existingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
indexPatternsToUpdate: [],
resultingIndexPatterns: ['index1-*', 'index2-*', 'index3-*'],
- operation: BulkActionEditType.add_index_patterns,
+ operation: BulkActionEditTypeEnum.add_index_patterns,
},
];
@@ -1296,8 +1296,8 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: bulkEditResponse } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
type: operation,
value: indexPatternsToUpdate,
@@ -1353,10 +1353,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: setTagsBody } = await postBulkAction().send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_tags,
+ type: BulkActionEditTypeEnum.set_tags,
value: ['reset-tag'],
},
],
@@ -1401,10 +1401,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_id: timelineId,
timeline_title: timelineTitle,
@@ -1444,10 +1444,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_id: '',
timeline_title: '',
@@ -1476,10 +1476,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [mlRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['index-*'],
},
],
@@ -1509,10 +1509,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['simple-index-*'],
},
],
@@ -1538,10 +1538,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_tags,
+ type: BulkActionEditTypeEnum.add_tags,
value: ['test'],
},
],
@@ -1559,35 +1559,35 @@ export default ({ getService }: FtrProviderContext): void => {
describe('prebuilt rules', () => {
const cases = [
{
- type: BulkActionEditType.add_tags,
+ type: BulkActionEditTypeEnum.add_tags,
value: ['new-tag'],
},
{
- type: BulkActionEditType.set_tags,
+ type: BulkActionEditTypeEnum.set_tags,
value: ['new-tag'],
},
{
- type: BulkActionEditType.delete_tags,
+ type: BulkActionEditTypeEnum.delete_tags,
value: ['new-tag'],
},
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['test-*'],
},
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: ['test-*'],
},
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['test-*'],
},
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: { timeline_id: 'mock-id', timeline_title: 'mock-title' },
},
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: { interval: '1m', lookback: '1m' },
},
];
@@ -1599,8 +1599,8 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [prebuiltRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
type,
value,
@@ -1648,10 +1648,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -1706,10 +1706,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -1766,10 +1766,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: '1h',
actions: [],
@@ -1818,10 +1818,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -1871,10 +1871,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -1931,10 +1931,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -2004,10 +2004,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -2069,10 +2069,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
actions: [],
@@ -2120,10 +2120,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
value: {
throttle: '1h',
actions: [],
@@ -2147,10 +2147,10 @@ export default ({ getService }: FtrProviderContext): void => {
describe('prebuilt rules', () => {
const cases = [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
},
{
- type: BulkActionEditType.add_rule_actions,
+ type: BulkActionEditTypeEnum.add_rule_actions,
},
];
cases.forEach(({ type }) => {
@@ -2162,8 +2162,8 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [prebuiltRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
type,
value: {
@@ -2220,10 +2220,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [prebuiltRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: '1h',
actions: [
@@ -2235,7 +2235,7 @@ export default ({ getService }: FtrProviderContext): void => {
},
},
{
- type: BulkActionEditType.set_tags,
+ type: BulkActionEditTypeEnum.set_tags,
value: ['tag-1'],
},
],
@@ -2290,10 +2290,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: payloadThrottle,
actions: [],
@@ -2331,62 +2331,63 @@ export default ({ getService }: FtrProviderContext): void => {
expectedThrottle: undefined,
},
];
- [BulkActionEditType.set_rule_actions, BulkActionEditType.add_rule_actions].forEach(
- (ruleAction) => {
- casesForNonEmptyActions.forEach(({ payloadThrottle, expectedThrottle }) => {
- it(`throttle is updated correctly for rule action "${ruleAction}", if payload throttle="${payloadThrottle}" and actions non empty`, async () => {
- // create a new connector
- const webHookConnector = await createWebHookConnector();
-
- const ruleId = 'ruleId';
- const createdRule = await createRule(supertest, log, getSimpleRule(ruleId));
-
- const { body } = await postBulkAction()
- .send({
- ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
- {
- type: BulkActionEditType.set_rule_actions,
- value: {
- throttle: payloadThrottle,
- actions: [
- {
- id: webHookConnector.id,
- group: 'default',
- params: { body: '{}' },
- },
- ],
- },
+ [
+ BulkActionEditTypeEnum.set_rule_actions,
+ BulkActionEditTypeEnum.add_rule_actions,
+ ].forEach((ruleAction) => {
+ casesForNonEmptyActions.forEach(({ payloadThrottle, expectedThrottle }) => {
+ it(`throttle is updated correctly for rule action "${ruleAction}", if payload throttle="${payloadThrottle}" and actions non empty`, async () => {
+ // create a new connector
+ const webHookConnector = await createWebHookConnector();
+
+ const ruleId = 'ruleId';
+ const createdRule = await createRule(supertest, log, getSimpleRule(ruleId));
+
+ const { body } = await postBulkAction()
+ .send({
+ ids: [createdRule.id],
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
+ {
+ type: BulkActionEditTypeEnum.set_rule_actions,
+ value: {
+ throttle: payloadThrottle,
+ actions: [
+ {
+ id: webHookConnector.id,
+ group: 'default',
+ params: { body: '{}' },
+ },
+ ],
},
- ],
- })
- .expect(200);
-
- // Check that the updated rule is returned with the response
- expect(body.attributes.results.updated[0].throttle).to.eql(expectedThrottle);
-
- const expectedActions = body.attributes.results.updated[0].actions.map(
- (action: any) => ({
- ...action,
- frequency: {
- summary: true,
- throttle: payloadThrottle !== 'rule' ? payloadThrottle : null,
- notifyWhen:
- payloadThrottle !== 'rule' ? 'onThrottleInterval' : 'onActiveAlert',
},
- })
- );
+ ],
+ })
+ .expect(200);
+
+ // Check that the updated rule is returned with the response
+ expect(body.attributes.results.updated[0].throttle).to.eql(expectedThrottle);
+
+ const expectedActions = body.attributes.results.updated[0].actions.map(
+ (action: any) => ({
+ ...action,
+ frequency: {
+ summary: true,
+ throttle: payloadThrottle !== 'rule' ? payloadThrottle : null,
+ notifyWhen:
+ payloadThrottle !== 'rule' ? 'onThrottleInterval' : 'onActiveAlert',
+ },
+ })
+ );
- // Check that the updates have been persisted
- const { body: rule } = await fetchRule(ruleId).expect(200);
+ // Check that the updates have been persisted
+ const { body: rule } = await fetchRule(ruleId).expect(200);
- expect(rule.throttle).to.eql(expectedThrottle);
- expect(rule.actions).to.eql(expectedActions);
- });
+ expect(rule.throttle).to.eql(expectedThrottle);
+ expect(rule.actions).to.eql(expectedActions);
});
- }
- );
+ });
+ });
});
describe('notifyWhen', () => {
@@ -2409,10 +2410,10 @@ export default ({ getService }: FtrProviderContext): void => {
await postBulkAction()
.send({
ids: [createdRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_rule_actions,
+ type: BulkActionEditTypeEnum.set_rule_actions,
value: {
throttle: payload.throttle,
actions: [],
@@ -2443,10 +2444,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
interval,
lookback,
@@ -2458,8 +2459,8 @@ export default ({ getService }: FtrProviderContext): void => {
expect(body.statusCode).to.eql(400);
expect(body.error).to.eql('Bad Request');
- expect(body.message).to.contain('Invalid value "0m" supplied to "edit,value,interval"');
- expect(body.message).to.contain('Invalid value "-1m" supplied to "edit,value,lookback"');
+ expect(body.message).to.contain('edit.0.value.interval: Invalid');
+ expect(body.message).to.contain('edit.0.value.lookback: Invalid');
});
it('should update schedule values in rules with a valid payload', async () => {
@@ -2473,10 +2474,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_schedule,
+ type: BulkActionEditTypeEnum.set_schedule,
value: {
interval,
lookback,
@@ -2511,10 +2512,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: setIndexBody } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['initial-index-*'],
overwrite_data_views: true,
},
@@ -2552,10 +2553,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: setIndexBody } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['initial-index-*'],
overwrite_data_views: false,
},
@@ -2597,10 +2598,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: setIndexBody } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: ['initial-index-*'],
overwrite_data_views: true,
},
@@ -2638,10 +2639,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: [],
overwrite_data_views: true,
},
@@ -2674,10 +2675,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: setIndexBody } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_index_patterns,
+ type: BulkActionEditTypeEnum.set_index_patterns,
value: ['initial-index-*'],
overwrite_data_views: false,
},
@@ -2720,10 +2721,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['simple-index-*'],
overwrite_data_views: true,
},
@@ -2761,10 +2762,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['simple-index-*'],
overwrite_data_views: true,
},
@@ -2797,10 +2798,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.delete_index_patterns,
+ type: BulkActionEditTypeEnum.delete_index_patterns,
value: ['simple-index-*'],
overwrite_data_views: false,
},
@@ -2830,14 +2831,14 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['initial-index-*'],
},
{
- type: BulkActionEditType.add_tags,
+ type: BulkActionEditTypeEnum.add_tags,
value: ['tag3'],
},
],
@@ -2868,16 +2869,16 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
// Valid operation
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['initial-index-*'],
},
// Operation to be skipped
{
- type: BulkActionEditType.add_tags,
+ type: BulkActionEditTypeEnum.add_tags,
value: ['tag1'],
},
],
@@ -2908,16 +2909,16 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [rule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
// Operation to be skipped
{
- type: BulkActionEditType.add_index_patterns,
+ type: BulkActionEditTypeEnum.add_index_patterns,
value: ['index1-*'],
},
// Operation to be skipped
{
- type: BulkActionEditType.add_tags,
+ type: BulkActionEditTypeEnum.add_tags,
value: ['tag1'],
},
],
@@ -2949,10 +2950,10 @@ export default ({ getService }: FtrProviderContext): void => {
Array.from({ length: 10 }).map(() =>
postBulkAction().send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_id: timelineId,
timeline_title: timelineTitle,
@@ -2978,10 +2979,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
ids: [id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_timeline,
+ type: BulkActionEditTypeEnum.set_timeline,
value: {
timeline_id: timelineId,
timeline_title: timelineTitle,
@@ -3033,7 +3034,7 @@ export default ({ getService }: FtrProviderContext): void => {
it('should export rules with legacy investigation_fields and transform legacy field in response', async () => {
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.export })
+ .send({ query: '', action: BulkActionTypeEnum.export })
.expect(200)
.expect('Content-Type', 'application/ndjson')
.expect('Content-Disposition', 'attachment; filename="rules_export.ndjson"')
@@ -3094,7 +3095,7 @@ export default ({ getService }: FtrProviderContext): void => {
it('should delete rules with investigation fields and transform legacy field in response', async () => {
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.delete })
+ .send({ query: '', action: BulkActionTypeEnum.delete })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 3, total: 3 });
@@ -3124,7 +3125,7 @@ export default ({ getService }: FtrProviderContext): void => {
it('should enable rules with legacy investigation fields and transform legacy field in response', async () => {
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.enable })
+ .send({ query: '', action: BulkActionTypeEnum.enable })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 3, total: 3 });
@@ -3188,7 +3189,7 @@ export default ({ getService }: FtrProviderContext): void => {
it('should disable rules with legacy investigation fields and transform legacy field in response', async () => {
const { body } = await postBulkAction()
- .send({ query: '', action: BulkActionType.disable })
+ .send({ query: '', action: BulkActionTypeEnum.disable })
.expect(200);
expect(body.attributes.summary).to.eql({ failed: 0, skipped: 0, succeeded: 3, total: 3 });
@@ -3251,7 +3252,7 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postBulkAction()
.send({
query: '',
- action: BulkActionType.duplicate,
+ action: BulkActionTypeEnum.duplicate,
duplicate: { include_exceptions: false, include_expired_exceptions: false },
})
.expect(200);
@@ -3353,10 +3354,10 @@ export default ({ getService }: FtrProviderContext): void => {
it('should edit rules with legacy investigation fields', async () => {
const { body } = await postBulkAction().send({
query: '',
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_tags,
+ type: BulkActionEditTypeEnum.set_tags,
value: ['reset-tag'],
},
],
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts
index a6df465d09f68..f1df03187379c 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/perform_bulk_action_dry_run.ts
@@ -12,8 +12,8 @@ import { getCreateEsqlRulesSchemaMock } from '@kbn/security-solution-plugin/comm
import expect from 'expect';
import {
- BulkActionType,
- BulkActionEditType,
+ BulkActionTypeEnum,
+ BulkActionEditTypeEnum,
} from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import {
@@ -65,7 +65,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, getSimpleRule());
const { body } = await postDryRunBulkAction()
- .send({ action: BulkActionType.export })
+ .send({ action: BulkActionTypeEnum.export })
.expect(400);
expect(body).toEqual({
@@ -80,7 +80,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, testRule);
const { body } = await postDryRunBulkAction()
- .send({ action: BulkActionType.delete })
+ .send({ action: BulkActionTypeEnum.delete })
.expect(200);
expect(body.attributes.summary).toEqual({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -101,7 +101,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, getSimpleRule(ruleId));
const { body } = await postDryRunBulkAction()
- .send({ action: BulkActionType.enable })
+ .send({ action: BulkActionTypeEnum.enable })
.expect(200);
expect(body.attributes.summary).toEqual({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -123,7 +123,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, getSimpleRule(ruleId, true));
const { body } = await postDryRunBulkAction()
- .send({ action: BulkActionType.disable })
+ .send({ action: BulkActionTypeEnum.disable })
.expect(200);
expect(body.attributes.summary).toEqual({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -146,7 +146,7 @@ export default ({ getService }: FtrProviderContext): void => {
await createRule(supertest, log, ruleToDuplicate);
const { body } = await postDryRunBulkAction()
- .send({ action: BulkActionType.disable })
+ .send({ action: BulkActionTypeEnum.disable })
.expect(200);
expect(body.attributes.summary).toEqual({ failed: 0, skipped: 0, succeeded: 1, total: 1 });
@@ -172,10 +172,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postDryRunBulkAction()
.send({
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_tags,
+ type: BulkActionEditTypeEnum.set_tags,
value: ['reset-tag'],
},
],
@@ -208,10 +208,10 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postDryRunBulkAction()
.send({
ids: [immutableRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
- type: BulkActionEditType.set_tags,
+ type: BulkActionEditTypeEnum.set_tags,
value: ['reset-tag'],
},
],
@@ -242,9 +242,9 @@ export default ({ getService }: FtrProviderContext): void => {
describe('validate updating index pattern for machine learning rule', () => {
const actions = [
- BulkActionEditType.add_index_patterns,
- BulkActionEditType.set_index_patterns,
- BulkActionEditType.delete_index_patterns,
+ BulkActionEditTypeEnum.add_index_patterns,
+ BulkActionEditTypeEnum.set_index_patterns,
+ BulkActionEditTypeEnum.delete_index_patterns,
];
actions.forEach((editAction) => {
@@ -254,8 +254,8 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postDryRunBulkAction()
.send({
ids: [mlRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
type: editAction,
value: [],
@@ -295,9 +295,9 @@ export default ({ getService }: FtrProviderContext): void => {
describe('validate updating index pattern for ES|QL rule', () => {
const actions = [
- BulkActionEditType.add_index_patterns,
- BulkActionEditType.set_index_patterns,
- BulkActionEditType.delete_index_patterns,
+ BulkActionEditTypeEnum.add_index_patterns,
+ BulkActionEditTypeEnum.set_index_patterns,
+ BulkActionEditTypeEnum.delete_index_patterns,
];
actions.forEach((editAction) => {
@@ -307,8 +307,8 @@ export default ({ getService }: FtrProviderContext): void => {
const { body } = await postDryRunBulkAction()
.send({
ids: [esqlRule.id],
- action: BulkActionType.edit,
- [BulkActionType.edit]: [
+ action: BulkActionTypeEnum.edit,
+ [BulkActionTypeEnum.edit]: [
{
type: editAction,
value: [],
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts
index 7c2d88620924f..d88ed8a898f90 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts
@@ -566,7 +566,8 @@ export default ({ getService }: FtrProviderContext) => {
expect(body).to.eql({
error: 'Bad Request',
- message: '[request body]: Invalid input',
+ message:
+ '[request body]: type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "query", type: Invalid literal value, expected "saved_query", saved_id: Required, and 14 more',
statusCode: 400,
});
});
@@ -955,7 +956,9 @@ export default ({ getService }: FtrProviderContext) => {
.send(updatedRule)
.expect(400);
- expect(body.message).to.eql('[request body]: Invalid input');
+ expect(body.message).to.eql(
+ '[request body]: investigation_fields: Expected object, received array, type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, and 22 more'
+ );
});
it('unsets legacy investigation fields when field not specified for update', async () => {
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts
index b5dbf7fca40f2..a3defbb6d1c82 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts
@@ -853,7 +853,9 @@ export default ({ getService }: FtrProviderContext) => {
])
.expect(400);
- expect(body.message).to.eql('[request body]: 0: Invalid input');
+ expect(body.message).to.eql(
+ '[request body]: 0.investigation_fields: Expected object, received array, 0.type: Invalid literal value, expected "eql", 0.language: Invalid literal value, expected "eql", 0.investigation_fields: Expected object, received array, 0.investigation_fields: Expected object, received array, and 22 more'
+ );
});
it('updates a rule with legacy investigation fields and transforms field in response', async () => {
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts
index 69425ac7fa4fc..4c38edaf0cd28 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts
@@ -28,7 +28,7 @@ import { v4 as uuidv4 } from 'uuid';
import {
QueryRuleCreateProps,
- BulkActionType,
+ BulkActionTypeEnum,
AlertSuppressionMissingFieldsStrategyEnum,
} from '@kbn/security-solution-plugin/common/api/detection_engine';
import { RuleExecutionStatusEnum } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring';
@@ -2296,7 +2296,7 @@ export default ({ getService }: FtrProviderContext) => {
.post(DETECTION_ENGINE_RULES_BULK_ACTION)
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '2023-10-31')
- .send({ query: '', action: BulkActionType.enable })
+ .send({ query: '', action: BulkActionTypeEnum.enable })
.expect(200);
// Confirming that enabling did not migrate rule, so rule
diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts
index 8c0cc688cb582..27cc61ca0c273 100644
--- a/x-pack/test/functional/apps/infra/home_page.ts
+++ b/x-pack/test/functional/apps/infra/home_page.ts
@@ -238,12 +238,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await retry.try(async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
- { name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' },
- { name: 'demo-stack-mysql-01', value: 1.2, color: '#82a7cd' },
- { name: 'demo-stack-nginx-01', value: 1.1, color: '#93b1d3' },
- { name: 'demo-stack-redis-01', value: 1, color: '#a2bcd9' },
+ { name: 'demo-stack-apache-01', value: 1.2, color: '#6092c0' },
+ { name: 'demo-stack-mysql-01', value: 1, color: '#93b1d3' },
+ { name: 'demo-stack-nginx-01', value: 0.9, color: '#b2c7df' },
+ { name: 'demo-stack-redis-01', value: 0.8, color: '#b2c7df' },
{ name: 'demo-stack-haproxy-01', value: 0.8, color: '#c2d2e6' },
- { name: 'demo-stack-client-01', value: 0.6, color: '#f0f4f9' },
+ { name: 'demo-stack-client-01', value: 0.5, color: '#f0f4f9' },
]);
});
});
@@ -256,12 +256,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await retry.try(async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
- { name: 'demo-stack-client-01', value: 0.6, color: '#f0f4f9' },
+ { name: 'demo-stack-client-01', value: 0.5, color: '#f0f4f9' },
{ name: 'demo-stack-haproxy-01', value: 0.8, color: '#c2d2e6' },
- { name: 'demo-stack-redis-01', value: 1, color: '#a2bcd9' },
- { name: 'demo-stack-nginx-01', value: 1.1, color: '#93b1d3' },
- { name: 'demo-stack-mysql-01', value: 1.2, color: '#82a7cd' },
- { name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' },
+ { name: 'demo-stack-redis-01', value: 0.8, color: '#b2c7df' },
+ { name: 'demo-stack-nginx-01', value: 0.9, color: '#b2c7df' },
+ { name: 'demo-stack-mysql-01', value: 1, color: '#93b1d3' },
+ { name: 'demo-stack-apache-01', value: 1.2, color: '#6092c0' },
]);
});
});
@@ -282,7 +282,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await retry.try(async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
- { name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' },
+ { name: 'demo-stack-apache-01', value: 1.2, color: '#6092c0' },
]);
});
await pageObjects.infraHome.clearSearchTerm();
@@ -295,12 +295,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await retry.try(async () => {
const nodesWithValue = await pageObjects.infraHome.getNodesWithValues();
expect(nodesWithValue).to.eql([
- { name: 'demo-stack-client-01', value: 0.6, color: '#6092c0' },
+ { name: 'demo-stack-client-01', value: 0.5, color: '#6092c0' },
{ name: 'demo-stack-haproxy-01', value: 0.8, color: '#b5c9df' },
- { name: 'demo-stack-redis-01', value: 1, color: '#f1d9b9' },
- { name: 'demo-stack-nginx-01', value: 1.1, color: '#eec096' },
- { name: 'demo-stack-mysql-01', value: 1.2, color: '#eba47a' },
- { name: 'demo-stack-apache-01', value: 1.4, color: '#e7664c' },
+ { name: 'demo-stack-redis-01', value: 0.8, color: '#d0dcea' },
+ { name: 'demo-stack-nginx-01', value: 0.9, color: '#d0dcea' },
+ { name: 'demo-stack-mysql-01', value: 1, color: '#eec096' },
+ { name: 'demo-stack-apache-01', value: 1.2, color: '#e7664c' },
]);
});
});
diff --git a/x-pack/test/security_solution_api_integration/README.md b/x-pack/test/security_solution_api_integration/README.md
index ebdf649e1e2bb..c0162a0abb041 100644
--- a/x-pack/test/security_solution_api_integration/README.md
+++ b/x-pack/test/security_solution_api_integration/README.md
@@ -28,7 +28,7 @@ ex:
```
-## Adding new security area's tests
+# Adding new security area's tests
1. Within the `test_suites` directory, create a new area folder.
2. Introduce `ess.config` and `serverless.config` files to reference the new test files and incorporate any additional custom properties defined in the `CreateTestConfigOptions` interface.
@@ -36,7 +36,7 @@ ex:
4. Append a new entry in the `ftr_configs.yml` file to enable the execution of the newly added tests within the CI pipeline.
-## Testing locally
+# Testing locally
In the `package.json` file, you'll find commands to configure the server for each environment and to run tests against that specific environment. These commands adhere to the Mocha tagging system, allowing for the inclusion and exclusion of tags, mirroring the setup of the CI pipeline.
@@ -44,49 +44,55 @@ In the `package.json` file, you'll find commands to configure the server for eac
In this project, you can run various commands to execute tests and workflows, each of which can be customized by specifying different parameters. Below, how to define the commands based on the parameters and their order.
-### Command Structure
-
-The command structure follows this pattern:
-
-- ``: The name of the specific command or test case.
-- ``: The test folder or workflow you want to run.
-- ``: The type of operation, either "server" or "runner."
-- ``: The testing environment, such as "serverlessEnv," "essEnv," or "qaEnv."
-- ``: The license folder the test is defined under such as "default_license", by default the value is "default_license"
-- ``: The area the test is defined under, such as "detection_engine", by default the value is "detection_engine"
-
-### Serverless and Ess Configuration
-
-- When using "serverless" or "ess" in the script, it specifies the correct configuration file for the tests.
-- "Serverless" and "ess" help determine the configuration specific to the chosen test.
-
-### serverlessEnv, essEnv, qaEnv Grep Command
-
-- When using "serverlessEnv,.." in the script, it appends the correct grep command for filtering tests in the serverless testing environment.
-- "serverlessEnv,..." is used to customize the test execution based on the serverless environment.
-
-
-### Command Examples
-
-Here are some command examples using the provided parameters:
-
-1. **Run the server for "exception_workflows" in the "serverlessEnv" environment:**
- ```shell
- npm run initialize-server exceptions/workflows serverless
- ```
-2. **To run tests for the "exception_workflows" using the serverless runner in the "serverlessEnv" environment, you can use the following command:**
- ```shell
- npm run run-tests exceptions/workflows serverless serverlessEnv
- ```
-3. **Run tests for "exception_workflows" using the serverless runner in the "qaEnv" environment:**
- ```shell
- npm run run-tests exceptions/workflows serverless qaEnv
- ```
-4. **Run the server for "exception_workflows" in the "essEnv" environment:**
- ```shell
- npm run initialize-server exceptions/workflows ess
- ```
-5. **Run tests for "exception_workflows" using the ess runner in the "essEnv" environment:**
- ```shell
- npm run run-tests exceptions/workflows ess essEnv
- ```
\ No newline at end of file
+1. Server Initialization and running tests for ex: (Detections Response - Default License):
+
+ The command structure follows this pattern
+ - `` can be either "server" or "runner," allowing you to either set up the server or execute the tests against the designated server.
+ - ``: The area the test is defined under, such as "detection_engine, entity_analytics,.."
+ - ``: The license folder the test is defined under such as "default_license, basic_license,..."
+
+ #### `initialize-server:dr:default`
+
+ - Command: `node ./scripts/index.js server detections_response default_license`
+ - Description: Initiates the server for the Detections Response area with the default license.
+ #### `run-tests:dr:default`
+
+ - Command: `node ./scripts/index.js runner detections_response default_license`
+ - Description: Runs the tests for the Detections Response area with the default license.
+
+
+
+ 2. Executes particular sets of test suites linked to the designated environment and license:
+
+ The command structure follows this pattern:
+
+ - ``: The test folder or workflow you want to run.
+ - ``: The type of project to pick the relevant configurations, either "serverless" or "ess."
+ - "serverless" and "ess" help determine the configuration specific to the chosen test.
+ - ``: The testing environment, such as "serverlessEnv," "essEnv," or "qaEnv."
+ - When using "serverlessEnv,.." in the script, it appends the correct grep command for filtering tests in the serverless testing environment.
+ - "serverlessEnv,..." is used to customize the test execution based on the serverless environment.
+
+
+ Here are some command examples for "exceptions" which defined under the "detection_engine" area using the default license:
+
+ 1. **Run the server for "exception_workflows" in the "serverlessEnv" environment:**
+ ```shell
+ npm run initialize-server:dr:default exceptions/workflows serverless
+ ```
+ 2. **To run tests for the "exception_workflows" using the serverless runner in the "serverlessEnv" environment, you can use the following command:**
+ ```shell
+ npm run run-tests:dr:default exceptions/workflows serverless serverlessEnv
+ ```
+ 3. **Run tests for "exception_workflows" using the serverless runner in the "qaEnv" environment:**
+ ```shell
+ npm run run-tests:dr:default exceptions/workflows serverless qaEnv
+ ```
+ 4. **Run the server for "exception_workflows" in the "essEnv" environment:**
+ ```shell
+ npm run initialize-server:dr:default exceptions/workflows ess
+ ```
+ 5. **Run tests for "exception_workflows" using the ess runner in the "essEnv" environment:**
+ ```shell
+ npm run run-tests:dr:default exceptions/workflows ess essEnv
+ ```
\ No newline at end of file
diff --git a/x-pack/test/security_solution_api_integration/ftr_provider_context.d.ts b/x-pack/test/security_solution_api_integration/ftr_provider_context.d.ts
index ae275fcecf99d..3a44ea9db01fe 100644
--- a/x-pack/test/security_solution_api_integration/ftr_provider_context.d.ts
+++ b/x-pack/test/security_solution_api_integration/ftr_provider_context.d.ts
@@ -4,7 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
+import { GenericFtrProviderContext } from '@kbn/test';
-import type { FtrProviderContext } from '../../test_serverless/api_integration/ftr_provider_context';
+import { services } from '../../test_serverless/api_integration/services';
-export type { FtrProviderContext };
+export type FtrProviderContext = GenericFtrProviderContext;
diff --git a/x-pack/test/security_solution_api_integration/package.json b/x-pack/test/security_solution_api_integration/package.json
index 24696f0c00bf0..a2bbd939fade2 100644
--- a/x-pack/test/security_solution_api_integration/package.json
+++ b/x-pack/test/security_solution_api_integration/package.json
@@ -7,6 +7,8 @@
"scripts": {
"initialize-server:dr:default": "node ./scripts/index.js server detections_response default_license",
"run-tests:dr:default": "node ./scripts/index.js runner detections_response default_license",
+ "initialize-server:ea:default": "node ./scripts/index.js server entity_analytics default_license",
+ "run-tests:ea:default": "node ./scripts/index.js runner entity_analytics default_license",
"exception_workflows:server:serverless": "npm run initialize-server:dr:default exceptions/workflows serverless",
"exception_workflows:runner:serverless": "npm run run-tests:dr:default exceptions/workflows serverless serverlessEnv",
"exception_workflows:qa:serverless": "npm run run-tests:dr:default exceptions/workflows serverless qaEnv",
@@ -41,6 +43,11 @@
"alerts:runner:serverless": "npm run run-tests:dr:default alerts serverless serverlessEnv",
"alerts:qa:serverless": "npm run run-tests:dr:default alerts serverless qaEnv",
"alerts:server:ess": "npm run initialize-server:dr:default alerts ess",
- "alerts:runner:ess": "npm run run-tests:dr:default alerts ess essEnv"
+ "alerts:runner:ess": "npm run run-tests:dr:default alerts ess essEnv",
+ "entity_analytics:server:serverless": "npm run initialize-server:ea:default risk_engine serverless",
+ "entity_analytics:runner:serverless": "npm run run-tests:ea:default risk_engine serverless serverlessEnv",
+ "entity_analytics:qa:serverless": "npm run run-tests:ea:default risk_engine serverless qaEnv",
+ "entity_analytics:server:ess": "npm run initialize-server:ea:default risk_engine ess",
+ "entity_analytics:runner:ess": "npm run run-tests:ea:default risk_engine ess essEnv"
}
}
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts
index 97b602c4db617..5ace976f1f4fc 100644
--- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts
@@ -467,7 +467,8 @@ export default ({ getService }: FtrProviderContext) => {
expect(body).to.eql({
error: 'Bad Request',
- message: '[request body]: Invalid input',
+ message:
+ '[request body]: type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", type: Invalid literal value, expected "query", type: Invalid literal value, expected "saved_query", saved_id: Required, and 14 more',
statusCode: 400,
});
});
@@ -574,7 +575,9 @@ export default ({ getService }: FtrProviderContext) => {
.send(rule)
.expect(400);
- expect(body.message).to.eql('[request body]: Invalid input');
+ expect(body.message).to.eql(
+ '[request body]: investigation_fields: Expected object, received array, type: Invalid literal value, expected "eql", language: Invalid literal value, expected "eql", investigation_fields: Expected object, received array, investigation_fields: Expected object, received array, and 22 more'
+ );
});
});
});
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_alerts_by_ids.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_alerts_by_ids.ts
index ce2b7ed1a4cf4..1cfc922d76677 100644
--- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_alerts_by_ids.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/get_alerts_by_ids.ts
@@ -14,6 +14,7 @@ import type { RiskEnrichmentFields } from '@kbn/security-solution-plugin/server/
import { DETECTION_ENGINE_QUERY_SIGNALS_URL as DETECTION_ENGINE_QUERY_ALERTS_URL } from '@kbn/security-solution-plugin/common/constants';
import { countDownTest } from '../count_down_test';
import { getQueryAlertsId } from './get_query_alerts_ids';
+import { routeWithNamespace } from '../route_with_namespace';
/**
* Given an array of rule ids this will return only alerts based on that rule id both
@@ -25,12 +26,14 @@ export const getAlertsByIds = async (
supertest: SuperTest.SuperTest,
log: ToolingLog,
ids: string[],
- size?: number
+ size?: number,
+ namespace?: string
): Promise> => {
const alertsOpen = await countDownTest>(
async () => {
+ const route = routeWithNamespace(DETECTION_ENGINE_QUERY_ALERTS_URL, namespace);
const response = await supertest
- .post(DETECTION_ENGINE_QUERY_ALERTS_URL)
+ .post(route)
.set('kbn-xsrf', 'true')
.send(getQueryAlertsId(ids, size));
if (response.status !== 200) {
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/wait_for_alerts_to_be_present.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/wait_for_alerts_to_be_present.ts
index e638bacf738c2..f7e873f98d4c7 100644
--- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/wait_for_alerts_to_be_present.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/wait_for_alerts_to_be_present.ts
@@ -21,11 +21,12 @@ export const waitForAlertsToBePresent = async (
supertest: SuperTest.SuperTest,
log: ToolingLog,
numberOfAlerts = 1,
- alertIds: string[]
+ alertIds: string[],
+ namespace?: string
): Promise => {
await waitFor(
async () => {
- const alertsOpen = await getAlertsByIds(supertest, log, alertIds, numberOfAlerts);
+ const alertsOpen = await getAlertsByIds(supertest, log, alertIds, numberOfAlerts, namespace);
return alertsOpen.hits.hits.length >= numberOfAlerts;
},
'waitForAlertsToBePresent',
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/README.md b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/README.md
new file mode 100644
index 0000000000000..e737e7b133929
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/README.md
@@ -0,0 +1,606 @@
+# Data Generator for functional tests
+
+Helper to generate and index documents for using in Kibana functional tests
+
+- [Data Generator for functional tests](#data-generator-for-functional-tests)
+ - [DataGenerator](#datagenerator)
+ - [Initialization](#initialization)
+ - [Prerequisites](#prerequisites)
+ - [dataGeneratorFactory](#datageneratorfactory)
+ - [methods](#methods)
+ - [**indexListOfDocuments**](#indexlistofdocuments)
+ - [**indexGeneratedDocuments**](#indexgenerateddocuments)
+ - [**indexEnhancedDocuments**](#indexenhanceddocuments)
+ - [Utils](#utils)
+ - [**generateDocuments**](#generatedocuments)
+ - [**enhanceDocument**](#enhancedocument)
+ - [**enhanceDocuments**](#enhancedocuments)
+ - [Usage](#usage)
+ - [create test query rule that queries indexed documents within a test](#create-test-query-rule-that-queries-indexed-documents-within-a-test)
+
+## DataGenerator
+
+### Initialization
+
+
+#### Prerequisites
+1. Create index mappings in `x-pack/test/functional/es_archives/security_solution`
+ - create folder for index `foo_bar`
+ - add mappings file `mappings.json` in it
+
+
+ x-pack/test/functional/es_archives/security_solution/foo_bar/mappings.json
+
+ ```JSON
+ {
+ "type": "index",
+ "value": {
+ "index": "foo_bar",
+ "mappings": {
+ "properties": {
+ "id": {
+ "type": "keyword"
+ },
+ "@timestamp": {
+ "type": "date"
+ },
+ "foo": {
+ "type": "keyword"
+ },
+ }
+ },
+ "settings": {
+ "index": {
+ "number_of_replicas": "1",
+ "number_of_shards": "1"
+ }
+ }
+ }
+ }
+ ```
+
+2. Add in `before` of the test file index initialization
+
+ ```ts
+ const esArchiver = getService('esArchiver');
+
+ before(async () => {
+ await esArchiver.load(
+ 'x-pack/test/functional/es_archives/security_solution/foo_bar'
+ );
+ });
+
+ ```
+
+3. Add in `after` of the test file index removal
+
+ ```ts
+ const esArchiver = getService('esArchiver');
+
+ before(async () => {
+ await esArchiver.unload(
+ 'x-pack/test/functional/es_archives/security_solution/foo_bar'
+ );
+ });
+
+ ```
+
+#### dataGeneratorFactory
+
+`DataGeneratorParams`
+
+| Property | Description | Type |
+| --------------- | ------------------------------------------------------ | ------ |
+| es | ES client | `ESClient` |
+| index | index where document will be added | `string` |
+| log | log client | `LogClient`|
+
+1. import and initialize factory
+
+ ```ts
+ import { dataGeneratorFactory } from '../../utils/data_generator';
+
+ const es = getService('es');
+ const log = getService('log');
+
+ const { indexListOfDocuments, indexGeneratedDocuments } = dataGeneratorFactory({
+ es,
+ index: 'foo_bar',
+ log,
+ });
+
+ ```
+2. Factory will return 2 methods which can be used to index documents into `foo_bar`
+
+where `getService` is method from `FtrProviderContext`
+
+### methods
+
+#### **indexListOfDocuments**
+
+| Property | Description | Type |
+| --------------- | ------------------------------------------------------ | ------ |
+| documents | list of documents to index | `Record` |
+
+Will index list of documents to `foo_bar` index as defined in `dataGeneratorFactory` params
+
+```ts
+ await indexListOfDocuments([{ foo: "bar" }, { id: "test-1" }])
+
+```
+
+#### **indexGeneratedDocuments**
+
+Will generate 10 documents in defined interval and index them in `foo_bar` index as defined in `dataGeneratorFactory` params
+Method receives same parameters as [generateDocuments](#generateDocuments) util.
+
+```ts
+ await indexGeneratedDocuments({
+ docsCount: 10,
+ interval: ['2020-10-28T07:30:00.000Z', '2020-10-30T07:30:00.000Z'],
+ seed: (i, id, timestamp) => ({ id, '@timestamp': timestamp, seq: i })
+ })
+
+```
+
+#### **indexEnhancedDocuments**
+
+Will index list of enhanced documents to `foo_bar` index as defined in `dataGeneratorFactory` params
+Method receives same parameters as [enhanceDocuments](#enhanceDocuments) util.
+
+```ts
+ await indexEnhancedDocuments({
+ interval: ['1996-02-15T13:02:37.531Z', '2000-02-15T13:02:37.531Z'],
+ documents: [{ foo: 'bar' }, { foo: 'bar-1' }, { foo: 'bar-2' }]
+ })
+
+```
+
+## Utils
+
+### **generateDocuments**
+
+Util `generateDocuments` can generate list of documents based on basic seed function
+
+ Seed callback will receive sequential number of document of document, generated id, timestamp.
+ Can be used to generate custom document with large set of options depends on needs. See examples below.
+
+ | Property | Description | Type |
+ | --------------- | ------------------------------------------------------ | ------ |
+ | docsCount | number of documents to generate | `number` |
+ | seed | function that receives sequential number of document, generated id, timestamp as arguments and can used it create a document | `(index: number, id: string, timestamp: string) => Document` |
+ | interval | interval in which generate documents, defined by '@timestamp' field | `[string \| Date string \| Date]` _(optional)_ |
+
+Examples:
+
+ 1. Generate 10 documents with random id, timestamp in interval between '2020-10-28T07:30:00.000Z', '2020-10-30T07:30:00.000Z', and field `seq` that represents sequential number of document
+
+ ```ts
+
+ const documents = generateDocuments({
+ docsCount: 10,
+ interval: ['2020-10-28T07:30:00.000Z', '2020-10-30T07:30:00.000Z'],
+ seed: (i, id, timestamp) => ({ id, '@timestamp': timestamp, seq: i })
+ })
+ ```
+
+
+Generated docs
+
+ ```JSON
+ [
+ {
+ "id": "87d3d231-13c8-4d03-9ae4-d40781b3b2d1",
+ "@timestamp": "2020-10-30T04:00:55.790Z",
+ "seq": 0
+ },
+ {
+ "id": "90b99797-d0da-460d-86fd-eca40bedff39",
+ "@timestamp": "2020-10-28T08:43:01.117Z",
+ "seq": 1
+ },
+ {
+ "id": "809c05be-f401-4e31-86e1-55be8af4fac4",
+ "@timestamp": "2020-10-29T15:06:23.054Z",
+ "seq": 2
+ },
+ {
+ "id": "a2720f82-5401-4eab-b2eb-444a8425c937",
+ "@timestamp": "2020-10-29T23:19:47.790Z",
+ "seq": 3
+ },
+ {
+ "id": "e36e4418-4e89-4388-97df-97085b3fca92",
+ "@timestamp": "2020-10-29T09:14:00.966Z",
+ "seq": 4
+ },
+ {
+ "id": "4747adb3-0603-4651-8c0f-0c7df037f779",
+ "@timestamp": "2020-10-28T14:23:50.500Z",
+ "seq": 5
+ },
+ {
+ "id": "1fbfd873-b0ca-4cda-9c96-9a044622e712",
+ "@timestamp": "2020-10-28T10:00:20.995Z",
+ "seq": 6
+ },
+ {
+ "id": "9173cf93-1f9f-4f91-be5e-1e6888cb3aae",
+ "@timestamp": "2020-10-28T08:52:27.830Z",
+ "seq": 7
+ },
+ {
+ "id": "53245337-e383-4b28-9975-acbd79901b7c",
+ "@timestamp": "2020-10-29T08:58:02.385Z",
+ "seq": 8
+ },
+ {
+ "id": "0c700d33-df10-426e-8f71-677f437923ec",
+ "@timestamp": "2020-10-29T16:33:10.240Z",
+ "seq": 9
+ }
+ ]
+ ```
+
+
+
+ 2. Generate 3 identical documents `{foo: bar}`
+
+ ```ts
+
+ const documents = generateDocuments({
+ docsCount: 3,
+ seed: () => ({ foo: 'bar' })
+ })
+ ```
+
+
+Generated docs
+
+ ```JSON
+ [
+ {
+ "foo": "bar"
+ },
+ {
+ "foo": "bar"
+ },
+ {
+ "foo": "bar"
+ }
+ ]
+ ```
+
+
+
+ 3. Generate 5 documents with custom ingested timestamp, with no interval. If interval not defined, timestamp will be current time
+
+ ```ts
+
+ const documents = generateDocuments({
+ docsCount: 5,
+ seed: (i, id, timestamp) => ({ foo: 'bar', event: { ingested: timestamp } })
+ })
+ ```
+
+
+Generated docs
+
+ ```JSON
+ [
+ {
+ "foo": "bar",
+ "event": {
+ "ingested": "2023-02-15T13:02:37.531Z"
+ }
+ },
+ {
+ "foo": "bar",
+ "event": {
+ "ingested": "2023-02-15T13:02:37.531Z"
+ }
+ },
+ {
+ "foo": "bar",
+ "event": {
+ "ingested": "2023-02-15T13:02:37.531Z"
+ }
+ },
+ {
+ "foo": "bar",
+ "event": {
+ "ingested": "2023-02-15T13:02:37.531Z"
+ }
+ },
+ {
+ "foo": "bar",
+ "event": {
+ "ingested": "2023-02-15T13:02:37.531Z"
+ }
+ }
+ ]
+ ```
+
+
+
+ 4. Generate 4 documents with custom if based on sequential number id
+
+ ```ts
+
+ const documents = generateDocuments({
+ docsCount: 4,
+ seed: (i) => ({ foo: 'bar', id: `id-${i}`})
+ })
+ ```
+
+
+Generated docs
+
+ ```JSON
+ [
+ {
+ "foo": "bar",
+ "id": "id-0"
+ },
+ {
+ "foo": "bar",
+ "id": "id-1"
+ },
+ {
+ "foo": "bar",
+ "id": "id-2"
+ },
+ {
+ "foo": "bar",
+ "id": "id-3"
+ }
+ ]
+ ```
+
+
+
+
+### **enhanceDocument**
+
+Adds generated `uuidv4` id and current time as `@timestamp` to document if `id`, `timestamp` params are not specified
+
+
+`EnhanceDocumentOptions`
+
+| Property | Description | Type |
+| --------------- | ------------------------------------------------------ | ------ |
+| id | id for document | `string` _(optional)_ |
+| timestamp | timestamp for document | `string` _(optional)_ |
+| document | document to enhance | `Record` |
+
+Examples:
+
+1. Enhance document with generated `uuidv4` id and current time as `@timestamp`
+
+ ```ts
+ const document = enhanceDocument({
+ document: { foo: 'bar' },
+ });
+ ```
+
+ document
+
+ ```JSON
+ {
+ "foo": "bar",
+ "id": "b501a64f-0dd4-4275-a38c-889be6a15a4d",
+ "@timestamp": "2023-02-15T17:21:21.429Z"
+ }
+ ```
+
+
+
+2. Enhance document with generated `uuidv4` id and predefined timestamp
+
+
+ ```ts
+ const document = enhanceDocument({
+ timestamp: '1996-02-15T13:02:37.531Z',
+ document: { foo: 'bar' },
+ });
+ ```
+
+ document
+
+ ```JSON
+ {
+ "foo": "bar",
+ "id": "7b7460bf-e173-4744-af15-2c01ac52963b",
+ "@timestamp": "1996-02-15T13:02:37.531Z"
+ }
+ ```
+
+
+
+3. Enhance document with predefined id and and current time as `@timestamp`
+
+
+ ```ts
+ const document = enhanceDocument({
+ id: 'test-id',
+ document: { foo: 'bar' },
+ });
+ ```
+
+ document
+
+ ```JSON
+ {
+ "foo": "bar",
+ "id": "test-id",
+ "@timestamp": "2023-02-15T17:21:21.429Z"
+ }
+ ```
+
+
+### **enhanceDocuments**
+
+
+
+Adds generated `uuidv4` `id` property to list of documents if `id` parameter is not specified.
+Adds `@timestamp` in defined interval to list of documents. If it's not specified, `@timestamp` will be added as current time
+
+| Property | Description | Type |
+| --------------- | ------------------------------------------------------ | ------ |
+| documents | documents to enhance | `Record[]` |
+| id | id for documents | `string` _(optional)_ |
+| interval | interval in which generate documents, defined by '@timestamp' field | `[string \| Date string \| Date]` _(optional)_ |
+
+Examples:
+
+1. Enhance documents with generated `uuidv4` id and current time as `@timestamp`
+
+ ```ts
+ const documents = enhanceDocuments({
+ documents: [{ foo: 'bar' }, { foo: 'bar-1' }, { foo: 'bar-2' }]
+ });
+ ```
+
+ documents
+
+ ```JSON
+ [
+ {
+ "foo": "bar",
+ "id": "c55ddd6b-3cf2-4ebf-94d6-4eeeb4e5b655",
+ "@timestamp": "2023-02-16T16:43:13.573Z"
+ },
+ {
+ "foo": "bar-1",
+ "id": "61b157b9-5f1f-4d99-a5bf-072069f5139d",
+ "@timestamp": "2023-02-16T16:43:13.573Z"
+ },
+ {
+ "foo": "bar-2",
+ "id": "04929927-6d9e-4ccc-b083-250e3fe2d7a7",
+ "@timestamp": "2023-02-16T16:43:13.573Z"
+ }
+ ]
+ ```
+
+
+
+2. Enhance document with generated `uuidv4` id and timestamp in predefined interval
+
+ ```ts
+ const documents = enhanceDocuments({
+ interval: ['1996-02-15T13:02:37.531Z', '2000-02-15T13:02:37.531Z'],
+ documents: [{ foo: 'bar' }, { foo: 'bar-1' }, { foo: 'bar-2' }]
+ });
+ ```
+
+ documents
+
+ ```JSON
+ [
+ {
+ "foo": "bar",
+ "id": "883a67cb-0a57-4711-bdf9-e8a394a52460",
+ "@timestamp": "1998-07-04T15:16:46.587Z"
+ },
+ {
+ "foo": "bar-1",
+ "id": "70691d9e-1030-412f-8ae1-c6db50e90e91",
+ "@timestamp": "1998-05-15T07:00:52.339Z"
+ },
+ {
+ "foo": "bar-2",
+ "id": "b2140328-5cc4-4532-947e-30b8fd830ed7",
+ "@timestamp": "1999-09-01T21:50:38.957Z"
+ }
+ ]
+ ```
+
+
+
+3. Enhance documents with predefined id and and current time as `@timestamp`
+
+ ```ts
+ const documents = enhanceDocuments({
+ id: 'test-id',
+ documents: [{ foo: 'bar' }, { foo: 'bar-1' }, { foo: 'bar-2' }]
+ });
+ ```
+
+ documents
+
+ ```JSON
+ [
+ {
+ "foo": "bar",
+ "id": "test-id",
+ "@timestamp": "2023-02-16T16:43:13.574Z"
+ },
+ {
+ "foo": "bar-1",
+ "id": "test-id",
+ "@timestamp": "2023-02-16T16:43:13.574Z"
+ },
+ {
+ "foo": "bar-2",
+ "id": "test-id",
+ "@timestamp": "2023-02-16T16:43:13.574Z"
+ }
+ ]
+
+ ```
+
+
+## Usage
+
+### create test query rule that queries indexed documents within a test
+
+When documents generated and indexed, there might be a need to create a test rule that targets only these documents. So, documents generated in the test, will be used only in context of this test.
+
+There are few possible ways to do this
+
+1. Create new index every time for a new test. Thus, newly indexed documents, will be the only documents present in test index. It might be costly operation, as it will require to create new index for each test, that re-initialize dataGeneratorFactory, or delete index after rule's run
+
+2. Use the same id or specific field in documents.
+ For example:
+
+ ```ts
+
+ const id = uuidv4();
+ const firstTimestamp = new Date().toISOString();
+ const firstDocument = {
+ id,
+ '@timestamp': firstTimestamp,
+ agent: {
+ name: 'agent-1',
+ },
+ };
+ await indexListOfDocuments([firstDocument, firstDocument]);
+
+ const rule: QueryRuleCreateProps = {
+ ...getRuleForSignalTesting(['ecs_compliant']),
+ query: `id:${id}`,
+ };
+
+
+ ```
+
+ All documents will have the same `id` and can be queried by following `id:${id}`
+
+3. Use utility method `getKQLQueryFromDocumentList` that will create query from all ids in generated documents
+
+ ```ts
+ const { documents } = await indexGeneratedDocuments({
+ docsCount: 4,
+ document: { foo: 'bar' },
+ enhance: true,
+ });
+
+ const query = getKQLQueryFromDocumentList(documents);
+ const rule = {
+ ...getRuleForSignalTesting(['ecs_non_compliant']),
+ query,
+ };
+ ```
+
+ util will generate the following query: `(id: "f6ca3ee1-407c-4685-a94b-11ef4ed5136b" or id: "2a7358b2-8cad-47ce-83b7-e4418c266f3e" or id: "9daec569-0ba1-4c46-a0c6-e340cee1c5fb" or id: "b03c2fdf-0ca1-447c-b8c6-2cc5a663ffe2")`, that will include all generated documents
\ No newline at end of file
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/data_generator_factory.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/data_generator_factory.ts
new file mode 100644
index 0000000000000..7842d105e40b0
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/data_generator_factory.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import type { Client } from '@elastic/elasticsearch';
+import { ToolingLog } from '@kbn/tooling-log';
+import type { BulkResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import { indexDocuments } from './index_documents';
+import { generateDocuments } from './generate_documents';
+import { enhanceDocuments, EnhanceDocumentsOptions } from './enhance_documents';
+import type { GenerateDocumentsParams } from './generate_documents';
+import type { Document } from './types';
+
+interface DataGeneratorParams {
+ es: Client;
+ documents: Array>;
+ index: string;
+ log: ToolingLog;
+}
+
+interface DataGeneratorResponse {
+ response: BulkResponse;
+ documents: Document[];
+}
+
+interface DataGenerator {
+ indexListOfDocuments: (docs: Document[]) => Promise;
+ indexGeneratedDocuments: (params: GenerateDocumentsParams) => Promise;
+ indexEnhancedDocuments: (params: EnhanceDocumentsOptions) => Promise;
+}
+
+/**
+ * initialize {@link DataGenerator}
+ * @param param.es - ES client
+ * @param params.index - index where document will be added
+ * @param params.log - logClient
+ * @returns methods of {@link DataGenerator}
+ */
+export const dataGeneratorFactory = ({
+ es,
+ index,
+ log,
+}: Omit): DataGenerator => {
+ return {
+ indexListOfDocuments: async (documents: DataGeneratorParams['documents']) => {
+ const response = await indexDocuments({ es, index, documents, log });
+
+ return {
+ documents,
+ response,
+ };
+ },
+ indexGeneratedDocuments: async (params: GenerateDocumentsParams) => {
+ const documents = generateDocuments(params);
+ const response = await indexDocuments({ es, index, documents, log });
+
+ return {
+ documents,
+ response,
+ };
+ },
+ indexEnhancedDocuments: async (params: EnhanceDocumentsOptions) => {
+ const documents = enhanceDocuments(params);
+ const response = await indexDocuments({ es, index, documents, log });
+
+ return {
+ documents,
+ response,
+ };
+ },
+ };
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/enhance_document.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/enhance_document.ts
new file mode 100644
index 0000000000000..f2e244edb90b3
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/enhance_document.ts
@@ -0,0 +1,29 @@
+/*
+ * 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 { v4 as uuidv4 } from 'uuid';
+
+interface EnhanceDocumentOptions {
+ id?: string;
+ timestamp?: string;
+ document: Record;
+}
+
+/**
+ * enhances document with generated id and timestamp
+ * @param {string} options.id - optional id, if not provided randomly generated
+ * @param {string} options.timestamp - optional timestamp of document, if not provided current time
+ * @param {Record} options.document - document that will be enhanced
+ */
+export const enhanceDocument = (options: EnhanceDocumentOptions) => {
+ const id = options?.id ?? uuidv4();
+ const timestamp = options?.timestamp ?? new Date().toISOString();
+ return {
+ ...options.document,
+ id,
+ '@timestamp': timestamp,
+ };
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/enhance_documents.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/enhance_documents.ts
new file mode 100644
index 0000000000000..5d701afe166ed
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/enhance_documents.ts
@@ -0,0 +1,32 @@
+/*
+ * 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 type { IndexingInterval, Document } from './types';
+import { getTimestamp } from './get_timestamp';
+import { enhanceDocument } from './enhance_document';
+
+export interface EnhanceDocumentsOptions {
+ interval?: IndexingInterval;
+ documents: Document[];
+ id?: string;
+}
+
+/**
+ * enhances documents with generated id and timestamp within interval
+ * @param {string} options.id - optional id, if not provided randomly generated
+ * @param {string} options.interval - optional interval of document, if not provided set as a current time
+ * @param {Record[]} options.documents - documents that will be enhanced
+ */
+export const enhanceDocuments = ({ documents, interval, id }: EnhanceDocumentsOptions) => {
+ return documents.map((document) =>
+ enhanceDocument({
+ document,
+ id,
+ timestamp: getTimestamp(interval),
+ })
+ );
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/generate_documents.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/generate_documents.ts
new file mode 100644
index 0000000000000..c9ba960867a43
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/generate_documents.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { v4 as uuidv4 } from 'uuid';
+import { getTimestamp } from './get_timestamp';
+
+import type { Document, IndexingInterval } from './types';
+
+type DocumentSeedFunc = (index: number, id: string, timestamp: string) => Document;
+
+export interface GenerateDocumentsParams {
+ interval?: IndexingInterval;
+ docsCount: number;
+ seed: DocumentSeedFunc;
+}
+
+/**
+ *
+ * @param param.interval - interval in which generate documents, defined by '@timestamp' field
+ * @param param.docsCount - number of document to generate
+ * @param param.seed - seed function. Function that receives index of document, generated id, timestamp as arguments and can used it create a document
+ * @returns generated Documents
+ */
+export const generateDocuments = ({ docsCount, interval, seed }: GenerateDocumentsParams) => {
+ const documents = [];
+
+ for (let i = 0; i < docsCount; i++) {
+ const id = uuidv4();
+ const timestamp = getTimestamp(interval);
+
+ documents.push(seed(i, id, timestamp));
+ }
+
+ return documents;
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/get_kql_query_from_documents_list.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/get_kql_query_from_documents_list.ts
new file mode 100644
index 0000000000000..3347c2120d4a4
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/get_kql_query_from_documents_list.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 type { Document } from './types';
+
+/**
+ * returns KQL query from a list documents that includes all documents by their ids.
+ * it can be used later to create test rules that will query only these documents
+ * ```ts
+ * const documents = [
+ {
+ foo: 'bar',
+ id: 'f07df596-65ec-4ab1-b0b2-f3b69558ed26',
+ '@timestamp': '2020-10-29T07:10:51.989Z',
+ },
+ {
+ foo: 'bar',
+ id: 'e07614f9-1dc5-4849-90c4-31362bbdf8d0',
+ '@timestamp': '2020-10-30T00:32:48.987Z',
+ },
+ {
+ foo: 'test',
+ id: 'e03a5b12-77e6-4aa3-b0be-fbe5b0843f07',
+ '@timestamp': '2020-10-29T03:40:35.318Z',
+ },
+ ];
+
+ const query = getKQLQueryFromDocumentList(documents);
+
+ // query equals to
+ // (id: "f07df596-65ec-4ab1-b0b2-f3b69558ed26" or id: "e07614f9-1dc5-4849-90c4-31362bbdf8d0" or id: "e03a5b12-77e6-4aa3-b0be-fbe5b0843f07")
+ * ```
+ */
+export const getKQLQueryFromDocumentList = (documents: Document[]) => {
+ const orClauses = documents.map(({ id }) => `id: "${id}"`).join(' or ');
+
+ return `(${orClauses})`;
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/get_timestamp.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/get_timestamp.ts
new file mode 100644
index 0000000000000..e828767a39650
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/get_timestamp.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import faker from 'faker';
+import type { IndexingInterval } from './types';
+
+export const getTimestamp = (interval?: IndexingInterval) => {
+ if (interval) {
+ return faker.date.between(...interval).toISOString();
+ }
+
+ return new Date().toISOString();
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/index.ts
new file mode 100644
index 0000000000000..4cd56dd896554
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/index.ts
@@ -0,0 +1,14 @@
+/*
+ * 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.
+ */
+
+export * from './data_generator_factory';
+export * from './enhance_document';
+export * from './enhance_documents';
+export * from './generate_documents';
+export * from './get_kql_query_from_documents_list';
+export * from './get_timestamp';
+export * from './index_documents';
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/index_documents.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/index_documents.ts
new file mode 100644
index 0000000000000..5408e11b25015
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/index_documents.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import type { Client } from '@elastic/elasticsearch';
+import type { BulkResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import { ToolingLog } from '@kbn/tooling-log';
+
+interface IndexDocumentsParams {
+ es: Client;
+ documents: Array>;
+ index: string;
+ log: ToolingLog;
+}
+
+type IndexDocuments = (params: IndexDocumentsParams) => Promise;
+
+/**
+ * Indexes documents into provided index
+ */
+export const indexDocuments: IndexDocuments = async ({ es, documents, index, log }) => {
+ const operations = documents.flatMap((doc: object) => [{ index: { _index: index } }, doc]);
+
+ const response = await es.bulk({ refresh: true, operations });
+
+ // throw error if document wasn't indexed, so test will be terminated earlier and no false positives can happen
+ response.items.some(({ index: responseIndex } = {}) => {
+ if (responseIndex?.error) {
+ log.error(
+ `Failed to index document in non_ecs_fields test suits: "${responseIndex.error?.reason}"`
+ );
+ throw Error(responseIndex.error.message);
+ }
+ });
+ return response;
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/types.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/types.ts
new file mode 100644
index 0000000000000..bbf54be68cfee
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/data_generator/types.ts
@@ -0,0 +1,10 @@
+/*
+ * 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.
+ */
+
+export type IndexingInterval = [string | Date, string | Date];
+
+export type Document = Record;
diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts
index 56d166c501b6b..9af5821d08ac3 100644
--- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/index.ts
@@ -8,6 +8,8 @@ export * from './rules';
export * from './exception_list_and_item';
export * from './alerts';
export * from './actions';
+export * from './data_generator';
+
export * from './rules/get_rule_so_by_id';
export * from './rules/create_rule_saved_object';
export * from './rules/get_rule_with_legacy_investigation_fields';
@@ -18,4 +20,5 @@ export * from './count_down_es';
export * from './update_username';
export * from './refresh_index';
export * from './wait_for';
+export * from './route_with_namespace';
export * from './wait_for_index_to_populate';
diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/ess.config.ts
new file mode 100644
index 0000000000000..bb4e078746d58
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/ess.config.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { FtrConfigProviderContext } from '@kbn/test';
+export default async function ({ readConfigFile }: FtrConfigProviderContext) {
+ const functionalConfig = await readConfigFile(
+ require.resolve('../../../../../config/ess/config.base.trial')
+ );
+
+ return {
+ ...functionalConfig.getAll(),
+ testFiles: [require.resolve('..')],
+ junit: {
+ reportName: 'Entity Analytics API Integration Tests - ESS - Risk Engine',
+ },
+ };
+}
diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/serverless.config.ts
new file mode 100644
index 0000000000000..e28df5b9c3506
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/configs/serverless.config.ts
@@ -0,0 +1,15 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { createTestConfig } from '../../../../../config/serverless/config.base';
+
+export default createTestConfig({
+ testFiles: [require.resolve('..')],
+ junit: {
+ reportName: 'Entity Analytics API Integration Tests - Serverless - Risk Engine',
+ },
+});
diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/index.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/index.ts
new file mode 100644
index 0000000000000..878725cd32f9a
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { FtrProviderContext } from '../../../../ftr_provider_context';
+
+export default function ({ loadTestFile }: FtrProviderContext) {
+ describe('Entity Analytics - Risk Engine', function () {
+ loadTestFile(require.resolve('./init_and_status_apis'));
+ loadTestFile(require.resolve('./risk_score_calculation'));
+ loadTestFile(require.resolve('./risk_score_preview'));
+ loadTestFile(require.resolve('./risk_scoring_task/task_execution'));
+ loadTestFile(require.resolve('./risk_scoring_task/task_execution_nondefault_spaces'));
+ loadTestFile(require.resolve('./telemetry_usage'));
+ });
+}
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/init_and_status_apis.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/init_and_status_apis.ts
similarity index 93%
rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/init_and_status_apis.ts
rename to x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/init_and_status_apis.ts
index 480ebd9d9c845..c88a30e8b42d8 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/init_and_status_apis.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/init_and_status_apis.ts
@@ -6,23 +6,20 @@
*/
import expect from '@kbn/expect';
-import { riskEngineConfigurationTypeName } from '@kbn/security-solution-plugin/server/lib/risk_engine/saved_object';
-import { FtrProviderContext } from '../../../common/ftr_provider_context';
+import { riskEngineConfigurationTypeName } from '@kbn/security-solution-plugin/server/lib/entity_analytics/risk_engine/saved_object';
+
import {
- cleanRiskEngineConfig,
legacyTransformIds,
createLegacyTransforms,
clearLegacyTransforms,
riskEngineRouteHelpersFactory,
- clearTransforms,
installLegacyRiskScore,
getLegacyRiskScoreDashboards,
clearLegacyDashboards,
- deleteRiskEngineTask,
- deleteAllRiskScores,
-} from './utils';
+ cleanRiskEngine,
+} from '../../utils';
+import { FtrProviderContext } from '../../../../ftr_provider_context';
-// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const es = getService('es');
const supertest = getService('supertest');
@@ -30,37 +27,17 @@ export default ({ getService }: FtrProviderContext) => {
const riskEngineRoutes = riskEngineRouteHelpersFactory(supertest);
const log = getService('log');
- describe('Risk Engine', () => {
+ describe('@ess @serverless init_and_status_apis', () => {
beforeEach(async () => {
- await cleanRiskEngineConfig({ kibanaServer });
- await deleteRiskEngineTask({ es, log });
- await deleteAllRiskScores(log, es);
- await clearTransforms({
- es,
- log,
- });
+ await cleanRiskEngine({ kibanaServer, es, log });
});
afterEach(async () => {
- await cleanRiskEngineConfig({
- kibanaServer,
- });
- await clearLegacyTransforms({
- es,
- log,
- });
- await clearTransforms({
- es,
- log,
- });
- await clearLegacyDashboards({
- supertest,
- log,
- });
- await deleteRiskEngineTask({ es, log });
+ await cleanRiskEngine({ kibanaServer, es, log });
+ await clearLegacyTransforms({ es, log });
+ await clearLegacyDashboards({ supertest, log });
});
- // FLAKY: https://github.com/elastic/kibana/issues/168376
describe('init api', () => {
it('should return response with success status', async () => {
const response = await riskEngineRoutes.init();
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_score_calculation.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_calculation.ts
similarity index 95%
rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_score_calculation.ts
rename to x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_calculation.ts
index f03214e301dd1..74e37b4737f71 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_score_calculation.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_calculation.ts
@@ -6,12 +6,16 @@
*/
import expect from '@kbn/expect';
+import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common';
+
import { RISK_SCORE_CALCULATION_URL } from '@kbn/security-solution-plugin/common/constants';
import type { RiskScore } from '@kbn/security-solution-plugin/common/risk_engine';
import { v4 as uuidv4 } from 'uuid';
-import { FtrProviderContext } from '../../../common/ftr_provider_context';
-import { deleteAllAlerts, deleteAllRules } from '../../../utils';
-import { dataGeneratorFactory } from '../../../utils/data_generator';
+import {
+ deleteAllAlerts,
+ deleteAllRules,
+ dataGeneratorFactory,
+} from '../../../detections_response/utils';
import {
buildDocument,
createAndSyncRuleAndAlertsFactory,
@@ -19,9 +23,9 @@ import {
readRiskScores,
normalizeScores,
waitForRiskScoresToBePresent,
-} from './utils';
+} from '../../utils';
+import { FtrProviderContext } from '../../../../ftr_provider_context';
-// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext): void => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
@@ -39,6 +43,7 @@ export default ({ getService }: FtrProviderContext): void => {
.post(RISK_SCORE_CALCULATION_URL)
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send(body)
.expect(200);
return result;
@@ -63,7 +68,7 @@ export default ({ getService }: FtrProviderContext): void => {
});
};
- describe('Risk Engine - Risk Scoring Calculation API', () => {
+ describe('@ess @serverless Risk Scoring Calculation API', () => {
context('with auditbeat data', () => {
const { indexListOfDocuments } = dataGeneratorFactory({
es,
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_score_preview.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_preview.ts
similarity index 97%
rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_score_preview.ts
rename to x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_preview.ts
index 31f8a86efc56e..ae1fdb82d0953 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_score_preview.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_score_preview.ts
@@ -10,17 +10,22 @@ import { ALERT_RISK_SCORE } from '@kbn/rule-data-utils';
import { RISK_SCORE_PREVIEW_URL } from '@kbn/security-solution-plugin/common/constants';
import type { RiskScore } from '@kbn/security-solution-plugin/common/risk_engine';
import { v4 as uuidv4 } from 'uuid';
-import { FtrProviderContext } from '../../../common/ftr_provider_context';
-import { createSignalsIndex, deleteAllAlerts, deleteAllRules } from '../../../utils';
-import { dataGeneratorFactory } from '../../../utils/data_generator';
+import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common';
+import {
+ createAlertsIndex,
+ deleteAllAlerts,
+ deleteAllRules,
+ dataGeneratorFactory,
+} from '../../../detections_response/utils';
import {
buildDocument,
createAndSyncRuleAndAlertsFactory,
deleteAllRiskScores,
sanitizeScores,
-} from './utils';
+} from '../../utils';
+
+import { FtrProviderContext } from '../../../../ftr_provider_context';
-// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext): void => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
@@ -37,6 +42,7 @@ export default ({ getService }: FtrProviderContext): void => {
const { body: result } = await supertest
.post(RISK_SCORE_PREVIEW_URL)
.set('elastic-api-version', '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.set('kbn-xsrf', 'true')
.send({ ...defaultBody, ...body })
.expect(200);
@@ -56,7 +62,7 @@ export default ({ getService }: FtrProviderContext): void => {
return await previewRiskScores({ body: {} });
};
- describe('Risk Engine - Risk Scoring Preview API', () => {
+ describe('@ess @serverless Risk Scoring Preview API', () => {
context('with auditbeat data', () => {
const { indexListOfDocuments } = dataGeneratorFactory({
es,
@@ -78,7 +84,7 @@ export default ({ getService }: FtrProviderContext): void => {
await deleteAllAlerts(supertest, log, es);
await deleteAllRules(supertest, log);
- await createSignalsIndex(supertest, log);
+ await createAlertsIndex(supertest, log);
});
afterEach(async () => {
diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/ftr_provider_context_with_spaces.d.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/ftr_provider_context_with_spaces.d.ts
new file mode 100644
index 0000000000000..922a5d9d25b71
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/ftr_provider_context_with_spaces.d.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import { GenericFtrProviderContext } from '@kbn/test';
+
+import { SpacesServiceProvider } from '../../../../../../common/services/spaces';
+import { services as serverlessServices } from '../../../../../../../test_serverless/api_integration/services';
+
+const services = {
+ ...serverlessServices,
+ spaces: SpacesServiceProvider,
+};
+export type FtrProviderContextWithSpaces = GenericFtrProviderContext;
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_scoring_task_execution.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts
similarity index 67%
rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_scoring_task_execution.ts
rename to x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts
index 6a95d236a9d0a..53c70bc90efb9 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/risk_scoring_task_execution.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution.ts
@@ -7,27 +7,25 @@
import expect from '@kbn/expect';
import { v4 as uuidv4 } from 'uuid';
-import { FtrProviderContext } from '../../../common/ftr_provider_context';
-import { deleteAllAlerts, deleteAllRules } from '../../../utils';
-import { dataGeneratorFactory } from '../../../utils/data_generator';
+import {
+ deleteAllAlerts,
+ deleteAllRules,
+ dataGeneratorFactory,
+} from '../../../../detections_response/utils';
import {
buildDocument,
createAndSyncRuleAndAlertsFactory,
- deleteRiskEngineTask,
- deleteAllRiskScores,
readRiskScores,
waitForRiskScoresToBePresent,
normalizeScores,
riskEngineRouteHelpersFactory,
updateRiskEngineConfigSO,
getRiskEngineTask,
- cleanRiskEngineConfig,
waitForRiskEngineTaskToBeGone,
- deleteRiskScoreIndices,
- clearTransforms,
-} from './utils';
+ cleanRiskEngine,
+} from '../../../utils';
+import { FtrProviderContext } from '../../../../../ftr_provider_context';
-// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext): void => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
@@ -38,7 +36,7 @@ export default ({ getService }: FtrProviderContext): void => {
const createAndSyncRuleAndAlerts = createAndSyncRuleAndAlertsFactory({ supertest, log });
const riskEngineRoutes = riskEngineRouteHelpersFactory(supertest);
- describe('Risk Engine - Risk Scoring Task', () => {
+ describe('@ess @serverless Risk Scoring Task Execution', () => {
context('with auditbeat data', () => {
const { indexListOfDocuments } = dataGeneratorFactory({
es,
@@ -57,21 +55,15 @@ export default ({ getService }: FtrProviderContext): void => {
});
beforeEach(async () => {
- await cleanRiskEngineConfig({ kibanaServer });
- await deleteRiskEngineTask({ es, log });
- await deleteAllRiskScores(log, es);
+ await cleanRiskEngine({ kibanaServer, es, log });
await deleteAllAlerts(supertest, log, es);
await deleteAllRules(supertest, log);
- await clearTransforms({ es, log });
});
afterEach(async () => {
- await cleanRiskEngineConfig({ kibanaServer });
- await deleteRiskEngineTask({ es, log });
- await deleteAllRiskScores(log, es);
+ await cleanRiskEngine({ kibanaServer, es, log });
await deleteAllAlerts(supertest, log, es);
await deleteAllRules(supertest, log);
- await clearTransforms({ es, log });
});
describe('with some alerts containing hosts', () => {
@@ -101,7 +93,7 @@ export default ({ getService }: FtrProviderContext): void => {
await riskEngineRoutes.init();
});
- it('calculates and persists risk scores for alert documents', async () => {
+ it('@skipInQA calculates and persists risk scores for alert documents', async () => {
await waitForRiskScoresToBePresent({ es, log, scoreCount: 10 });
const scores = await readRiskScores(es);
@@ -112,7 +104,7 @@ export default ({ getService }: FtrProviderContext): void => {
);
});
- it('starts the latest transform', async () => {
+ it('@skipInQA starts the latest transform', async () => {
await waitForRiskScoresToBePresent({ es, log, scoreCount: 10 });
const transformStats = await es.transform.getTransformStats({
@@ -122,7 +114,7 @@ export default ({ getService }: FtrProviderContext): void => {
expect(transformStats.transforms[0].state).to.eql('started');
});
- describe('disabling and re-enabling the risk engine', () => {
+ describe('@skipInQA disabling and re-enabling the risk engine', () => {
beforeEach(async () => {
await waitForRiskScoresToBePresent({ es, log, scoreCount: 10 });
await riskEngineRoutes.disable();
@@ -144,7 +136,7 @@ export default ({ getService }: FtrProviderContext): void => {
});
});
- describe('disabling the risk engine', () => {
+ describe('@skipInQA disabling the risk engine', () => {
beforeEach(async () => {
await waitForRiskScoresToBePresent({ es, log, scoreCount: 10 });
});
@@ -223,7 +215,7 @@ export default ({ getService }: FtrProviderContext): void => {
await riskEngineRoutes.init();
});
- it('calculates and persists risk scores for both types of entities', async () => {
+ it('@skipInQA calculates and persists risk scores for both types of entities', async () => {
await waitForRiskScoresToBePresent({ es, log, scoreCount: 20 });
const riskScores = await readRiskScores(es);
@@ -235,74 +227,6 @@ export default ({ getService }: FtrProviderContext): void => {
expect(scoredIdentifiers.includes('user.name')).to.be(true);
});
});
-
- describe('with alerts in a non-default space', () => {
- let namespace: string;
- let index: string[];
- let documentId: string;
- let createAndSyncRuleAndAlertsForOtherSpace: ReturnType<
- typeof createAndSyncRuleAndAlertsFactory
- >;
-
- beforeEach(async () => {
- documentId = uuidv4();
- namespace = uuidv4();
- index = [`risk-score.risk-score-${namespace}`];
-
- createAndSyncRuleAndAlertsForOtherSpace = createAndSyncRuleAndAlertsFactory({
- supertest,
- log,
- namespace,
- });
- const riskEngineRoutesForNamespace = riskEngineRouteHelpersFactory(supertest, namespace);
-
- const spaces = getService('spaces');
- await spaces.create({
- id: namespace,
- name: namespace,
- disabledFeatures: [],
- });
-
- const baseEvent = buildDocument({ host: { name: 'host-1' } }, documentId);
- await indexListOfDocuments(
- Array(10)
- .fill(baseEvent)
- .map((_baseEvent, _index) => ({
- ..._baseEvent,
- 'host.name': `host-${_index}`,
- }))
- );
-
- await createAndSyncRuleAndAlertsForOtherSpace({
- query: `id: ${documentId}`,
- alerts: 10,
- riskScore: 40,
- });
-
- await riskEngineRoutesForNamespace.init();
- });
-
- afterEach(async () => {
- await getService('spaces').delete(namespace);
- await deleteRiskScoreIndices({ log, es, namespace });
- });
-
- it('calculates and persists risk scores for alert documents', async () => {
- await waitForRiskScoresToBePresent({
- es,
- log,
- scoreCount: 10,
- index,
- });
-
- const scores = await readRiskScores(es, index);
- expect(normalizeScores(scores).map(({ id_value: idValue }) => idValue)).to.eql(
- Array(10)
- .fill(0)
- .map((_, _index) => `host-${_index}`)
- );
- });
- });
});
});
};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution_nondefault_spaces.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution_nondefault_spaces.ts
new file mode 100644
index 0000000000000..cf9bf98f88d9d
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/risk_scoring_task/task_execution_nondefault_spaces.ts
@@ -0,0 +1,133 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import expect from '@kbn/expect';
+import { v4 as uuidv4 } from 'uuid';
+import {
+ deleteAllAlerts,
+ deleteAllRules,
+ dataGeneratorFactory,
+} from '../../../../detections_response/utils';
+import {
+ buildDocument,
+ createAndSyncRuleAndAlertsFactory,
+ readRiskScores,
+ waitForRiskScoresToBePresent,
+ normalizeScores,
+ riskEngineRouteHelpersFactory,
+ cleanRiskEngine,
+ deleteRiskScoreIndices,
+} from '../../../utils';
+
+import { FtrProviderContextWithSpaces } from './ftr_provider_context_with_spaces';
+
+export default ({ getService }: FtrProviderContextWithSpaces): void => {
+ const supertest = getService('supertest');
+ const esArchiver = getService('esArchiver');
+ const es = getService('es');
+ const log = getService('log');
+ const kibanaServer = getService('kibanaServer');
+
+ describe('@ess Risk Scoring Task in non-default space', () => {
+ context('with auditbeat data', () => {
+ const { indexListOfDocuments } = dataGeneratorFactory({
+ es,
+ index: 'ecs_compliant',
+ log,
+ });
+
+ before(async () => {
+ await esArchiver.load('x-pack/test/functional/es_archives/security_solution/ecs_compliant');
+ });
+
+ after(async () => {
+ await esArchiver.unload(
+ 'x-pack/test/functional/es_archives/security_solution/ecs_compliant'
+ );
+ });
+
+ beforeEach(async () => {
+ await cleanRiskEngine({ kibanaServer, es, log });
+ await deleteAllAlerts(supertest, log, es);
+ await deleteAllRules(supertest, log);
+ });
+
+ afterEach(async () => {
+ await cleanRiskEngine({ kibanaServer, es, log });
+ await deleteAllAlerts(supertest, log, es);
+ await deleteAllRules(supertest, log);
+ });
+ describe('with alerts in a non-default space', () => {
+ let namespace: string;
+ let index: string[];
+ let documentId: string;
+ let createAndSyncRuleAndAlertsForOtherSpace: ReturnType<
+ typeof createAndSyncRuleAndAlertsFactory
+ >;
+
+ beforeEach(async () => {
+ documentId = uuidv4();
+ namespace = uuidv4();
+ index = [`risk-score.risk-score-${namespace}`];
+
+ createAndSyncRuleAndAlertsForOtherSpace = createAndSyncRuleAndAlertsFactory({
+ supertest,
+ log,
+ namespace,
+ });
+ const riskEngineRoutesForNamespace = riskEngineRouteHelpersFactory(supertest, namespace);
+
+ const spaces = getService('spaces');
+ await spaces.create({
+ id: namespace,
+ name: namespace,
+ disabledFeatures: [],
+ });
+
+ const baseEvent = buildDocument({ host: { name: 'host-1' } }, documentId);
+ await indexListOfDocuments(
+ Array(10)
+ .fill(baseEvent)
+ .map((_baseEvent, _index) => ({
+ ..._baseEvent,
+ 'host.name': `host-${_index}`,
+ }))
+ );
+
+ await createAndSyncRuleAndAlertsForOtherSpace({
+ query: `id: ${documentId}`,
+ alerts: 10,
+ riskScore: 40,
+ });
+
+ await riskEngineRoutesForNamespace.init();
+ });
+
+ afterEach(async () => {
+ await getService('spaces').delete(namespace);
+ await deleteRiskScoreIndices({ log, es, namespace });
+ });
+
+ it('calculates and persists risk scores for alert documents', async () => {
+ await waitForRiskScoresToBePresent({
+ es,
+ log,
+ scoreCount: 10,
+ index,
+ });
+
+ const scores = await readRiskScores(es, index);
+ expect(normalizeScores(scores).map(({ id_value: idValue }) => idValue)).to.eql(
+ Array(10)
+ .fill(0)
+ .map((_, _index) => `host-${_index}`)
+ );
+ });
+ });
+ });
+ });
+};
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/telemetry_usage.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/telemetry_usage.ts
similarity index 78%
rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/telemetry_usage.ts
rename to x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/telemetry_usage.ts
index 2e7888fe00591..f68a8c1dd3e60 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/telemetry_usage.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/default_license/risk_engine/telemetry_usage.ts
@@ -7,21 +7,21 @@
import expect from '@kbn/expect';
import { v4 as uuidv4 } from 'uuid';
-import type { FtrProviderContext } from '../../../../common/ftr_provider_context';
-import { deleteAllRules, deleteAllAlerts, getRiskEngineStats } from '../../../utils';
+import {
+ deleteAllRules,
+ deleteAllAlerts,
+ dataGeneratorFactory,
+} from '../../../detections_response/utils';
import {
buildDocument,
createAndSyncRuleAndAlertsFactory,
- deleteRiskEngineTask,
- deleteRiskScoreIndices,
waitForRiskScoresToBePresent,
riskEngineRouteHelpersFactory,
- cleanRiskEngineConfig,
- clearTransforms,
-} from './utils';
-import { dataGeneratorFactory } from '../../../utils/data_generator';
+ cleanRiskEngine,
+ getRiskEngineStats,
+} from '../../utils';
+import { FtrProviderContext } from '../../../../ftr_provider_context';
-// eslint-disable-next-line import/no-default-export
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
@@ -32,7 +32,7 @@ export default ({ getService }: FtrProviderContext) => {
const createAndSyncRuleAndAlerts = createAndSyncRuleAndAlertsFactory({ supertest, log });
const riskEngineRoutes = riskEngineRouteHelpersFactory(supertest);
- describe('Risk engine telemetry', async () => {
+ describe('@ess @serverless telemetry', async () => {
const { indexListOfDocuments } = dataGeneratorFactory({
es,
index: 'ecs_compliant',
@@ -49,12 +49,9 @@ export default ({ getService }: FtrProviderContext) => {
});
beforeEach(async () => {
- await cleanRiskEngineConfig({ kibanaServer });
- await deleteRiskEngineTask({ es, log });
- await deleteRiskScoreIndices({ log, es });
+ await cleanRiskEngine({ kibanaServer, es, log });
await deleteAllAlerts(supertest, log, es);
await deleteAllRules(supertest, log);
- await clearTransforms({ es, log });
});
describe('Risk engine not enabled', () => {
@@ -67,7 +64,6 @@ export default ({ getService }: FtrProviderContext) => {
});
});
- // FLAKY: https://github.com/elastic/kibana/issues/168429
describe('Risk engine enabled', () => {
let hostId: string;
let userId: string;
@@ -105,12 +101,9 @@ export default ({ getService }: FtrProviderContext) => {
});
afterEach(async () => {
- await cleanRiskEngineConfig({ kibanaServer });
- await deleteRiskEngineTask({ es, log });
- await deleteRiskScoreIndices({ log, es });
+ await cleanRiskEngine({ kibanaServer, es, log });
await deleteAllAlerts(supertest, log, es);
await deleteAllRules(supertest, log);
- await clearTransforms({ es, log });
});
it('should return riskEngineMetrics with expected values', async () => {
@@ -132,8 +125,6 @@ export default ({ getService }: FtrProviderContext) => {
all_host_risk_scores_total_day: 10,
};
expect(otherStats).to.eql(expected);
- expect(allRiskScoreIndexSize).to.be.greaterThan(0);
- expect(uniqueRiskScoreIndexSize).to.be.greaterThan(0);
});
});
});
diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_stats.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_stats.ts
new file mode 100644
index 0000000000000..c5343372ce99a
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/get_risk_engine_stats.ts
@@ -0,0 +1,73 @@
+/*
+ * 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 type { ToolingLog } from '@kbn/tooling-log';
+import type SuperTest from 'supertest';
+import type { DetectionMetrics } from '@kbn/security-solution-plugin/server/usage/detections/types';
+import type { RiskEngineMetrics } from '@kbn/security-solution-plugin/server/usage/risk_engine/types';
+import {
+ ELASTIC_HTTP_VERSION_HEADER,
+ X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
+} from '@kbn/core-http-common';
+
+import { getStatsUrl } from '../../../../detection_engine_api_integration/utils/get_stats_url';
+import {
+ getDetectionMetricsFromBody,
+ getRiskEngineMetricsFromBody,
+} from '../../../../detection_engine_api_integration/utils/get_detection_metrics_from_body';
+
+/**
+ * Gets the stats from the stats endpoint.
+ * @param supertest The supertest agent.
+ * @returns The detection metrics
+ */
+export const getStats = async (
+ supertest: SuperTest.SuperTest,
+ log: ToolingLog
+): Promise => {
+ const response = await supertest
+ .post(getStatsUrl())
+ .set('kbn-xsrf', 'true')
+ .set(ELASTIC_HTTP_VERSION_HEADER, '2')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
+ .send({ unencrypted: true, refreshCache: true });
+ if (response.status !== 200) {
+ log.error(
+ `Did not get an expected 200 "ok" when getting the stats for detections. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify(
+ response.body
+ )}, status: ${JSON.stringify(response.status)}`
+ );
+ }
+
+ return getDetectionMetricsFromBody(response.body);
+};
+
+/**
+ * Gets the stats from the stats endpoint.
+ * @param supertest The supertest agent.
+ * @returns The detection metrics
+ */
+export const getRiskEngineStats = async (
+ supertest: SuperTest.SuperTest,
+ log: ToolingLog
+): Promise => {
+ const response = await supertest
+ .post(getStatsUrl())
+ .set('kbn-xsrf', 'true')
+ .set(ELASTIC_HTTP_VERSION_HEADER, '2')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
+ .send({ unencrypted: true, refreshCache: true });
+ if (response.status !== 200) {
+ log.error(
+ `Did not get an expected 200 "ok" when getting the stats for risk engine. CI issues could happen. Suspect this line if you are seeing CI issues. body: ${JSON.stringify(
+ response.body
+ )}, status: ${JSON.stringify(response.status)}`
+ );
+ }
+
+ return getRiskEngineMetricsFromBody(response.body);
+};
diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts
new file mode 100644
index 0000000000000..00eb2adafd2e8
--- /dev/null
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/index.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+export * from './risk_engine';
+export * from './get_risk_engine_stats';
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/utils.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts
similarity index 87%
rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/utils.ts
rename to x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts
index 7af59dfab7cf8..48c7763d7a9d6 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/utils.ts
+++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts
@@ -5,13 +5,16 @@
* 2.0.
*/
-import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
+import {
+ ELASTIC_HTTP_VERSION_HEADER,
+ X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
+} from '@kbn/core-http-common';
import { v4 as uuidv4 } from 'uuid';
import SuperTest from 'supertest';
import type { Client } from '@elastic/elasticsearch';
import type { ToolingLog } from '@kbn/tooling-log';
import type { EcsRiskScore, RiskScore } from '@kbn/security-solution-plugin/common/risk_engine';
-import { riskEngineConfigurationTypeName } from '@kbn/security-solution-plugin/server/lib/risk_engine/saved_object';
+import { riskEngineConfigurationTypeName } from '@kbn/security-solution-plugin/server/lib/entity_analytics/risk_engine/saved_object';
import type { KbnClient } from '@kbn/test';
import {
RISK_ENGINE_INIT_URL,
@@ -21,13 +24,13 @@ import {
} from '@kbn/security-solution-plugin/common/constants';
import {
createRule,
- waitForSignalsToBePresent,
+ waitForAlertsToBePresent,
waitForRuleSuccess,
- getRuleForSignalTesting,
+ getRuleForAlertTesting,
countDownTest,
waitFor,
routeWithNamespace,
-} from '../../../utils';
+} from '../../detections_response/utils';
const sanitizeScore = (score: Partial): Partial => {
delete score['@timestamp'];
@@ -79,7 +82,7 @@ export const createAndSyncRuleAndAlertsFactory =
query: string;
riskScoreOverride?: string;
}): Promise => {
- const rule = getRuleForSignalTesting(['ecs_compliant']);
+ const rule = getRuleForAlertTesting(['ecs_compliant']);
const { id } = await createRule(
supertest,
log,
@@ -99,7 +102,7 @@ export const createAndSyncRuleAndAlertsFactory =
namespace
);
await waitForRuleSuccess({ supertest, log, id, namespace });
- await waitForSignalsToBePresent(supertest, log, alerts, [id], namespace);
+ await waitForAlertsToBePresent(supertest, log, alerts, [id], namespace);
};
export const deleteRiskScoreIndices = async ({
@@ -119,7 +122,7 @@ export const deleteRiskScoreIndices = async ({
}),
]);
} catch (e) {
- log.error(`Error deleting risk score indices: ${e.message}`);
+ log.warning(`Error deleting risk score indices: ${e.message}`);
}
};
@@ -302,6 +305,24 @@ export const cleanRiskEngineConfig = async ({
}
};
+/**
+ * General helper for cleaning up risk engine artifacts. This should be used before and after any risk engine tests so as not to pollute the test environment.
+ */
+export const cleanRiskEngine = async ({
+ es,
+ kibanaServer,
+ log,
+}: {
+ es: Client;
+ kibanaServer: KbnClient;
+ log: ToolingLog;
+}): Promise => {
+ await deleteRiskEngineTask({ es, log });
+ await cleanRiskEngineConfig({ kibanaServer });
+ await clearTransforms({ es, log });
+ await deleteRiskScoreIndices({ log, es });
+};
+
export const updateRiskEngineConfigSO = async ({
attributes,
kibanaServer,
@@ -344,7 +365,7 @@ export const clearTransforms = async ({
force: true,
});
} catch (e) {
- log.error(`Error deleting risk_score_latest_transform_default: ${e.message}`);
+ log.warning(`Error deleting risk_score_latest_transform_default: ${e.message}`);
}
};
@@ -364,7 +385,7 @@ export const clearLegacyTransforms = async ({
try {
await Promise.all(transforms);
} catch (e) {
- log.error(`Error deleting legacy transforms: ${e.message}`);
+ log.warning(`Error deleting legacy transforms: ${e.message}`);
}
};
@@ -381,6 +402,7 @@ export const clearLegacyDashboards = async ({
'/internal/risk_score/prebuilt_content/saved_objects/_bulk_delete/hostRiskScoreDashboards'
)
.set('kbn-xsrf', 'true')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200);
@@ -389,10 +411,11 @@ export const clearLegacyDashboards = async ({
'/internal/risk_score/prebuilt_content/saved_objects/_bulk_delete/userRiskScoreDashboards'
)
.set('kbn-xsrf', 'true')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200);
} catch (e) {
- log.error(`Error deleting legacy dashboards: ${e.message}`);
+ log.warning(`Error deleting legacy dashboards: ${e.message}`);
}
};
@@ -450,6 +473,7 @@ export const riskEngineRouteHelpersFactory = (
.post(routeWithNamespace(RISK_ENGINE_INIT_URL, namespace))
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200),
@@ -466,6 +490,7 @@ export const riskEngineRouteHelpersFactory = (
.post(routeWithNamespace(RISK_ENGINE_ENABLE_URL, namespace))
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200),
@@ -474,6 +499,7 @@ export const riskEngineRouteHelpersFactory = (
.post(routeWithNamespace(RISK_ENGINE_DISABLE_URL, namespace))
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200),
});
@@ -487,6 +513,7 @@ export const installLegacyRiskScore = async ({
.post('/internal/risk_score')
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send({ riskScoreEntity: 'host' })
.expect(200);
@@ -494,6 +521,7 @@ export const installLegacyRiskScore = async ({
.post('/internal/risk_score')
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send({ riskScoreEntity: 'user' })
.expect(200);
@@ -503,6 +531,7 @@ export const installLegacyRiskScore = async ({
)
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200);
@@ -512,6 +541,7 @@ export const installLegacyRiskScore = async ({
)
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
+ .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200);
};
diff --git a/x-pack/test/security_solution_api_integration/tsconfig.json b/x-pack/test/security_solution_api_integration/tsconfig.json
index b2e2715a52ccd..2c3b9082ac7cc 100644
--- a/x-pack/test/security_solution_api_integration/tsconfig.json
+++ b/x-pack/test/security_solution_api_integration/tsconfig.json
@@ -30,6 +30,7 @@
"@kbn/core-saved-objects-server",
"@kbn/core",
"@kbn/alerting-plugin",
+ "@kbn/core-http-common",
"@kbn/securitysolution-ecs"
]
}
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts
index c55c8f62dc4a9..2ec99abb00db4 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_status.cy.ts
@@ -37,10 +37,13 @@ import { visit } from '../../../tasks/navigation';
import { ALERTS_URL } from '../../../urls/navigation';
-// FLAKY: https://github.com/elastic/kibana/issues/169091
-describe('Changing alert status', () => {
+describe('Changing alert status', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
- cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' });
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
+ });
+
+ after(() => {
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
});
context('Opening alerts', { tags: ['@ess', '@serverless'] }, () => {
@@ -56,10 +59,6 @@ describe('Changing alert status', () => {
waitForAlerts();
});
- after(() => {
- cy.task('esArchiverUnload', 'auditbeat_big');
- });
-
it('can mark a closed alert as open', () => {
waitForAlertsToPopulate();
cy.get(ALERTS_COUNT)
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts
index ee3955576a272..162c63ad3ce48 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_alerts/alert_tags.cy.ts
@@ -26,19 +26,24 @@ import {
} from '../../../screens/alerts';
describe('Alert tagging', { tags: ['@ess', '@serverless'] }, () => {
+ before(() => {
+ cy.task('esArchiverLoad', { archiveName: 'endpoint' });
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
+ });
+
+ after(() => {
+ cy.task('esArchiverUnload', 'endpoint');
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
+ });
+
beforeEach(() => {
login();
deleteAlertsAndRules();
- cy.task('esArchiverLoad', { archiveName: 'endpoint' });
createRule(getNewRule({ rule_id: 'new custom rule' }));
visitWithTimeRange(ALERTS_URL);
waitForAlertsToPopulate();
});
- afterEach(() => {
- cy.task('esArchiverUnload', 'endpoint');
- });
-
it('Add and remove a tag using the alert bulk action menu', () => {
// Add a tag to one alert
selectNumberOfAlerts(1);
@@ -66,13 +71,13 @@ describe('Alert tagging', { tags: ['@ess', '@serverless'] }, () => {
updateAlertTags();
cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist');
// Then add tags to both alerts
- selectNumberOfAlerts(2);
+ selectNumberOfAlerts(5);
openAlertTaggingBulkActionMenu();
cy.get(MIXED_ALERT_TAG).contains('Duplicate');
clickAlertTag('Duplicate');
updateAlertTags();
cy.get(ALERTS_TABLE_ROW_LOADER).should('not.exist');
- selectNumberOfAlerts(2);
+ selectNumberOfAlerts(5);
openAlertTaggingBulkActionMenu();
cy.get(SELECTED_ALERT_TAG).contains('Duplicate');
});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts
index eeca0d06bcc57..b895460661858 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts
@@ -71,7 +71,7 @@ describe('EQL rules', { tags: ['@ess', '@serverless'] }, () => {
const mitreAttack = rule.threat;
const expectedMitre = formatMitreAttackDescription(mitreAttack ?? []);
const expectedNumberOfRules = 1;
- const expectedNumberOfAlerts = '2 alerts';
+ const expectedNumberOfAlerts = '1 alert';
it('Creates and enables a new EQL rule', function () {
visit(CREATE_RULE_URL);
@@ -143,11 +143,12 @@ describe('EQL rules', { tags: ['@ess', '@serverless'] }, () => {
const rule = getEqlSequenceRule();
- beforeEach(() => {
- cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' });
+ before(() => {
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
});
- afterEach(() => {
- cy.task('esArchiverUnload', 'auditbeat_big');
+
+ after(() => {
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
});
it('Creates and enables a new EQL rule with a sequence', function () {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts
index 7b8e5b0744c72..585cd9187f3e0 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/override.cy.ts
@@ -146,8 +146,8 @@ describe('Rules override', { tags: ['@ess', '@serverless'] }, () => {
cy.get(ALERTS_COUNT)
.invoke('text')
.should('match', /^[1-9].+$/); // Any number of alerts
- cy.get(ALERT_GRID_CELL).contains('auditbeat');
- cy.get(ALERT_GRID_CELL).contains('critical');
+ cy.get(ALERT_GRID_CELL).contains('winlogbeat');
+ cy.get(ALERT_GRID_CELL).contains('high');
cy.get(ALERT_GRID_CELL).contains('80');
});
});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts
index d543843641b78..ac6c723dbc0c6 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_edit_rules_actions.cy.ts
@@ -76,7 +76,7 @@ const expectedSlackMessage = 'Slack action test message';
describe(
'Detection rules, bulk edit of rule actions',
- { tags: ['@ess', '@serverless', '@brokenInServerlessQA'] },
+ { tags: ['@ess', '@serverless', '@brokenInServerless', '@brokenInServerlessQA'] },
() => {
beforeEach(() => {
login();
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts
index a676fe5038d3e..24d13322f7d9d 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts
@@ -38,7 +38,6 @@ import {
previewErrorButtonClick,
} from '../../tasks/entity_analytics';
-// TODO: https://github.com/elastic/kibana/issues/161539
describe(
'Entity analytics management page',
{
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts
index 7474fd2e5cf2d..8ec40a0e36436 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts
@@ -50,179 +50,182 @@ import {
createEndpointExceptionListItem,
} from '../../../tasks/api_calls/exceptions';
-// TODO: https://github.com/elastic/kibana/issues/161539
-describe(
- 'Add endpoint exception from rule details',
- { tags: ['@ess', '@serverless', '@brokenInServerless'] },
- () => {
- const ITEM_NAME = 'Sample Exception List Item';
- const NEW_ITEM_NAME = 'Exception item-EDITED';
- const ITEM_FIELD = 'event.code';
- const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.type';
-
+describe('Add endpoint exception from rule details', { tags: ['@ess', '@serverless'] }, () => {
+ const ITEM_NAME = 'Sample Exception List Item';
+ const NEW_ITEM_NAME = 'Exception item-EDITED';
+ const ITEM_FIELD = 'event.code';
+ const FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD = 'agent.type';
+
+ before(() => {
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
+ });
+
+ after(() => {
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
+ });
+
+ beforeEach(() => {
+ deleteExceptionLists();
+ deleteEndpointExceptionList();
+ login();
+ deleteAlertsAndRules();
+ });
+
+ describe('without exception items', () => {
beforeEach(() => {
- deleteExceptionLists();
- deleteEndpointExceptionList();
- login();
- deleteAlertsAndRules();
- });
-
- describe('without exception items', () => {
- beforeEach(() => {
- createEndpointExceptionList().then((response) => {
- createRule(
- getNewRule({
- query: 'event.code:*',
- index: ['auditbeat*'],
- exceptions_list: [
- {
- id: response.body.id,
- list_id: response.body.list_id,
- type: response.body.type,
- namespace_type: response.body.namespace_type,
- },
- ],
- rule_id: '2',
- enabled: false,
- })
- ).then((rule) => visitRuleDetailsPage(rule.body.id, { tab: 'endpoint_exceptions' }));
- });
+ createEndpointExceptionList().then((response) => {
+ createRule(
+ getNewRule({
+ query: 'event.code:*',
+ index: ['auditbeat*'],
+ exceptions_list: [
+ {
+ id: response.body.id,
+ list_id: response.body.list_id,
+ type: response.body.type,
+ namespace_type: response.body.namespace_type,
+ },
+ ],
+ rule_id: '2',
+ enabled: false,
+ })
+ ).then((rule) => visitRuleDetailsPage(rule.body.id, { tab: 'endpoint_exceptions' }));
});
+ });
- it('creates an exception item', () => {
- // when no exceptions exist, empty component shows with action to add exception
- cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist');
+ it('creates an exception item', () => {
+ // when no exceptions exist, empty component shows with action to add exception
+ cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('exist');
- // open add exception modal
- openExceptionFlyoutFromEmptyViewerPrompt();
+ // open add exception modal
+ openExceptionFlyoutFromEmptyViewerPrompt();
- // submit button is disabled if no paramerters were added
- cy.get(CONFIRM_BTN).should('have.attr', 'disabled');
+ // submit button is disabled if no paramerters were added
+ cy.get(CONFIRM_BTN).should('have.attr', 'disabled');
- // for endpoint exceptions, must specify OS
- selectOs('windows');
+ // for endpoint exceptions, must specify OS
+ selectOs('windows');
- // add exception item conditions
- addExceptionConditions({
- field: 'event.code',
- operator: 'is',
- values: ['foo'],
- });
+ // add exception item conditions
+ addExceptionConditions({
+ field: 'event.code',
+ operator: 'is',
+ values: ['foo'],
+ });
- // Name is required so want to check that submit is still disabled
- cy.get(CONFIRM_BTN).should('have.attr', 'disabled');
+ // Name is required so want to check that submit is still disabled
+ cy.get(CONFIRM_BTN).should('have.attr', 'disabled');
- // add exception item name
- addExceptionFlyoutItemName(ITEM_NAME);
+ // add exception item name
+ addExceptionFlyoutItemName(ITEM_NAME);
- // Option to add to rule or add to list should NOT appear
- cy.get(ADD_TO_RULE_OR_LIST_SECTION).should('not.exist');
+ // Option to add to rule or add to list should NOT appear
+ cy.get(ADD_TO_RULE_OR_LIST_SECTION).should('not.exist');
- // not testing close alert functionality here, just ensuring that the options appear as expected
- cy.get(CLOSE_SINGLE_ALERT_CHECKBOX).should('not.exist');
- cy.get(CLOSE_ALERTS_CHECKBOX).should('exist');
+ // not testing close alert functionality here, just ensuring that the options appear as expected
+ cy.get(CLOSE_SINGLE_ALERT_CHECKBOX).should('not.exist');
+ cy.get(CLOSE_ALERTS_CHECKBOX).should('exist');
- // submit
- submitNewExceptionItem();
+ // submit
+ submitNewExceptionItem();
- // new exception item displays
- cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
- });
+ // new exception item displays
+ cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
});
+ });
+
+ describe('with exception items', () => {
+ beforeEach(() => {
+ createEndpointExceptionList().then((response) => {
+ createEndpointExceptionListItem({
+ comments: [],
+ description: 'Exception list item',
+ entries: [
+ {
+ field: ITEM_FIELD,
+ operator: 'included',
+ type: 'match',
+ value: 'foo',
+ },
+ ],
+ name: ITEM_NAME,
+ tags: [],
+ type: 'simple',
+ os_types: ['windows'],
+ });
- describe('with exception items', () => {
- beforeEach(() => {
- createEndpointExceptionList().then((response) => {
- createEndpointExceptionListItem({
- comments: [],
- description: 'Exception list item',
- entries: [
+ createRule(
+ getNewRule({
+ name: 'Rule with exceptions',
+ query: 'event.code:*',
+ index: ['auditbeat*'],
+ exceptions_list: [
{
- field: ITEM_FIELD,
- operator: 'included',
- type: 'match',
- value: 'foo',
+ id: response.body.id,
+ list_id: response.body.list_id,
+ type: response.body.type,
+ namespace_type: response.body.namespace_type,
},
],
- name: ITEM_NAME,
- tags: [],
- type: 'simple',
- os_types: ['windows'],
- });
-
- createRule(
- getNewRule({
- name: 'Rule with exceptions',
- query: 'event.code:*',
- index: ['auditbeat*'],
- exceptions_list: [
- {
- id: response.body.id,
- list_id: response.body.list_id,
- type: response.body.type,
- namespace_type: response.body.namespace_type,
- },
- ],
- rule_id: '2',
- enabled: false,
- })
- ).then((rule) => {
- visitRuleDetailsPage(rule.body.id, { tab: 'endpoint_exceptions' });
- waitForRuleDetailsPageToBeLoaded('Rule with exceptions');
- });
+ rule_id: '2',
+ enabled: false,
+ })
+ ).then((rule) => {
+ visitRuleDetailsPage(rule.body.id, { tab: 'endpoint_exceptions' });
+ waitForRuleDetailsPageToBeLoaded('Rule with exceptions');
});
});
+ });
- it('edits an endpoint exception item', () => {
- // displays existing exception items
- cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
- cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist');
- cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME);
- cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ` ${ITEM_FIELD}IS foo`);
+ it('edits an endpoint exception item', () => {
+ // displays existing exception items
+ cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
+ cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist');
+ cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME);
+ cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ` ${ITEM_FIELD}IS foo`);
- // open edit exception modal
- openEditException();
+ // open edit exception modal
+ openEditException();
- // edit exception item name
- editExceptionFlyoutItemName(NEW_ITEM_NAME);
+ // edit exception item name
+ editExceptionFlyoutItemName(NEW_ITEM_NAME);
- // check that the existing item's field is being populated
- cy.get(EXCEPTION_ITEM_CONTAINER)
- .eq(0)
- .find(FIELD_INPUT_PARENT)
- .eq(0)
- .should('have.text', ITEM_FIELD);
- cy.get(VALUES_INPUT).should('have.text', 'foo');
+ // check that the existing item's field is being populated
+ cy.get(EXCEPTION_ITEM_CONTAINER)
+ .eq(0)
+ .find(FIELD_INPUT_PARENT)
+ .eq(0)
+ .should('have.text', ITEM_FIELD);
+ cy.get(VALUES_INPUT).should('have.text', 'foo');
- // edit conditions
- editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0);
+ // edit conditions
+ editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0);
- // submit
- submitEditedExceptionItem();
+ // submit
+ submitEditedExceptionItem();
- // new exception item displays
- cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
+ // new exception item displays
+ cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
- // check that updates stuck
- cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME);
- cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.typeIS foo');
- });
+ // check that updates stuck
+ cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', NEW_ITEM_NAME);
+ cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should('have.text', ' agent.typeIS foo');
+ });
- it('allows user to search for items', () => {
- cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
+ it('allows user to search for items', () => {
+ cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
- // can search for an exception value
- searchForExceptionItem('foo');
+ // can search for an exception value
+ searchForExceptionItem('foo');
- // new exception item displays
- cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
+ // new exception item displays
+ cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1);
- // displays empty search result view if no matches found
- searchForExceptionItem('abc');
+ // displays empty search result view if no matches found
+ searchForExceptionItem('abc');
- // new exception item displays
- cy.get(NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT).should('exist');
- });
+ // new exception item displays
+ cy.get(NO_EXCEPTIONS_SEARCH_RESULTS_PROMPT).should('exist');
});
- }
-);
+ });
+});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts
index eba0c3a64570f..023140d420f2a 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts
@@ -6,6 +6,7 @@
*/
import type { RuleResponse } from '@kbn/security-solution-plugin/common/api/detection_engine';
+import { MAX_COMMENT_LENGTH } from '@kbn/security-solution-plugin/common/constants';
import { getNewRule } from '../../../objects/rule';
import { login } from '../../../tasks/login';
import { visit } from '../../../tasks/navigation';
@@ -20,9 +21,7 @@ import {
submitEditedExceptionItem,
submitNewExceptionItem,
deleteFirstExceptionItemInListDetailPage,
- dismissExceptionItemErrorCallOut,
addExceptionHugeComment,
- submitNewExceptionItemWithFailure,
editExceptionComment,
} from '../../../tasks/exceptions';
import { EXCEPTIONS_URL } from '../../../urls/navigation';
@@ -42,7 +41,6 @@ import {
} from '../../../tasks/exceptions_table';
import { visitRuleDetailsPage } from '../../../tasks/rule_details';
import { deleteEndpointExceptionList, deleteExceptionLists } from '../../../tasks/common';
-import { closeErrorToast } from '../../../tasks/alerts_detection_rules';
describe('Add, edit and delete exception', { tags: ['@ess', '@serverless'] }, () => {
beforeEach(() => {
@@ -147,7 +145,7 @@ describe('Add, edit and delete exception', { tags: ['@ess', '@serverless'] }, ()
cy.get(EMPTY_EXCEPTIONS_VIEWER).should('exist');
});
- it('should handle huge text as a comment gracefully and allow user create exception item after user updates the comment', function () {
+ it('should not allow to add huge text as a comment', function () {
createSharedExceptionList(
{ name: 'Newly created list', description: 'This is my list.' },
true
@@ -173,26 +171,19 @@ describe('Add, edit and delete exception', { tags: ['@ess', '@serverless'] }, ()
linkFirstSharedListOnExceptionFlyout();
// add exception comment which is super long
- addExceptionHugeComment([...new Array(5000).keys()].map((_) => `Test text!`).join(''));
-
- // submit
- submitNewExceptionItemWithFailure();
+ addExceptionHugeComment(
+ [...new Array(MAX_COMMENT_LENGTH + 1).keys()].map((_) => 'a').join('')
+ );
- // Failed to add exception due to comment length and submit button should be disabled
+ // submit button should be disabled due to comment length
cy.get(CONFIRM_BTN).should('have.attr', 'disabled');
- // Close error toast
- closeErrorToast();
-
- // Dismiss error callout
- dismissExceptionItemErrorCallOut();
-
- // Submit button should be enabled after we dismissed error callout
- cy.get(CONFIRM_BTN).should('not.have.attr', 'disabled');
-
// update exception comment to a reasonable (length wise) text
editExceptionComment('Exceptional comment');
+ // submit button should be enabled
+ cy.get(CONFIRM_BTN).should('not.have.attr', 'disabled');
+
// submit
submitNewExceptionItem();
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts
index 83b9d086db5f2..7bb492d51d25c 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/entity_analytics.cy.ts
@@ -57,9 +57,9 @@ import {
import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine';
import { enableRiskEngine } from '../../../tasks/entity_analytics';
-const TEST_USER_ALERTS = 2;
+const TEST_USER_ALERTS = 1;
const TEST_USER_NAME = 'test';
-const SIEM_KIBANA_HOST_ALERTS = 2;
+const SIEM_KIBANA_HOST_ALERTS = 1;
const SIEM_KIBANA_HOST_NAME = 'siem-kibana';
const DATE_FORMAT = 'MMM D, YYYY @ HH:mm:ss.SSS';
const DATE_BEFORE_ALERT_CREATION = moment().format(DATE_FORMAT);
@@ -67,10 +67,15 @@ const OLDEST_DATE = moment('2019-01-19T16:22:56.217Z').format(DATE_FORMAT);
describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
login();
deleteRiskEngineConfiguration();
});
+ after(() => {
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
+ });
+
describe('legacy risk score', () => {
describe('Without data', () => {
beforeEach(() => {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts
index 20884e070cf9a..0a211a58feba3 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/hosts/events_viewer.cy.ts
@@ -48,11 +48,11 @@ const defaultHeadersInDefaultEcsCategory = [
describe('Events Viewer', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
- cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' });
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
});
after(() => {
- cy.task('esArchiverUnload', 'auditbeat_big');
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
});
context('Fields rendering', () => {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts
index 0fcb7f86cd0de..1205d2420b7ab 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/overview/overview.cy.ts
@@ -64,13 +64,6 @@ describe('Overview Page', { tags: ['@ess', '@serverless', '@serverlessQA'] }, ()
});
describe('Overview page with no data', { tags: '@brokenInServerless' }, () => {
- before(() => {
- cy.task('esArchiverUnload', 'auditbeat');
- });
- after(() => {
- cy.task('esArchiverLoad', { archiveName: 'auditbeat' });
- });
-
it('Splash screen should be here', () => {
login();
visitWithTimeRange(OVERVIEW_URL);
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts
index 84cfcc8b52aad..911b870d08347 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_cell_actions.cy.ts
@@ -105,7 +105,7 @@ describe('Alerts cell actions', { tags: ['@ess', '@serverless'] }, () => {
.first()
.invoke('text')
.then((severityVal) => {
- scrollAlertTableColumnIntoView(ALERT_TABLE_SEVERITY_VALUES);
+ scrollAlertTableColumnIntoView(ALERT_TABLE_SEVERITY_HEADER);
addAlertPropertyToTimeline(ALERT_TABLE_SEVERITY_VALUES, 0);
openActiveTimeline();
cy.get(PROVIDER_BADGE)
@@ -138,7 +138,7 @@ describe('Alerts cell actions', { tags: ['@ess', '@serverless'] }, () => {
.first()
.invoke('text')
.then(() => {
- scrollAlertTableColumnIntoView(ALERT_TABLE_SEVERITY_VALUES);
+ scrollAlertTableColumnIntoView(ALERT_TABLE_SEVERITY_HEADER);
showTopNAlertProperty(ALERT_TABLE_SEVERITY_VALUES, 0);
cy.get(SHOW_TOP_N_HEADER).first().should('have.text', `Top kibana.alert.severity`);
});
@@ -157,7 +157,7 @@ describe('Alerts cell actions', { tags: ['@ess', '@serverless'] }, () => {
.first()
.invoke('text')
.then(() => {
- scrollAlertTableColumnIntoView(ALERT_TABLE_SEVERITY_VALUES);
+ scrollAlertTableColumnIntoView(ALERT_TABLE_SEVERITY_HEADER);
cy.window().then((win) => {
cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT');
});
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts
index 1868435825597..426193bbf72ba 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts
@@ -38,14 +38,14 @@ describe(
});
it('Filter in/out should add a filter to KQL bar', function () {
- const expectedNumberOfAlerts = 2;
+ const expectedNumberOfAlerts = 1;
clickAlertsHistogramLegend();
clickAlertsHistogramLegendFilterFor(ruleConfigs.name);
cy.get(GLOBAL_SEARCH_BAR_FILTER_ITEM).should(
'have.text',
`kibana.alert.rule.name: ${ruleConfigs.name}`
);
- cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alerts`);
+ cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alert`);
clickAlertsHistogramLegend();
clickAlertsHistogramLegendFilterOut(ruleConfigs.name);
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts
index ee51f507e37c7..9ab0d07569421 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts
@@ -54,8 +54,8 @@ describe('Alert details flyout', { tags: ['@ess', '@serverless'] }, () => {
it('should update the table when status of the alert is updated', () => {
cy.get(OVERVIEW_RULE).should('be.visible');
- cy.get(ALERTS_TABLE_COUNT).should('have.text', '2 alerts');
- cy.get(ALERT_SUMMARY_SEVERITY_DONUT_CHART).should('contain.text', '2alerts');
+ cy.get(ALERTS_TABLE_COUNT).should('have.text', '1 alert');
+ cy.get(ALERT_SUMMARY_SEVERITY_DONUT_CHART).should('contain.text', '1alert');
expandFirstAlert();
changeAlertStatusTo('acknowledged');
cy.get(ALERTS_TABLE_COUNT).should('have.text', '1 alert');
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts
index d913d1701c2c8..718feeca31533 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/building_block_alerts.cy.ts
@@ -19,11 +19,11 @@ const EXPECTED_NUMBER_OF_ALERTS = 5;
describe('Alerts generated by building block rules', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
- cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' });
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
});
after(() => {
- cy.task('esArchiverUnload', 'auditbeat_big');
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
});
beforeEach(() => {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts
index 3ee54dd437942..f06fad0cd43ee 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts
@@ -42,11 +42,11 @@ import { ALERTS_URL } from '../../../urls/navigation';
// Iusse tracked in: https://github.com/elastic/kibana/issues/167809
describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () => {
before(() => {
- cy.task('esArchiverLoad', { archiveName: 'auditbeat_big' });
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' });
});
after(() => {
- cy.task('esArchiverUnload', 'auditbeat_big');
+ cy.task('esArchiverUnload', 'auditbeat_multiple');
});
context('Opening alerts', () => {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts
index 55b0817483ff6..dd29284f6c0ce 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/detection_page_filters.cy.ts
@@ -235,7 +235,7 @@ describe(`Detections : Page Filters`, { tags: ['@ess', '@serverless'] }, () => {
cy.get(ALERTS_COUNT)
.invoke('text')
.should((newAlertCount) => {
- expect(newAlertCount.split(' ')[0]).eq(String(parseInt(originalAlertCount, 10) - 1));
+ expect(newAlertCount.split(' ')[0]).eq(String(parseInt(originalAlertCount, 10)));
});
});
});
@@ -318,7 +318,7 @@ describe(`Detections : Page Filters`, { tags: ['@ess', '@serverless'] }, () => {
togglePageFilterPopover(0);
cy.get(OPTION_SELECTABLE(0, 'open')).should('be.visible');
cy.get(OPTION_SELECTABLE(0, 'open')).should('contain.text', 'open');
- cy.get(OPTION_SELECTABLE(0, 'open')).get(OPTION_SELECTABLE_COUNT).should('have.text', 2);
+ cy.get(OPTION_SELECTABLE(0, 'open')).get(OPTION_SELECTABLE_COUNT).should('have.text', 1);
});
it('should take kqlQuery into account', () => {
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts
index d0f12799c795a..38fd4ffb7496a 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts
@@ -70,7 +70,7 @@ describe(
.and('contain.text', 'test');
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_ALERT_COUNT_CELL).should(
'contain.text',
- 2
+ 1
);
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_DOC_COUNT_CELL).should(
'contain.text',
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts
index db3fad7b57b2d..0570557d33f21 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/investigate_in_timeline.cy.ts
@@ -65,10 +65,12 @@ describe('Investigate in timeline', { tags: ['@ess', '@serverless'] }, () => {
// Click on the last button that lets us investigate in timeline.
// We expect this to be the `process.args` row.
+ cy.get(ALERT_FLYOUT).find(SUMMARY_VIEW_INVESTIGATE_IN_TIMELINE_BUTTON).eq(5).scrollIntoView();
cy.get(ALERT_FLYOUT)
.find(SUMMARY_VIEW_INVESTIGATE_IN_TIMELINE_BUTTON)
- .last()
- .should('have.text', alertCount)
+ .eq(5)
+ .should('be.visible')
+ .and('have.text', alertCount)
.click();
// Make sure a new timeline is created and opened
diff --git a/x-pack/test/security_solution_cypress/cypress/screens/common/filter_group.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/filter_group.ts
index a4c069c2e2467..0f037a9955726 100644
--- a/x-pack/test/security_solution_cypress/cypress/screens/common/filter_group.ts
+++ b/x-pack/test/security_solution_cypress/cypress/screens/common/filter_group.ts
@@ -7,37 +7,22 @@
import { getDataTestSubjectSelector } from '../../helpers/common';
-export const FILTER_GROUP_LOADING = '[data-test-subj="filter-group__loading"]';
-export const FILTER_GROUP_ITEMS = '[data-test-subj="filter-group__items"]';
-export const FILTER_GROUP_CLEAR = '[data-test-subj="filter-group__clear"]';
-
+export const CONTROL_GROUP = '[data-test-subj="controls-group"]';
export const CONTROL_FRAMES = '[data-test-subj="control-frame"]';
export const CONTROL_FRAME_TITLE = '[data-test-subj="control-frame-title"]';
-export const CONTROL_FRAME_DRAG_HANDLE = '.controlFrame__dragHandle';
-
export const OPTION_LIST_LABELS = '.controlFrame__labelToolTip';
export const OPTION_LIST_VALUES = (idx: number) => `[data-test-subj="optionsList-control-${idx}"]`;
export const OPTION_LIST_CLEAR_BTN = '.presentationUtil__floatingActions [aria-label="Clear"]';
-export const OPTION_LIST_NUMBER_OFF = '.euiFilterButton__notification';
-
export const OPTION_LISTS_LOADING = '.optionsList--filterBtnWrapper .euiLoadingSpinner';
-export const OPTION_LISTS_EXISTS = '[data-test-subj="optionsList-control-selection-exists"]';
-
-export const OPTION_LIST_ACTIVE_CLEAR_SELECTION =
- '[data-test-subj="optionsList-control-clear-all-selections"]';
-
export const OPTION_SELECTABLE = (popoverIndex: number, value: string) =>
`#control-popover-${popoverIndex} [data-test-subj="optionsList-control-selection-${value}"]`;
-export const OPTION_IGNORED = (popoverIndex: number, value: string) =>
- `#control-popover-${popoverIndex} [data-test-subj="optionsList-control-ignored-selection-${value}"]`;
-
export const OPTION_SELECTABLE_COUNT = getDataTestSubjectSelector(
'optionsList-document-count-badge'
);
@@ -61,8 +46,6 @@ export const DETECTION_PAGE_FILTER_GROUP_RESET_BUTTON =
export const FILTER_GROUP_CONTEXT_EDIT_CONTROLS = '[data-test-subj="filter-group__context--edit"]';
-export const FILTER_GROUP_CONTEXT_SAVE_CONTROLS = '[data-test-subj="filter-group__context--save"]';
-
export const FILTER_GROUP_CONTEXT_DISCARD_CHANGES =
'[data-test-subj="filter-group__context--discard"]';
@@ -70,10 +53,6 @@ export const FILTER_GROUP_ADD_CONTROL = '[data-test-subj="filter-group__add-cont
export const FILTER_GROUP_SAVE_CHANGES = '[data-test-subj="filter-group__save"]';
-export const FILTER_GROUP_DISCARD_CHANGES = '[data-test-subj="filter-group__discard"]';
-
-export const FILTER_GROUP_SAVE_CHANGES_POPOVER = '[data-test-subj="filter-group__save-popover"]';
-
export const FILTER_GROUP_EDIT_CONTROLS_PANEL = '[data-test-subj="control-editor-flyout"]';
export const FILTER_GROUP_EDIT_CONTROL_PANEL_ITEMS = {
diff --git a/x-pack/test/security_solution_cypress/cypress/screens/overview.ts b/x-pack/test/security_solution_cypress/cypress/screens/overview.ts
index 442fcf621fc95..37b95f6ba6f59 100644
--- a/x-pack/test/security_solution_cypress/cypress/screens/overview.ts
+++ b/x-pack/test/security_solution_cypress/cypress/screens/overview.ts
@@ -55,7 +55,7 @@ const STAT_PACKAGE = {
domId: '[data-test-subj="host-stat-auditbeatPackage"]',
};
const STAT_PROCESS = {
- value: '2',
+ value: '1',
domId: '[data-test-subj="host-stat-auditbeatProcess"]',
};
const STAT_USER = {
diff --git a/x-pack/test/security_solution_cypress/cypress/support/e2e.ts b/x-pack/test/security_solution_cypress/cypress/support/e2e.ts
index eb3488178485f..b0961b77a2bba 100644
--- a/x-pack/test/security_solution_cypress/cypress/support/e2e.ts
+++ b/x-pack/test/security_solution_cypress/cypress/support/e2e.ts
@@ -16,7 +16,7 @@ import { setupUsers } from './setup_users';
import { CLOUD_SERVERLESS, IS_SERVERLESS } from '../env_var_names_constants';
before(() => {
- cy.task('esArchiverLoad', { archiveName: 'auditbeat' });
+ cy.task('esArchiverLoad', { archiveName: 'auditbeat_single' });
});
if (!Cypress.env(IS_SERVERLESS) && !Cypress.env(CLOUD_SERVERLESS)) {
diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts
index 23b5d106cb6cf..cc1a06d3545de 100644
--- a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts
+++ b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts
@@ -75,6 +75,7 @@ import {
OPTION_LIST_VALUES,
OPTION_LIST_CLEAR_BTN,
OPTION_SELECTABLE,
+ CONTROL_GROUP,
} from '../screens/common/filter_group';
import { LOADING_SPINNER } from '../screens/common/page';
import { ALERTS_URL } from '../urls/navigation';
@@ -189,7 +190,7 @@ export const closePageFilterPopover = (filterIndex: number) => {
};
export const clearAllSelections = (filterIndex: number) => {
- cy.scrollTo('top');
+ cy.get(CONTROL_GROUP).scrollIntoView();
recurse(
() => {
cy.get(CONTROL_FRAME_TITLE).eq(filterIndex).realHover();
diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts
index 00d6c2d405b87..4ed5ff5ef2f8d 100644
--- a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts
+++ b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts
@@ -237,8 +237,9 @@ export const addExceptionComment = (comment: string) => {
export const addExceptionHugeComment = (comment: string) => {
cy.get(EXCEPTION_COMMENTS_ACCORDION_BTN).click();
+ cy.get(EXCEPTION_COMMENT_TEXT_AREA).type(` {backspace}`);
cy.get(EXCEPTION_COMMENT_TEXT_AREA).invoke('val', comment);
- cy.get(EXCEPTION_COMMENT_TEXT_AREA).type(`!{backspace}`);
+ cy.get(EXCEPTION_COMMENT_TEXT_AREA).type(` {backspace}`);
cy.get(EXCEPTION_COMMENT_TEXT_AREA).should('have.value', comment);
};
diff --git a/x-pack/test/security_solution_cypress/es_archives/auditbeat_big/data.json b/x-pack/test/security_solution_cypress/es_archives/auditbeat_multiple/data.json
similarity index 100%
rename from x-pack/test/security_solution_cypress/es_archives/auditbeat_big/data.json
rename to x-pack/test/security_solution_cypress/es_archives/auditbeat_multiple/data.json
diff --git a/x-pack/test/security_solution_cypress/es_archives/auditbeat_big/mappings.json b/x-pack/test/security_solution_cypress/es_archives/auditbeat_multiple/mappings.json
similarity index 100%
rename from x-pack/test/security_solution_cypress/es_archives/auditbeat_big/mappings.json
rename to x-pack/test/security_solution_cypress/es_archives/auditbeat_multiple/mappings.json
diff --git a/x-pack/test/security_solution_cypress/es_archives/auditbeat/data.json b/x-pack/test/security_solution_cypress/es_archives/auditbeat_single/data.json
similarity index 50%
rename from x-pack/test/security_solution_cypress/es_archives/auditbeat/data.json
rename to x-pack/test/security_solution_cypress/es_archives/auditbeat_single/data.json
index a4e42ac0335a9..cb9a035e8d19d 100644
--- a/x-pack/test/security_solution_cypress/es_archives/auditbeat/data.json
+++ b/x-pack/test/security_solution_cypress/es_archives/auditbeat_single/data.json
@@ -1,126 +1,3 @@
-{
- "type": "doc",
- "value": {
- "id": "_aZE5nwBOpWiDweSth_F",
- "index": "auditbeat-2022",
- "source": {
- "@timestamp" : "2022-03-04T19:41:33.045Z",
- "host" : {
- "hostname" : "test.local",
- "architecture" : "x86_64",
- "os" : {
- "platform" : "darwin",
- "version" : "10.16",
- "family" : "darwin",
- "name" : "Mac OS X",
- "kernel" : "21.3.0",
- "build" : "21D62",
- "type" : "macos"
- },
- "id" : "44426D67-79AB-547C-7777-440AB8F5DDD2",
- "ip" : [
- "fe80::bade:48ff:fe00:1122",
- "fe81::4ab:9565:1199:be3",
- "192.168.5.175",
- "fe80::40d7:d0ff:fe66:f55",
- "fe81::40d8:d0ff:fe66:f55",
- "fe82::c2c:6bdf:3307:dce0",
- "fe83::5069:fcd5:e31c:7059",
- "fe80::ce81:b2c:bd2c:69e",
- "fe80::febc:bbc1:c517:827b",
- "fe80::6d09:bee6:55a5:539d",
- "fe80::c920:752e:1e0e:edc9",
- "fe80::a4a:ca38:761f:83e2"
- ],
- "mac" : [
- "ad:df:48:00:11:22",
- "a6:86:e7:ae:5a:b6",
- "a9:83:e7:ae:5a:b6",
- "43:d8:d0:66:0f:55",
- "42:d8:d0:66:0f:57",
- "82:70:c7:c2:3c:01",
- "82:70:c6:c2:4c:00",
- "82:76:a6:c2:3c:05",
- "82:70:c6:b2:3c:04",
- "82:71:a6:c2:3c:01"
- ],
- "name" : "siem-kibana"
- },
- "agent" : {
- "type" : "auditbeat",
- "version" : "8.1.0",
- "ephemeral_id" : "f6df090f-656a-4a79-a6a1-0c8671c9752d",
- "id" : "0ebd469b-c164-4734-00e6-96d018098dc7",
- "name" : "test.local"
- },
- "event" : {
- "module" : "system",
- "dataset" : "process",
- "kind" : "event",
- "category" : [
- "process"
- ],
- "type" : [
- "start"
- ],
- "action" : "process_started"
- },
- "destination": {
- "port": 80
- },
- "process" : {
- "start" : "2022-03-04T19:41:32.902Z",
- "pid" : 30884,
- "working_directory" : "/Users/test/security_solution",
- "hash" : {
- "sha1" : "ae2d46c38fa207efbea5fcecd6294eebbf5af00f"
- },
- "parent" : {
- "pid" : 777
- },
- "executable" : "/bin/zsh",
- "name" : "zsh",
- "args" : [
- "-zsh"
- ],
- "entity_id" : "q6pltOhTWlQx3BCD",
- "entry_leader": {
- "entity_id": "q6pltOhTWlQx3BCD",
- "name": "fake entry",
- "pid": 2342342
- }
- },
- "message" : "Process zsh (PID: 27884) by user test STARTED",
- "user" : {
- "id" : "505",
- "group" : {
- "name" : "staff",
- "id" : "20"
- },
- "effective" : {
- "id" : "505",
- "group" : {
- "id" : "20"
- }
- },
- "saved" : {
- "id" : "505",
- "group" : {
- "id" : "20"
- }
- },
- "name" : "test"
- },
- "service" : {
- "type" : "system"
- },
- "ecs" : {
- "version" : "8.0.0"
- }
- }
- }
-}
-
{
"type": "doc",
"value": {
diff --git a/x-pack/test/security_solution_cypress/es_archives/auditbeat/mappings.json b/x-pack/test/security_solution_cypress/es_archives/auditbeat_single/mappings.json
similarity index 100%
rename from x-pack/test/security_solution_cypress/es_archives/auditbeat/mappings.json
rename to x-pack/test/security_solution_cypress/es_archives/auditbeat_single/mappings.json
diff --git a/x-pack/test/security_solution_cypress/package.json b/x-pack/test/security_solution_cypress/package.json
index 67125c9c55daa..0e34d7867d37a 100644
--- a/x-pack/test/security_solution_cypress/package.json
+++ b/x-pack/test/security_solution_cypress/package.json
@@ -7,7 +7,7 @@
"scripts": {
"cypress": "NODE_OPTIONS=--openssl-legacy-provider ../../../node_modules/.bin/cypress",
"cypress:open:ess": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../plugins/security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ../../test/security_solution_cypress/cypress/cypress.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config",
- "cypress:run:ess": "yarn cypress:ess --spec './cypress/e2e/exceptions/shared_exception_lists_management/**/*.cy.ts'",
+ "cypress:run:ess": "yarn cypress:ess --spec './cypress/e2e/!(investigations|explore)/**/*.cy.ts'",
"cypress:run:cases:ess": "yarn cypress:ess --spec './cypress/e2e/explore/cases/*.cy.ts'",
"cypress:ess": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../plugins/security_solution/scripts/start_cypress_parallel run --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config",
"cypress:run:respops:ess": "yarn cypress:ess --spec './cypress/e2e/(detection_response|exceptions)/**/*.cy.ts'",
@@ -21,7 +21,7 @@
"cypress:cloud:serverless": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider NODE_TLS_REJECT_UNAUTHORIZED=0 ../../../node_modules/.bin/cypress",
"cypress:open:cloud:serverless": "yarn cypress:cloud:serverless open --config-file ./cypress/cypress_serverless.config.ts --env CLOUD_SERVERLESS=true",
"cypress:open:serverless": "yarn cypress:serverless open --config-file ../../test/security_solution_cypress/cypress/cypress_serverless.config.ts --spec './cypress/e2e/**/*.cy.ts'",
- "cypress:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/exceptions/shared_exception_lists_management/**/*.cy.ts'",
+ "cypress:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/!(investigations|explore)/**/*.cy.ts'",
"cypress:run:cloud:serverless": "yarn cypress:cloud:serverless run --config-file ./cypress/cypress_ci_serverless.config.ts --env CLOUD_SERVERLESS=true",
"cypress:investigations:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/investigations/**/*.cy.ts'",
"cypress:explore:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/explore/**/*.cy.ts'",
diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts
index 03f229f21b47a..8796dcfe93773 100644
--- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts
+++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts
@@ -72,20 +72,16 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
it("management apps from the sidenav hide the 'stack management' root from the breadcrumbs", async () => {
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:triggersActions' });
- await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Explore', 'Alerts', 'Rules']);
+ await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Alerts', 'Rules']);
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:index_management' });
- await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([
- 'Content',
- 'Index Management',
- 'Indices',
- ]);
+ await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Index Management', 'Indices']);
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:ingest_pipelines' });
- await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Content', 'Ingest Pipelines']);
+ await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Ingest Pipelines']);
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:api_keys' });
- await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Security', 'API keys']);
+ await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['API keys']);
});
it('navigate management', async () => {
diff --git a/yarn.lock b/yarn.lock
index 0d11dd72a0359..68faac71450cc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4304,6 +4304,10 @@
version "0.0.0"
uid ""
+"@kbn/error-boundary-example-plugin@link:examples/error_boundary":
+ version "0.0.0"
+ uid ""
+
"@kbn/es-archiver@link:packages/kbn-es-archiver":
version "0.0.0"
uid ""
@@ -8251,7 +8255,7 @@
resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.3.tgz#fbb68696899d7b8c1b9b891eded9c04fe2cd5529"
integrity sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A==
-"@testing-library/dom@^8.0.0", "@testing-library/dom@^8.19.0":
+"@testing-library/dom@^8.0.0":
version "8.19.0"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.19.0.tgz#bd3f83c217ebac16694329e413d9ad5fdcfd785f"
integrity sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==
@@ -20473,10 +20477,10 @@ kdbush@^4.0.2:
resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-4.0.2.tgz#2f7b7246328b4657dd122b6c7f025fbc2c868e39"
integrity sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==
-kea@^2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/kea/-/kea-2.4.2.tgz#53af42702f2c8962422e456e5dd943391bad26e9"
- integrity sha512-cdGds/gsJsbo/KbVAMk5/tTr229eDibVT1wmPPxPO/10zYb8GFoP3udBIQb+Hop5qGEu2wIHVdXwJvXqSS8JAg==
+kea@^2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/kea/-/kea-2.6.0.tgz#774a82188e0fb52cdb18b72843a875ee857f3807"
+ integrity sha512-+yaLyZx8h2v96aL01XIRZjqA8Qk4fIUziznSKnkjDItUU8YnH75xER6+vMHT5EHC3MJeSScxIx5UuqZl30DBdg==
keyv@^3.0.0:
version "3.0.0"