)}
-
+
|
{isCollapsible && (
diff --git a/src/legacy/core_plugins/kibana/public/management/landing.html b/src/legacy/core_plugins/kibana/public/management/landing.html
index a69033e4131c9..39459b26f7415 100644
--- a/src/legacy/core_plugins/kibana/public/management/landing.html
+++ b/src/legacy/core_plugins/kibana/public/management/landing.html
@@ -1,3 +1,3 @@
-
+
diff --git a/src/legacy/ui/public/agg_types/param_types/field.ts b/src/legacy/ui/public/agg_types/param_types/field.ts
index 0ca60267becec..a0fa6ad6e3189 100644
--- a/src/legacy/ui/public/agg_types/param_types/field.ts
+++ b/src/legacy/ui/public/agg_types/param_types/field.ts
@@ -115,7 +115,10 @@ export class FieldParamType extends BaseParamType {
const filteredFields = fields.filter((field: Field) => {
const { onlyAggregatable, scriptable, filterFieldTypes } = this;
- if ((onlyAggregatable && !field.aggregatable) || (!scriptable && field.scripted)) {
+ if (
+ (onlyAggregatable && (!field.aggregatable || field.subType?.nested)) ||
+ (!scriptable && field.scripted)
+ ) {
return false;
}
diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js
index 3ec903d5b18e4..8ddd18c2c67f4 100644
--- a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js
+++ b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.test.js
@@ -37,7 +37,7 @@ describe('index_patterns/field_capabilities/field_caps_response', () => {
describe('conflicts', () => {
it('returns a field for each in response, no filtering', () => {
const fields = readFieldCapsResponse(esResponse);
- expect(fields).toHaveLength(25);
+ expect(fields).toHaveLength(24);
});
it(
@@ -68,8 +68,8 @@ describe('index_patterns/field_capabilities/field_caps_response', () => {
sandbox.spy(shouldReadFieldFromDocValuesNS, 'shouldReadFieldFromDocValues');
const fields = readFieldCapsResponse(esResponse);
const conflictCount = fields.filter(f => f.type === 'conflict').length;
- // +1 is for the object field which is filtered out of the final return value from readFieldCapsResponse
- sinon.assert.callCount(shouldReadFieldFromDocValues, fields.length - conflictCount + 1);
+ // +2 is for the object and nested fields which get filtered out of the final return value from readFieldCapsResponse
+ sinon.assert.callCount(shouldReadFieldFromDocValues, fields.length - conflictCount + 2);
});
it('converts es types to kibana types', () => {
@@ -143,13 +143,6 @@ describe('index_patterns/field_capabilities/field_caps_response', () => {
expect(child).toHaveProperty('subType', { nested: { path: 'nested_object_parent' } });
});
- it('returns nested sub-fields as non-aggregatable', () => {
- const fields = readFieldCapsResponse(esResponse);
- // Normally a keyword field would be aggregatable, but the fact that it is nested overrides that
- const child = fields.find(f => f.name === 'nested_object_parent.child.keyword');
- expect(child).toHaveProperty('aggregatable', false);
- });
-
it('handles fields that are both nested and multi', () => {
const fields = readFieldCapsResponse(esResponse);
const child = fields.find(f => f.name === 'nested_object_parent.child.keyword');
@@ -159,12 +152,10 @@ describe('index_patterns/field_capabilities/field_caps_response', () => {
});
});
- it('returns the nested parent as not searchable or aggregatable', () => {
+ it('does not include the field actually mapped as nested itself', () => {
const fields = readFieldCapsResponse(esResponse);
const child = fields.find(f => f.name === 'nested_object_parent');
- expect(child.type).toBe('nested');
- expect(child.aggregatable).toBe(false);
- expect(child.searchable).toBe(false);
+ expect(child).toBeUndefined();
});
it('should not confuse object children for multi or nested field children', () => {
diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts
index 0c8c2ce48fa84..06eb30db0b24b 100644
--- a/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts
+++ b/src/plugins/data/server/index_patterns/fetcher/lib/field_capabilities/field_caps_response.ts
@@ -182,19 +182,11 @@ export function readFieldCapsResponse(fieldCapsResponse: FieldCapsResponse): Fie
if (Object.keys(subType).length > 0) {
field.subType = subType;
-
- // We don't support aggregating on nested fields, trying to do so in the UI will return
- // blank results. For now we will stop showing nested fields as an option for aggregation.
- // Once we add support for nested fields this condition should be removed and old index
- // patterns should be migrated.
- if (field.subType.nested) {
- field.aggregatable = false;
- }
}
}
});
return kibanaFormattedCaps.filter(field => {
- return !['object'].includes(field.type);
+ return !['object', 'nested'].includes(field.type);
});
}
diff --git a/src/plugins/kibana_react/public/field_icon/field_icon.tsx b/src/plugins/kibana_react/public/field_icon/field_icon.tsx
index 7c44fe89d0e7f..2e199a7471a64 100644
--- a/src/plugins/kibana_react/public/field_icon/field_icon.tsx
+++ b/src/plugins/kibana_react/public/field_icon/field_icon.tsx
@@ -36,8 +36,8 @@ interface FieldIconProps {
| 'number'
| '_source'
| 'string'
- | 'nested'
- | string;
+ | string
+ | 'nested';
label?: string;
size?: IconSize;
useColor?: boolean;
diff --git a/src/plugins/management/public/management_app.tsx b/src/plugins/management/public/management_app.tsx
index f7e8dba4f8210..705d98eaaf2ff 100644
--- a/src/plugins/management/public/management_app.tsx
+++ b/src/plugins/management/public/management_app.tsx
@@ -34,7 +34,7 @@ export class ManagementApp {
readonly basePath: string;
readonly order: number;
readonly mount: ManagementSectionMount;
- protected enabledStatus: boolean = true;
+ private enabledStatus = true;
constructor(
{ id, title, basePath, order = 100, mount }: CreateManagementApp,
@@ -54,6 +54,11 @@ export class ManagementApp {
title,
mount: async ({}, params) => {
let appUnmount: Unmount;
+ if (!this.enabledStatus) {
+ const [coreStart] = await getStartServices();
+ coreStart.application.navigateToApp('kibana#/management');
+ return () => {};
+ }
async function setBreadcrumbs(crumbs: ChromeBreadcrumb[]) {
const [coreStart] = await getStartServices();
coreStart.chrome.setBreadcrumbs([
diff --git a/test/api_integration/apis/index_patterns/fields_for_wildcard_route/response.js b/test/api_integration/apis/index_patterns/fields_for_wildcard_route/response.js
index 555056173ec62..c4c71abdae125 100644
--- a/test/api_integration/apis/index_patterns/fields_for_wildcard_route/response.js
+++ b/test/api_integration/apis/index_patterns/fields_for_wildcard_route/response.js
@@ -72,15 +72,7 @@ export default function({ getService }) {
readFromDocValues: true,
},
{
- aggregatable: false,
- esTypes: ['nested'],
- name: 'nestedField',
- readFromDocValues: false,
- searchable: false,
- type: 'nested',
- },
- {
- aggregatable: false,
+ aggregatable: true,
esTypes: ['keyword'],
name: 'nestedField.child',
readFromDocValues: true,
@@ -162,15 +154,7 @@ export default function({ getService }) {
readFromDocValues: true,
},
{
- aggregatable: false,
- esTypes: ['nested'],
- name: 'nestedField',
- readFromDocValues: false,
- searchable: false,
- type: 'nested',
- },
- {
- aggregatable: false,
+ aggregatable: true,
esTypes: ['keyword'],
name: 'nestedField.child',
readFromDocValues: true,
diff --git a/test/plugin_functional/plugins/management_test_plugin/public/plugin.tsx b/test/plugin_functional/plugins/management_test_plugin/public/plugin.tsx
index 8b7cdd653ed8c..f3b7a19f70ae3 100644
--- a/test/plugin_functional/plugins/management_test_plugin/public/plugin.tsx
+++ b/test/plugin_functional/plugins/management_test_plugin/public/plugin.tsx
@@ -62,6 +62,22 @@ export class ManagementTestPlugin
};
},
});
+
+ testSection!
+ .registerApp({
+ id: 'test-management-disabled',
+ title: 'Management Test Disabled',
+ mount(params) {
+ params.setBreadcrumbs([{ text: 'Management Test Disabled' }]);
+ ReactDOM.render( This is a secret that should never be seen! , params.element);
+
+ return () => {
+ ReactDOM.unmountComponentAtNode(params.element);
+ };
+ },
+ })
+ .disable();
+
return {};
}
diff --git a/test/plugin_functional/test_suites/management/management_plugin.js b/test/plugin_functional/test_suites/management/management_plugin.js
index d65fb1dcd3a7e..0c185f4b385b5 100644
--- a/test/plugin_functional/test_suites/management/management_plugin.js
+++ b/test/plugin_functional/test_suites/management/management_plugin.js
@@ -36,5 +36,13 @@ export default function({ getService, getPageObjects }) {
await testSubjects.click('test-management-link-basepath');
await testSubjects.existOrFail('test-management-link-one');
});
+
+ it('should redirect when app is disabled', async () => {
+ await PageObjects.common.navigateToActualUrl(
+ 'kibana',
+ 'management/test-section/test-management-disabled'
+ );
+ await testSubjects.existOrFail('management-landing');
+ });
});
}
diff --git a/x-pack/legacy/plugins/reporting/index.ts b/x-pack/legacy/plugins/reporting/index.ts
index 82d94422b70ce..52e26b3132007 100644
--- a/x-pack/legacy/plugins/reporting/index.ts
+++ b/x-pack/legacy/plugins/reporting/index.ts
@@ -7,47 +7,20 @@
import { resolve } from 'path';
import { i18n } from '@kbn/i18n';
import { Legacy } from 'kibana';
-import { IUiSettingsClient } from 'src/core/server';
-import { XPackMainPlugin } from '../xpack_main/server/xpack_main';
import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from './common/constants';
-// @ts-ignore untyped module defintition
-import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status';
-import { registerRoutes } from './server/routes';
-import {
- LevelLogger,
- checkLicenseFactory,
- getExportTypesRegistry,
- runValidations,
-} from './server/lib';
-import { createBrowserDriverFactory } from './server/browsers';
-import { registerReportingUsageCollector } from './server/usage';
import { ReportingConfigOptions, ReportingPluginSpecOptions } from './types.d';
import { config as reportingConfig } from './config';
-import { logConfiguration } from './log_configuration';
+import {
+ LegacySetup,
+ ReportingPlugin,
+ ReportingSetupDeps,
+ reportingPluginFactory,
+} from './server/plugin';
const kbToBase64Length = (kb: number) => {
return Math.floor((kb * 1024 * 8) / 6);
};
-type LegacyPlugins = Legacy.Server['plugins'];
-
-export interface ServerFacade {
- config: Legacy.Server['config'];
- info: Legacy.Server['info'];
- log: Legacy.Server['log'];
- plugins: {
- elasticsearch: LegacyPlugins['elasticsearch'];
- security: LegacyPlugins['security'];
- xpack_main: XPackMainPlugin & {
- status?: any;
- };
- };
- route: Legacy.Server['route'];
- savedObjects: Legacy.Server['savedObjects'];
- uiSettingsServiceFactory: Legacy.Server['uiSettingsServiceFactory'];
- fieldFormatServiceFactory: (uiConfig: IUiSettingsClient) => unknown;
-}
-
export const reporting = (kibana: any) => {
return new kibana.Plugin({
id: PLUGIN_ID,
@@ -93,7 +66,11 @@ export const reporting = (kibana: any) => {
},
async init(server: Legacy.Server) {
- const serverFacade: ServerFacade = {
+ const coreSetup = server.newPlatform.setup.core;
+ const pluginsSetup: ReportingSetupDeps = {
+ usageCollection: server.newPlatform.setup.plugins.usageCollection,
+ };
+ const __LEGACY: LegacySetup = {
config: server.config,
info: server.info,
route: server.route.bind(server),
@@ -108,38 +85,9 @@ export const reporting = (kibana: any) => {
fieldFormatServiceFactory: server.fieldFormatServiceFactory,
log: server.log.bind(server),
};
- const exportTypesRegistry = getExportTypesRegistry();
-
- let isCollectorReady = false;
- // Register a function with server to manage the collection of usage stats
- const { usageCollection } = server.newPlatform.setup.plugins;
- registerReportingUsageCollector(
- usageCollection,
- serverFacade,
- () => isCollectorReady,
- exportTypesRegistry
- );
-
- const logger = LevelLogger.createForServer(serverFacade, [PLUGIN_ID]);
- const browserDriverFactory = await createBrowserDriverFactory(serverFacade);
-
- logConfiguration(serverFacade, logger);
- runValidations(serverFacade, logger, browserDriverFactory);
-
- const { xpack_main: xpackMainPlugin } = serverFacade.plugins;
- mirrorPluginStatus(xpackMainPlugin, this);
- const checkLicense = checkLicenseFactory(exportTypesRegistry);
- (xpackMainPlugin as any).status.once('green', () => {
- // Register a function that is called whenever the xpack info changes,
- // to re-compute the license check results for this plugin
- xpackMainPlugin.info.feature(this.id).registerLicenseCheckResultsGenerator(checkLicense);
- });
-
- // Post initialization of the above code, the collector is now ready to fetch its data
- isCollectorReady = true;
- // Reporting routes
- registerRoutes(serverFacade, exportTypesRegistry, browserDriverFactory, logger);
+ const plugin: ReportingPlugin = reportingPluginFactory(__LEGACY, this);
+ await plugin.setup(coreSetup, pluginsSetup);
},
deprecations({ unused }: any) {
diff --git a/x-pack/legacy/plugins/reporting/server/plugin.ts b/x-pack/legacy/plugins/reporting/server/plugin.ts
new file mode 100644
index 0000000000000..934a3487209c4
--- /dev/null
+++ b/x-pack/legacy/plugins/reporting/server/plugin.ts
@@ -0,0 +1,107 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { Legacy } from 'kibana';
+import { CoreSetup, CoreStart, Plugin } from 'src/core/server';
+import { IUiSettingsClient } from 'src/core/server';
+import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
+import { XPackMainPlugin } from '../../xpack_main/server/xpack_main';
+// @ts-ignore
+import { mirrorPluginStatus } from '../../../server/lib/mirror_plugin_status';
+import { PLUGIN_ID } from '../common/constants';
+import { ReportingPluginSpecOptions } from '../types.d';
+import { registerRoutes } from './routes';
+import { LevelLogger, checkLicenseFactory, getExportTypesRegistry, runValidations } from './lib';
+import { createBrowserDriverFactory } from './browsers';
+import { registerReportingUsageCollector } from './usage';
+import { logConfiguration } from '../log_configuration';
+
+// For now there is no exposed functionality to other plugins
+export type ReportingSetup = object;
+export type ReportingStart = object;
+
+export interface ReportingSetupDeps {
+ usageCollection: UsageCollectionSetup;
+}
+export type ReportingStartDeps = object;
+
+type LegacyPlugins = Legacy.Server['plugins'];
+
+export interface LegacySetup {
+ config: Legacy.Server['config'];
+ info: Legacy.Server['info'];
+ log: Legacy.Server['log'];
+ plugins: {
+ elasticsearch: LegacyPlugins['elasticsearch'];
+ security: LegacyPlugins['security'];
+ xpack_main: XPackMainPlugin & {
+ status?: any;
+ };
+ };
+ route: Legacy.Server['route'];
+ savedObjects: Legacy.Server['savedObjects'];
+ uiSettingsServiceFactory: Legacy.Server['uiSettingsServiceFactory'];
+ fieldFormatServiceFactory: (uiConfig: IUiSettingsClient) => unknown;
+}
+
+export type ReportingPlugin = Plugin<
+ ReportingSetup,
+ ReportingStart,
+ ReportingSetupDeps,
+ ReportingStartDeps
+>;
+
+/* We need a factory that returns an instance of the class because the class
+ * implementation itself restricts against having Legacy dependencies passed
+ * into `setup`. The factory parameters take the legacy dependencies, and the
+ * `setup` method gets it from enclosure */
+export function reportingPluginFactory(
+ __LEGACY: LegacySetup,
+ legacyPlugin: ReportingPluginSpecOptions
+) {
+ return new (class ReportingPlugin implements ReportingPlugin {
+ public async setup(core: CoreSetup, plugins: ReportingSetupDeps): Promise {
+ const exportTypesRegistry = getExportTypesRegistry();
+
+ let isCollectorReady = false;
+ // Register a function with server to manage the collection of usage stats
+ const { usageCollection } = plugins;
+ registerReportingUsageCollector(
+ usageCollection,
+ __LEGACY,
+ () => isCollectorReady,
+ exportTypesRegistry
+ );
+
+ const logger = LevelLogger.createForServer(__LEGACY, [PLUGIN_ID]);
+ const browserDriverFactory = await createBrowserDriverFactory(__LEGACY);
+
+ logConfiguration(__LEGACY, logger);
+ runValidations(__LEGACY, logger, browserDriverFactory);
+
+ const { xpack_main: xpackMainPlugin } = __LEGACY.plugins;
+ mirrorPluginStatus(xpackMainPlugin, legacyPlugin);
+ const checkLicense = checkLicenseFactory(exportTypesRegistry);
+ (xpackMainPlugin as any).status.once('green', () => {
+ // Register a function that is called whenever the xpack info changes,
+ // to re-compute the license check results for this plugin
+ xpackMainPlugin.info.feature(PLUGIN_ID).registerLicenseCheckResultsGenerator(checkLicense);
+ });
+
+ // Post initialization of the above code, the collector is now ready to fetch its data
+ isCollectorReady = true;
+
+ // Reporting routes
+ registerRoutes(__LEGACY, exportTypesRegistry, browserDriverFactory, logger);
+
+ return {};
+ }
+
+ public start(core: CoreStart, plugins: ReportingStartDeps): ReportingStart {
+ return {};
+ }
+ })();
+}
diff --git a/x-pack/legacy/plugins/reporting/types.d.ts b/x-pack/legacy/plugins/reporting/types.d.ts
index f67f44860f14a..9fae60afee4e8 100644
--- a/x-pack/legacy/plugins/reporting/types.d.ts
+++ b/x-pack/legacy/plugins/reporting/types.d.ts
@@ -15,7 +15,7 @@ import { CancellationToken } from './common/cancellation_token';
import { LevelLogger } from './server/lib/level_logger';
import { HeadlessChromiumDriverFactory } from './server/browsers/chromium/driver_factory';
import { BrowserType } from './server/browsers/types';
-import { ServerFacade } from './index';
+import { LegacySetup } from './server/plugin';
export type ReportingPlugin = object; // For Plugin contract
@@ -69,6 +69,8 @@ interface GenerateExportTypePayload {
* Legacy System
*/
+export type ServerFacade = LegacySetup;
+
export type ReportingPluginSpecOptions = Legacy.PluginSpecOptions;
export type EnqueueJobFn = (
@@ -353,5 +355,3 @@ export interface InterceptedRequest {
frameId: string;
resourceType: string;
}
-
-export { ServerFacade };
diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx
index 87d83f7f2972c..0b99a8b059df7 100644
--- a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/index.tsx
@@ -16,11 +16,11 @@ import { MatrixHistogramGqlQuery } from '../../containers/matrix_histogram/index
const ID = 'alertsOverTimeQuery';
export const alertsStackByOptions: MatrixHistogramOption[] = [
{
- text: i18n.CATEGORY,
+ text: 'event.category',
value: 'event.category',
},
{
- text: i18n.MODULE,
+ text: 'event.module',
value: 'event.module',
},
];
@@ -54,7 +54,6 @@ export const AlertsView = ({
<>
diff --git a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts
index 8c6248e38c057..408c406a854be 100644
--- a/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/components/alerts_viewer/translations.ts
@@ -14,10 +14,14 @@ export const TOTAL_COUNT_OF_ALERTS = i18n.translate('xpack.siem.alertsView.total
defaultMessage: 'alerts match the search criteria',
});
-export const ALERTS_TABLE_TITLE = i18n.translate('xpack.siem.alertsView.alertsDocumentType', {
+export const ALERTS_TABLE_TITLE = i18n.translate('xpack.siem.alertsView.alertsTableTitle', {
defaultMessage: 'Alerts',
});
+export const ALERTS_GRAPH_TITLE = i18n.translate('xpack.siem.alertsView.alertsGraphTitle', {
+ defaultMessage: 'Alert detection frequency',
+});
+
export const ALERTS_STACK_BY_MODULE = i18n.translate(
'xpack.siem.alertsView.alertsStackByOptions.module',
{
diff --git a/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx b/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx
index db6ff7cf55f92..5a286532fabfc 100644
--- a/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/header_global/index.tsx
@@ -55,7 +55,7 @@ export const HeaderGlobal = React.memo(({ hideDetectionEngine
display="condensed"
navTabs={
hideDetectionEngine
- ? pickBy((_, key) => key !== SiemPageName.detectionEngine, navTabs)
+ ? pickBy((_, key) => key !== SiemPageName.detections, navTabs)
: navTabs
}
/>
diff --git a/x-pack/legacy/plugins/siem/public/components/link_to/link_to.tsx b/x-pack/legacy/plugins/siem/public/components/link_to/link_to.tsx
index 7c15af3fe642a..3180fc955c690 100644
--- a/x-pack/legacy/plugins/siem/public/components/link_to/link_to.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/link_to/link_to.tsx
@@ -20,6 +20,7 @@ import { RedirectToHostsPage, RedirectToHostDetailsPage } from './redirect_to_ho
import { RedirectToNetworkPage } from './redirect_to_network';
import { RedirectToOverviewPage } from './redirect_to_overview';
import { RedirectToTimelinesPage } from './redirect_to_timelines';
+import { DetectionEngineTab } from '../../pages/detection_engine/types';
interface LinkToPageProps {
match: RouteMatch<{}>;
@@ -60,26 +61,32 @@ export const LinkToPage = React.memo(({ match }) => (
+
;
-export const DETECTION_ENGINE_PAGE_NAME = 'detection-engine';
+export const DETECTION_ENGINE_PAGE_NAME = 'detections';
export const RedirectToDetectionEnginePage = ({
+ match: {
+ params: { tabName },
+ },
location: { search },
-}: DetectionEngineComponentProps) => (
-
-);
+}: DetectionEngineComponentProps) => {
+ const defaultSelectedTab = DetectionEngineTab.signals;
+ const selectedTab = tabName ? tabName : defaultSelectedTab;
+ const to = `/${DETECTION_ENGINE_PAGE_NAME}/${selectedTab}${search}`;
+
+ return ;
+};
export const RedirectToRulesPage = ({ location: { search } }: DetectionEngineComponentProps) => {
return ;
@@ -28,7 +37,7 @@ export const RedirectToRulesPage = ({ location: { search } }: DetectionEngineCom
export const RedirectToCreateRulePage = ({
location: { search },
}: DetectionEngineComponentProps) => {
- return ;
+ return ;
};
export const RedirectToRuleDetailsPage = ({
@@ -44,6 +53,8 @@ export const RedirectToEditRulePage = ({ location: { search } }: DetectionEngine
};
export const getDetectionEngineUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}`;
+export const getDetectionEngineAlertUrl = () =>
+ `#/link-to/${DETECTION_ENGINE_PAGE_NAME}/${DetectionEngineTab.alerts}`;
export const getRulesUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}/rules`;
export const getCreateRuleUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}/rules/create-rule`;
export const getRuleDetailsUrl = () => `#/link-to/${DETECTION_ENGINE_PAGE_NAME}/rules/rule-details`;
diff --git a/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx b/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx
index 56ebbb06f3eb9..cdd62c430a50c 100644
--- a/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/matrix_histogram/index.tsx
@@ -46,12 +46,12 @@ export const MatrixHistogramComponent: React.FC {
expect(setBreadcrumbs).toHaveBeenNthCalledWith(1, {
detailName: undefined,
navTabs: {
- 'detection-engine': {
+ detections: {
disabled: false,
- href: '#/link-to/detection-engine',
- id: 'detection-engine',
- name: 'Detection engine',
- urlKey: 'detection-engine',
+ href: '#/link-to/detections',
+ id: 'detections',
+ name: 'Detections',
+ urlKey: 'detections',
},
hosts: {
disabled: false,
@@ -146,12 +146,12 @@ describe('SIEM Navigation', () => {
detailName: undefined,
filters: [],
navTabs: {
- 'detection-engine': {
+ detections: {
disabled: false,
- href: '#/link-to/detection-engine',
- id: 'detection-engine',
- name: 'Detection engine',
- urlKey: 'detection-engine',
+ href: '#/link-to/detections',
+ id: 'detections',
+ name: 'Detections',
+ urlKey: 'detections',
},
hosts: {
disabled: false,
diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/search_super_select/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/search_super_select/index.tsx
index c7259edbdc593..009ab141e958e 100644
--- a/x-pack/legacy/plugins/siem/public/components/timeline/search_super_select/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/timeline/search_super_select/index.tsx
@@ -45,11 +45,25 @@ const MyEuiFlexItem = styled(EuiFlexItem)`
white-space: nowrap;
`;
-const EuiSelectableContainer = styled.div`
+const EuiSelectableContainer = styled.div<{ loading: boolean }>`
.euiSelectable {
.euiFormControlLayout__childrenWrapper {
display: flex;
}
+ ${({ loading }) => `${
+ loading
+ ? `
+ .euiFormControlLayoutIcons {
+ display: none;
+ }
+ .euiFormControlLayoutIcons.euiFormControlLayoutIcons--right {
+ display: block;
+ left: 12px;
+ top: 12px;
+ }`
+ : ''
+ }
+ `}
}
`;
@@ -265,7 +279,7 @@ const SearchTimelineSuperSelectComponent: React.FC
{({ timelines, loading, totalCount }) => (
-
+
{
- describe('isKqlForRoute', () => {
- test('host page and host page kuery', () => {
- const result = isKqlForRoute(SiemPageName.hosts, undefined, CONSTANTS.hostsPage);
- expect(result).toBeTruthy();
- });
- test('host page and host details kuery', () => {
- const result = isKqlForRoute(SiemPageName.hosts, undefined, CONSTANTS.hostsDetails);
- expect(result).toBeFalsy();
- });
- test('host details and host details kuery', () => {
- const result = isKqlForRoute(SiemPageName.hosts, 'siem-kibana', CONSTANTS.hostsDetails);
- expect(result).toBeTruthy();
- });
- test('host details and host page kuery', () => {
- const result = isKqlForRoute(SiemPageName.hosts, 'siem-kibana', CONSTANTS.hostsPage);
- expect(result).toBeFalsy();
- });
- test('network page and network page kuery', () => {
- const result = isKqlForRoute(SiemPageName.network, undefined, CONSTANTS.networkPage);
- expect(result).toBeTruthy();
- });
- test('network page and network details kuery', () => {
- const result = isKqlForRoute(SiemPageName.network, undefined, CONSTANTS.networkDetails);
- expect(result).toBeFalsy();
- });
- test('network details and network details kuery', () => {
- const result = isKqlForRoute(SiemPageName.network, '10.100.7.198', CONSTANTS.networkDetails);
- expect(result).toBeTruthy();
- });
- test('network details and network page kuery', () => {
- const result = isKqlForRoute(SiemPageName.network, '123.234.34', CONSTANTS.networkPage);
- expect(result).toBeFalsy();
- });
- });
describe('getTitle', () => {
test('host page name', () => {
const result = getTitle('hosts', undefined, navTabs);
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts b/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts
index aa340b54c1699..6ba5810f794b0 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/helpers.ts
@@ -78,8 +78,8 @@ export const getUrlType = (pageName: string): UrlStateType => {
return 'host';
} else if (pageName === SiemPageName.network) {
return 'network';
- } else if (pageName === SiemPageName.detectionEngine) {
- return 'detection-engine';
+ } else if (pageName === SiemPageName.detections) {
+ return 'detections';
} else if (pageName === SiemPageName.timelines) {
return 'timeline';
}
@@ -111,31 +111,14 @@ export const getCurrentLocation = (
return CONSTANTS.networkDetails;
}
return CONSTANTS.networkPage;
- } else if (pageName === SiemPageName.detectionEngine) {
- return CONSTANTS.detectionEnginePage;
+ } else if (pageName === SiemPageName.detections) {
+ return CONSTANTS.detectionsPage;
} else if (pageName === SiemPageName.timelines) {
return CONSTANTS.timelinePage;
}
return CONSTANTS.unknown;
};
-export const isKqlForRoute = (
- pageName: string,
- detailName: string | undefined,
- queryLocation: LocationTypes | null = null
-): boolean => {
- const currentLocation = getCurrentLocation(pageName, detailName);
- if (
- (currentLocation === CONSTANTS.hostsPage && queryLocation === CONSTANTS.hostsPage) ||
- (currentLocation === CONSTANTS.networkPage && queryLocation === CONSTANTS.networkPage) ||
- (currentLocation === CONSTANTS.hostsDetails && queryLocation === CONSTANTS.hostsDetails) ||
- (currentLocation === CONSTANTS.networkDetails && queryLocation === CONSTANTS.networkDetails)
- ) {
- return true;
- }
- return false;
-};
-
export const makeMapStateToProps = () => {
const getInputsSelector = inputsSelectors.inputsSelector();
const getGlobalQuerySelector = inputsSelectors.globalQuerySelector();
diff --git a/x-pack/legacy/plugins/siem/public/components/url_state/types.ts b/x-pack/legacy/plugins/siem/public/components/url_state/types.ts
index a48653a7ea6f4..be1ae1ad63bd4 100644
--- a/x-pack/legacy/plugins/siem/public/components/url_state/types.ts
+++ b/x-pack/legacy/plugins/siem/public/components/url_state/types.ts
@@ -24,7 +24,7 @@ export const ALL_URL_STATE_KEYS: KeyUrlState[] = [
];
export const URL_STATE_KEYS: Record = {
- 'detection-engine': [
+ detections: [
CONSTANTS.appQuery,
CONSTANTS.filters,
CONSTANTS.savedQuery,
@@ -56,7 +56,7 @@ export const URL_STATE_KEYS: Record = {
};
export type LocationTypes =
- | CONSTANTS.detectionEnginePage
+ | CONSTANTS.detectionsPage
| CONSTANTS.hostsDetails
| CONSTANTS.hostsPage
| CONSTANTS.networkDetails
diff --git a/x-pack/legacy/plugins/siem/public/containers/anomalies/anomalies_query_tab_body/index.tsx b/x-pack/legacy/plugins/siem/public/containers/anomalies/anomalies_query_tab_body/index.tsx
index f691219e446a8..2d9ac8b7645ca 100644
--- a/x-pack/legacy/plugins/siem/public/containers/anomalies/anomalies_query_tab_body/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/anomalies/anomalies_query_tab_body/index.tsx
@@ -39,6 +39,14 @@ export const AnomaliesQueryTabBody = ({
flowTarget,
ip,
}: AnomaliesQueryTabBodyProps) => {
+ useEffect(() => {
+ return () => {
+ if (deleteQuery) {
+ deleteQuery({ id: ID });
+ }
+ };
+ }, []);
+
const [, siemJobs] = useSiemJobs(true);
const [anomalyScore] = useUiSetting$(DEFAULT_ANOMALY_SCORE);
@@ -51,21 +59,12 @@ export const AnomaliesQueryTabBody = ({
ip
);
- useEffect(() => {
- return () => {
- if (deleteQuery) {
- deleteQuery({ id: ID });
- }
- };
- }, []);
-
return (
<>
=> {
- const requests = rules.map(rule =>
- fetch(`${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}`, {
+ const response = await fetch(
+ `${chrome.getBasePath()}${DETECTION_ENGINE_RULES_URL}/_bulk_create`,
+ {
method: 'POST',
credentials: 'same-origin',
headers: {
'content-type': 'application/json',
'kbn-xsrf': 'true',
},
- body: JSON.stringify({
- ...rule,
- name: `${rule.name} [${i18n.DUPLICATE}]`,
- created_at: undefined,
- created_by: undefined,
- id: undefined,
- rule_id: undefined,
- updated_at: undefined,
- updated_by: undefined,
- enabled: rule.enabled,
- immutable: false,
- last_success_at: undefined,
- last_success_message: undefined,
- status: undefined,
- status_date: undefined,
- }),
- })
+ body: JSON.stringify(
+ rules.map(rule => ({
+ ...rule,
+ name: `${rule.name} [${i18n.DUPLICATE}]`,
+ created_at: undefined,
+ created_by: undefined,
+ id: undefined,
+ rule_id: undefined,
+ updated_at: undefined,
+ updated_by: undefined,
+ enabled: rule.enabled,
+ immutable: undefined,
+ last_success_at: undefined,
+ last_success_message: undefined,
+ status: undefined,
+ status_date: undefined,
+ }))
+ ),
+ }
);
- const responses = await Promise.all(requests);
- await responses.map(response => throwIfNotOk(response));
- return Promise.all(
- responses.map>(response => response.json())
- );
+ await throwIfNotOk(response);
+ return response.json();
};
/**
@@ -322,7 +322,7 @@ export const getRuleStatusById = async ({
}: {
id: string;
signal: AbortSignal;
-}): Promise> => {
+}): Promise> => {
const response = await fetch(
`${chrome.getBasePath()}${DETECTION_ENGINE_RULES_STATUS}?ids=${encodeURIComponent(
JSON.stringify([id])
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/index.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/index.ts
index a61cbabd80626..e9a0f27b34696 100644
--- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/index.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/index.ts
@@ -10,3 +10,4 @@ export * from './persist_rule';
export * from './types';
export * from './use_rule';
export * from './use_rules';
+export * from './use_rule_status';
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts
index feef888c0d47f..0dcd0da5be8f6 100644
--- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/types.ts
@@ -146,7 +146,7 @@ export interface DeleteRulesProps {
}
export interface DuplicateRulesProps {
- rules: Rules;
+ rules: Rule[];
}
export interface BasicFetchProps {
@@ -181,9 +181,15 @@ export interface ExportRulesProps {
}
export interface RuleStatus {
+ current_status: RuleInfoStatus;
+ failures: RuleInfoStatus[];
+}
+
+export type RuleStatusType = 'executing' | 'failed' | 'going to run' | 'succeeded';
+export interface RuleInfoStatus {
alert_id: string;
status_date: string;
- status: string;
+ status: RuleStatusType | null;
last_failure_at: string | null;
last_success_at: string | null;
last_failure_message: string | null;
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_create_packaged_rules.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_create_packaged_rules.tsx
new file mode 100644
index 0000000000000..592419f879011
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_create_packaged_rules.tsx
@@ -0,0 +1,81 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { useEffect, useState } from 'react';
+
+import { createPrepackagedRules } from './api';
+
+type Return = [boolean, boolean | null];
+
+interface UseCreatePackagedRules {
+ canUserCRUD: boolean | null;
+ hasIndexManage: boolean | null;
+ hasManageApiKey: boolean | null;
+ isAuthenticated: boolean | null;
+ isSignalIndexExists: boolean | null;
+}
+
+/**
+ * Hook for creating the packages rules
+ *
+ * @param canUserCRUD boolean
+ * @param hasIndexManage boolean
+ * @param hasManageApiKey boolean
+ * @param isAuthenticated boolean
+ * @param isSignalIndexExists boolean
+ *
+ * @returns [loading, hasCreatedPackageRules]
+ */
+export const useCreatePackagedRules = ({
+ canUserCRUD,
+ hasIndexManage,
+ hasManageApiKey,
+ isAuthenticated,
+ isSignalIndexExists,
+}: UseCreatePackagedRules): Return => {
+ const [hasCreatedPackageRules, setHasCreatedPackageRules] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ let isSubscribed = true;
+ const abortCtrl = new AbortController();
+ setLoading(true);
+
+ async function createRules() {
+ try {
+ await createPrepackagedRules({
+ signal: abortCtrl.signal,
+ });
+
+ if (isSubscribed) {
+ setHasCreatedPackageRules(true);
+ }
+ } catch (error) {
+ if (isSubscribed) {
+ setHasCreatedPackageRules(false);
+ }
+ }
+ if (isSubscribed) {
+ setLoading(false);
+ }
+ }
+ if (
+ canUserCRUD &&
+ hasIndexManage &&
+ hasManageApiKey &&
+ isAuthenticated &&
+ isSignalIndexExists
+ ) {
+ createRules();
+ }
+ return () => {
+ isSubscribed = false;
+ abortCtrl.abort();
+ };
+ }, [canUserCRUD, hasIndexManage, hasManageApiKey, isAuthenticated, isSignalIndexExists]);
+
+ return [loading, hasCreatedPackageRules];
+};
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rule_status.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rule_status.tsx
index 216fbcea861a3..466c2cddac97d 100644
--- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rule_status.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/rules/use_rule_status.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { useStateToaster } from '../../../components/toasters';
import { errorToToaster } from '../../../components/ml/api/error_to_toaster';
@@ -12,7 +12,8 @@ import { getRuleStatusById } from './api';
import * as i18n from './translations';
import { RuleStatus } from './types';
-type Return = [boolean, RuleStatus[] | null];
+type Func = (ruleId: string) => void;
+type Return = [boolean, RuleStatus | null, Func | null];
/**
* Hook for using to get a Rule from the Detection Engine API
@@ -21,7 +22,8 @@ type Return = [boolean, RuleStatus[] | null];
*
*/
export const useRuleStatus = (id: string | undefined | null): Return => {
- const [ruleStatus, setRuleStatus] = useState(null);
+ const [ruleStatus, setRuleStatus] = useState(null);
+ const fetchRuleStatus = useRef(null);
const [loading, setLoading] = useState(true);
const [, dispatchToaster] = useStateToaster();
@@ -29,7 +31,7 @@ export const useRuleStatus = (id: string | undefined | null): Return => {
let isSubscribed = true;
const abortCtrl = new AbortController();
- async function fetchData(idToFetch: string) {
+ const fetchData = async (idToFetch: string) => {
try {
setLoading(true);
const ruleStatusResponse = await getRuleStatusById({
@@ -49,15 +51,16 @@ export const useRuleStatus = (id: string | undefined | null): Return => {
if (isSubscribed) {
setLoading(false);
}
- }
+ };
if (id != null) {
fetchData(id);
}
+ fetchRuleStatus.current = fetchData;
return () => {
isSubscribed = false;
abortCtrl.abort();
};
}, [id]);
- return [loading, ruleStatus];
+ return [loading, ruleStatus, fetchRuleStatus.current];
};
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/types.ts b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/types.ts
index 34cb7684a0399..ea4860dafd40f 100644
--- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/types.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/types.ts
@@ -96,5 +96,5 @@ export interface Privilege {
write: boolean;
};
};
- isAuthenticated: boolean;
+ is_authenticated: boolean;
}
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_privilege_user.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_privilege_user.tsx
index 792ff29ad2488..7d0e331200d55 100644
--- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_privilege_user.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_privilege_user.tsx
@@ -42,7 +42,7 @@ export const usePrivilegeUser = (): Return => {
});
if (isSubscribed && privilege != null) {
- setAuthenticated(privilege.isAuthenticated);
+ setAuthenticated(privilege.is_authenticated);
if (privilege.index != null && Object.keys(privilege.index).length > 0) {
const indexName = Object.keys(privilege.index)[0];
setHasIndexManage(privilege.index[indexName].manage);
diff --git a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx
index 189d8a1bf3f75..c1ee5fd12b8c1 100644
--- a/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/detection_engine/signals/use_signal_index.tsx
@@ -8,7 +8,6 @@ import { useEffect, useState, useRef } from 'react';
import { errorToToaster } from '../../../components/ml/api/error_to_toaster';
import { useStateToaster } from '../../../components/toasters';
-import { createPrepackagedRules } from '../rules';
import { createSignalIndex, getSignalIndex } from './api';
import * as i18n from './translations';
import { PostSignalError, SignalIndexError } from './types';
@@ -41,7 +40,6 @@ export const useSignalIndex = (): Return => {
if (isSubscribed && signal != null) {
setSignalIndexName(signal.name);
setSignalIndexExists(true);
- createPrepackagedRules({ signal: abortCtrl.signal });
}
} catch (error) {
if (isSubscribed) {
diff --git a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.tsx b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.tsx
index 5b1be4ca2c1dc..d5fd325bb9a26 100644
--- a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/index.tsx
@@ -26,7 +26,6 @@ import { SetQuery } from '../../pages/hosts/navigation/types';
export interface OwnProps extends QueryTemplateProps {
dataKey: string | string[];
defaultStackByOption: MatrixHistogramOption;
- deleteQuery?: ({ id }: { id: string }) => void;
errorMessage: string;
headerChildren?: React.ReactNode;
hideHistogramIfEmpty?: boolean;
diff --git a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/utils.ts b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/utils.ts
index 9cda9d8f6115f..1df1aec76627c 100644
--- a/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/utils.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/matrix_histogram/utils.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { getOr } from 'lodash/fp';
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import {
MatrixHistogramDataTypes,
MatrixHistogramQueryProps,
@@ -35,7 +35,7 @@ export const useQuery = ({
}: MatrixHistogramQueryProps) => {
const [defaultIndex] = useUiSetting$(DEFAULT_INDEX_KEY);
const [, dispatchToaster] = useStateToaster();
- const [refetch, setRefetch] = useState();
+ const refetch = useRef();
const [loading, setLoading] = useState(false);
const [data, setData] = useState(null);
const [inspect, setInspect] = useState(null);
@@ -71,7 +71,7 @@ export const useQuery = ({
return apolloClient
.query({
query,
- fetchPolicy: 'cache-first',
+ fetchPolicy: 'network-only',
variables: matrixHistogramVariables,
context: {
fetchOptions: {
@@ -103,9 +103,7 @@ export const useQuery = ({
}
);
}
- setRefetch(() => {
- fetchData();
- });
+ refetch.current = fetchData;
fetchData();
return () => {
isSubscribed = false;
@@ -122,5 +120,5 @@ export const useQuery = ({
endDate,
]);
- return { data, loading, inspect, totalCount, refetch };
+ return { data, loading, inspect, totalCount, refetch: refetch.current };
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/activity_monitor/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/activity_monitor/index.tsx
index 8290da1ba3220..5f017a3a1f67f 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/activity_monitor/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/activity_monitor/index.tsx
@@ -45,7 +45,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 1,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -55,7 +55,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 2,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -65,7 +65,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 3,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -76,7 +76,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 4,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -87,7 +87,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 5,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -98,7 +98,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 6,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -109,7 +109,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 7,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -120,7 +120,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 8,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -131,7 +131,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 9,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -142,7 +142,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 10,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -153,7 +153,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 11,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -164,7 +164,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 12,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -175,7 +175,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 13,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -186,7 +186,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 14,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -197,7 +197,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 15,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -208,7 +208,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 16,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -219,7 +219,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 17,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -230,7 +230,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 18,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -241,7 +241,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 19,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -252,7 +252,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 20,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
@@ -263,7 +263,7 @@ export const ActivityMonitor = React.memo(() => {
{
id: 21,
rule: {
- href: '#/detection-engine/rules/rule-details',
+ href: '#/detections/rules/rule-details',
name: 'Automated exfiltration',
},
ran: '2019-12-28 00:00:00.000-05:00',
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/translations.ts
index d1ba946be41de..c262f907c9876 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals/translations.ts
@@ -11,7 +11,7 @@ export const PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.pageTitle',
});
export const SIGNALS_TABLE_TITLE = i18n.translate('xpack.siem.detectionEngine.signals.tableTitle', {
- defaultMessage: 'All signals',
+ defaultMessage: 'Signals',
});
export const SIGNALS_DOCUMENT_TYPE = i18n.translate(
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/config.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/config.ts
index f329780b075e3..d475fd155ea25 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/config.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/config.ts
@@ -4,18 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import * as i18n from './translations';
import { SignalsHistogramOption } from './types';
export const signalsHistogramOptions: SignalsHistogramOption[] = [
- { text: i18n.STACK_BY_RISK_SCORES, value: 'signal.rule.risk_score' },
- { text: i18n.STACK_BY_SEVERITIES, value: 'signal.rule.severity' },
- { text: i18n.STACK_BY_DESTINATION_IPS, value: 'destination.ip' },
- { text: i18n.STACK_BY_ACTIONS, value: 'event.action' },
- { text: i18n.STACK_BY_CATEGORIES, value: 'event.category' },
- { text: i18n.STACK_BY_HOST_NAMES, value: 'host.name' },
- { text: i18n.STACK_BY_RULE_TYPES, value: 'signal.rule.type' },
- { text: i18n.STACK_BY_RULE_NAMES, value: 'signal.rule.name' },
- { text: i18n.STACK_BY_SOURCE_IPS, value: 'source.ip' },
- { text: i18n.STACK_BY_USERS, value: 'user.name' },
+ { text: 'signal.rule.risk_score', value: 'signal.rule.risk_score' },
+ { text: 'signal.rule.severity', value: 'signal.rule.severity' },
+ { text: 'destination.ip', value: 'destination.ip' },
+ { text: 'event.action', value: 'event.action' },
+ { text: 'event.category', value: 'event.category' },
+ { text: 'host.name', value: 'host.name' },
+ { text: 'signal.rule.type', value: 'signal.rule.type' },
+ { text: 'signal.rule.name', value: 'signal.rule.name' },
+ { text: 'source.ip', value: 'source.ip' },
+ { text: 'user.name', value: 'user.name' },
];
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx
index fda40f5f9fa5d..64bc7ba24c689 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/index.tsx
@@ -46,7 +46,7 @@ export const SignalsHistogramPanel = memo(
filters,
query,
from,
- legendPosition = 'bottom',
+ legendPosition = 'right',
loadingInitial = false,
showLinkToSignals = false,
showTotalSignalsCount = false,
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram/index.tsx
index 218fcc3a70f79..d4db8cc7c37e8 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/signals_histogram/index.tsx
@@ -44,7 +44,7 @@ export const SignalsHistogram = React.memo(
from,
query,
filters,
- legendPosition = 'bottom',
+ legendPosition = 'right',
loadingInitial,
setTotalSignalsCount,
stackByField,
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts
index 0245b9968cc36..8c88fa4a5dae6 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/signals_histogram_panel/translations.ts
@@ -86,7 +86,7 @@ export const STACK_BY_USERS = i18n.translate(
export const HISTOGRAM_HEADER = i18n.translate(
'xpack.siem.detectionEngine.signals.histogram.headerTitle',
{
- defaultMessage: 'Signal detection frequency',
+ defaultMessage: 'Signal count',
}
);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/user_info/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/user_info/index.tsx
index bbaccb7882484..24e14473d40e9 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/user_info/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/components/user_info/index.tsx
@@ -10,6 +10,7 @@ import React, { useEffect, useReducer, Dispatch, createContext, useContext } fro
import { usePrivilegeUser } from '../../../../containers/detection_engine/signals/use_privilege_user';
import { useSignalIndex } from '../../../../containers/detection_engine/signals/use_signal_index';
import { useKibana } from '../../../../lib/kibana';
+import { useCreatePackagedRules } from '../../../../containers/detection_engine/rules/use_create_packaged_rules';
export interface State {
canUserCRUD: boolean | null;
@@ -161,6 +162,14 @@ export const useUserInfo = (): State => {
createSignalIndex,
] = useSignalIndex();
+ useCreatePackagedRules({
+ canUserCRUD,
+ hasIndexManage,
+ hasManageApiKey,
+ isAuthenticated,
+ isSignalIndexExists,
+ });
+
const uiCapabilities = useKibana().services.application.capabilities;
const capabilitiesCanUserCRUD: boolean =
typeof uiCapabilities.siem.crud === 'boolean' ? uiCapabilities.siem.crud : false;
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx
index 388f667f47fe1..d9e0377b34060 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/detection_engine.tsx
@@ -4,27 +4,31 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiButton, EuiSpacer } from '@elastic/eui';
-import React, { useCallback } from 'react';
+import { EuiButton, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui';
+import React, { useCallback, useMemo } from 'react';
+import { useParams } from 'react-router-dom';
import { StickyContainer } from 'react-sticky';
-
import { connect } from 'react-redux';
import { ActionCreator } from 'typescript-fsa';
+
+import { Query } from '../../../../../../../src/plugins/data/common/query';
+import { esFilters } from '../../../../../../../src/plugins/data/common/es_query';
+
+import { GlobalTime } from '../../containers/global_time';
+import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source';
+import { AlertsTable } from '../../components/alerts_viewer/alerts_table';
import { FiltersGlobal } from '../../components/filters_global';
import { HeaderPage } from '../../components/header_page';
+import { DETECTION_ENGINE_PAGE_NAME } from '../../components/link_to/redirect_to_detection_engine';
import { SiemSearchBar } from '../../components/search_bar';
import { WrapperPage } from '../../components/wrapper_page';
-import { GlobalTime } from '../../containers/global_time';
-import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source';
-import { SpyRoute } from '../../utils/route/spy_routes';
-
-import { Query } from '../../../../../../../src/plugins/data/common/query';
-import { esFilters } from '../../../../../../../src/plugins/data/common/es_query';
import { State } from '../../store';
import { inputsSelectors } from '../../store/inputs';
import { setAbsoluteRangeDatePicker as dispatchSetAbsoluteRangeDatePicker } from '../../store/inputs/actions';
+import { SpyRoute } from '../../utils/route/spy_routes';
import { InputsModelId } from '../../store/inputs/constants';
import { InputsRange } from '../../store/inputs/model';
+import { AlertsByCategory } from '../overview/alerts_by_category';
import { useSignalInfo } from './components/signals_info';
import { SignalsTable } from './components/signals';
import { NoWriteSignalsCallOut } from './components/no_write_signals_callout';
@@ -35,6 +39,7 @@ import { DetectionEngineEmptyPage } from './detection_engine_empty_page';
import { DetectionEngineNoIndex } from './detection_engine_no_signal_index';
import { DetectionEngineUserUnauthenticated } from './detection_engine_user_unauthenticated';
import * as i18n from './translations';
+import { DetectionEngineTab } from './types';
interface ReduxProps {
filters: esFilters.Filter[];
@@ -51,8 +56,22 @@ export interface DispatchProps {
type DetectionEngineComponentProps = ReduxProps & DispatchProps;
+const detectionsTabs = [
+ {
+ id: DetectionEngineTab.signals,
+ name: i18n.SIGNAL,
+ disabled: false,
+ },
+ {
+ id: DetectionEngineTab.alerts,
+ name: i18n.ALERT,
+ disabled: false,
+ },
+];
+
const DetectionEngineComponent = React.memo(
({ filters, query, setAbsoluteRangeDatePicker }) => {
+ const { tabName = DetectionEngineTab.signals } = useParams();
const {
loading,
isSignalIndexExists,
@@ -87,6 +106,25 @@ const DetectionEngineComponent = React.memo(
);
}
+
+ const tabs = useMemo(
+ () => (
+
+ {detectionsTabs.map(tab => (
+
+ {tab.name}
+
+ ))}
+
+ ),
+ [detectionsTabs, tabName]
+ );
+
return (
<>
{hasIndexWrite != null && !hasIndexWrite && }
@@ -99,7 +137,6 @@ const DetectionEngineComponent = React.memo(
@@ -111,32 +148,55 @@ const DetectionEngineComponent = React.memo(
}
title={i18n.PAGE_TITLE}
>
-
+
{i18n.BUTTON_MANAGE_RULES}
- {({ to, from }) => (
+ {({ to, from, deleteQuery, setQuery }) => (
<>
-
+ {tabs}
-
+ {tabName === DetectionEngineTab.signals && (
+ <>
+
+
+
+ >
+ )}
+ {tabName === DetectionEngineTab.alerts && (
+ <>
+
+
+
+ >
+ )}
>
)}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/index.tsx
index c4e83429aebdb..33186d2787d8a 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/index.tsx
@@ -7,21 +7,26 @@
import React from 'react';
import { Redirect, Route, Switch, RouteComponentProps } from 'react-router-dom';
+import { ManageUserInfo } from './components/user_info';
import { CreateRuleComponent } from './rules/create';
import { DetectionEngine } from './detection_engine';
import { EditRuleComponent } from './rules/edit';
import { RuleDetails } from './rules/details';
import { RulesComponent } from './rules';
-import { ManageUserInfo } from './components/user_info';
+import { DetectionEngineTab } from './types';
-const detectionEnginePath = `/:pageName(detection-engine)`;
+const detectionEnginePath = `/:pageName(detections)`;
type Props = Partial> & { url: string };
export const DetectionEngineContainer = React.memo(() => (
-
+
@@ -30,16 +35,16 @@ export const DetectionEngineContainer = React.memo(() => (
-
+
(
-
+
)}
/>
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts
index 757c1fabfc9cd..b79b3ed091f16 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/__mocks__/mock.ts
@@ -60,7 +60,7 @@ export const mockTableData: TableData[] = [
lastResponse: { type: '—' },
method: 'saved_query',
rule: {
- href: '#/detection-engine/rules/id/abe6c564-050d-45a5-aaf0-386c37dd1f61',
+ href: '#/detections/rules/id/abe6c564-050d-45a5-aaf0-386c37dd1f61',
name: 'Home Grown!',
status: 'Status Placeholder',
},
@@ -112,7 +112,7 @@ export const mockTableData: TableData[] = [
lastResponse: { type: '—' },
method: 'saved_query',
rule: {
- href: '#/detection-engine/rules/id/63f06f34-c181-4b2d-af35-f2ace572a1ee',
+ href: '#/detections/rules/id/63f06f34-c181-4b2d-af35-f2ace572a1ee',
name: 'Home Grown!',
status: 'Status Placeholder',
},
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx
index f83a19445acd6..435edcab433b6 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/actions.tsx
@@ -29,17 +29,25 @@ export const editRuleAction = (rule: Rule, history: H.History) => {
history.push(`/${DETECTION_ENGINE_PAGE_NAME}/rules/id/${rule.id}/edit`);
};
-export const duplicateRuleAction = async (
- rule: Rule,
+export const duplicateRulesAction = async (
+ rules: Rule[],
dispatch: React.Dispatch,
dispatchToaster: Dispatch
) => {
try {
- dispatch({ type: 'updateLoading', ids: [rule.id], isLoading: true });
- const duplicatedRule = await duplicateRules({ rules: [rule] });
- dispatch({ type: 'updateLoading', ids: [rule.id], isLoading: false });
- dispatch({ type: 'updateRules', rules: duplicatedRule, appendRuleId: rule.id });
- displaySuccessToast(i18n.SUCCESSFULLY_DUPLICATED_RULES(duplicatedRule.length), dispatchToaster);
+ const ruleIds = rules.map(r => r.id);
+ dispatch({ type: 'updateLoading', ids: ruleIds, isLoading: true });
+ const duplicatedRules = await duplicateRules({ rules });
+ dispatch({ type: 'updateLoading', ids: ruleIds, isLoading: false });
+ dispatch({
+ type: 'updateRules',
+ rules: duplicatedRules,
+ appendRuleId: rules[rules.length - 1].id,
+ });
+ displaySuccessToast(
+ i18n.SUCCESSFULLY_DUPLICATED_RULES(duplicatedRules.length),
+ dispatchToaster
+ );
} catch (e) {
displayErrorToast(i18n.DUPLICATE_RULE_ERROR, [e.message], dispatchToaster);
}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx
index 06d4c709a32bf..8a10d4f7100b9 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/batch_actions.tsx
@@ -10,9 +10,13 @@ import * as H from 'history';
import * as i18n from '../translations';
import { TableData } from '../types';
import { Action } from './reducer';
-import { deleteRulesAction, enableRulesAction, exportRulesAction } from './actions';
+import {
+ deleteRulesAction,
+ duplicateRulesAction,
+ enableRulesAction,
+ exportRulesAction,
+} from './actions';
import { ActionToaster } from '../../../../components/toasters';
-import { DETECTION_ENGINE_PAGE_NAME } from '../../../../components/link_to/redirect_to_detection_engine';
export const getBatchItems = (
selectedState: TableData[],
@@ -25,7 +29,6 @@ export const getBatchItems = (
const containsDisabled = selectedState.some(v => !v.activate);
const containsLoading = selectedState.some(v => v.isLoading);
const containsImmutable = selectedState.some(v => v.immutable);
- const containsMultipleRules = Array.from(new Set(selectedState.map(v => v.rule_id))).length > 1;
return [
,
{
closePopover();
- history.push(`/${DETECTION_ENGINE_PAGE_NAME}/rules/id/${selectedState[0].id}/edit`);
+ await duplicateRulesAction(
+ selectedState.map(s => s.sourceRule),
+ dispatch,
+ dispatchToaster
+ );
}}
>
- {i18n.BATCH_ACTION_EDIT_INDEX_PATTERNS}
+ {i18n.BATCH_ACTION_DUPLICATE_SELECTED}
,
{
closePopover();
await deleteRulesAction(
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx
index 91b018eb3078f..d546c4edb55d3 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/columns.tsx
@@ -18,7 +18,7 @@ import React, { Dispatch } from 'react';
import { getEmptyTagValue } from '../../../../components/empty_value';
import {
deleteRulesAction,
- duplicateRuleAction,
+ duplicateRulesAction,
editRuleAction,
exportRulesAction,
} from './actions';
@@ -30,6 +30,7 @@ import { FormattedDate } from '../../../../components/formatted_date';
import { RuleSwitch } from '../components/rule_switch';
import { SeverityBadge } from '../components/severity_badge';
import { ActionToaster } from '../../../../components/toasters';
+import { getStatusColor } from '../components/rule_status/helpers';
const getActions = (
dispatch: React.Dispatch,
@@ -48,7 +49,7 @@ const getActions = (
icon: 'copy',
name: i18n.DUPLICATE_RULE,
onClick: (rowItem: TableData) =>
- duplicateRuleAction(rowItem.sourceRule, dispatch, dispatchToaster),
+ duplicateRulesAction([rowItem.sourceRule], dispatch, dispatchToaster),
},
{
description: i18n.EXPORT_RULE,
@@ -62,7 +63,6 @@ const getActions = (
icon: 'trash',
name: i18n.DELETE_RULE,
onClick: (rowItem: TableData) => deleteRulesAction([rowItem.id], dispatch, dispatchToaster),
- enabled: (rowItem: TableData) => !rowItem.immutable,
},
];
@@ -87,7 +87,7 @@ export const getColumns = (
field: 'method',
name: i18n.COLUMN_METHOD,
truncateText: true,
- width: '16%',
+ width: '14%',
},
{
field: 'severity',
@@ -114,19 +114,11 @@ export const getColumns = (
field: 'status',
name: i18n.COLUMN_LAST_RESPONSE,
render: (value: TableData['status']) => {
- const color =
- value == null
- ? 'subdued'
- : value === 'succeeded'
- ? 'success'
- : value === 'failed'
- ? 'danger'
- : value === 'executing'
- ? 'warning'
- : 'subdued';
return (
<>
- {value ?? getEmptyTagValue()}
+
+ {value ?? getEmptyTagValue()}
+
>
);
},
@@ -162,7 +154,7 @@ export const getColumns = (
/>
),
sortable: true,
- width: '85px',
+ width: '95px',
},
];
const actions: RulesColumns[] = [
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts
index 9666b7a5688cf..07a2f2f278987 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/helpers.ts
@@ -24,7 +24,7 @@ export const formatRules = (rules: Rule[], selectedIds?: string[]): TableData[]
immutable: rule.immutable,
rule_id: rule.rule_id,
rule: {
- href: `#/detection-engine/rules/id/${encodeURIComponent(rule.id)}`,
+ href: `#/detections/rules/id/${encodeURIComponent(rule.id)}`,
name: rule.name,
status: 'Status Placeholder',
},
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx
index e8b6919165c8b..011c008c5b2d2 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/description_step/helpers.tsx
@@ -125,7 +125,7 @@ export const buildThreatsDescription = ({
description: (
{threats.map((threat, index) => {
- const tactic = tacticsOptions.find(t => t.name === threat.tactic.name);
+ const tactic = tacticsOptions.find(t => t.id === threat.tactic.id);
return (
@@ -133,7 +133,7 @@ export const buildThreatsDescription = ({
{threat.techniques.map(technique => {
- const myTechnique = techniquesOptions.find(t => t.name === technique.name);
+ const myTechnique = techniquesOptions.find(t => t.id === technique.id);
return (
- theme.euiColorPrimary};
+ width: 40px;
+ height: 40px;
+ }
+`;
+
interface RuleActionsOverflowComponentProps {
rule: Rule | null;
userHasNoPermissions: boolean;
@@ -54,7 +66,7 @@ const RuleActionsOverflowComponent = ({
disabled={userHasNoPermissions}
onClick={async () => {
setIsPopoverOpen(false);
- await duplicateRuleAction(rule, noop, dispatchToaster);
+ await duplicateRulesAction([rule], noop, dispatchToaster);
}}
>
{i18nActions.DUPLICATE_RULE}
@@ -73,7 +85,7 @@ const RuleActionsOverflowComponent = ({
{
setIsPopoverOpen(false);
await deleteRulesAction([rule.id], noop, dispatchToaster, onRuleDeletedCallback);
@@ -86,20 +98,29 @@ const RuleActionsOverflowComponent = ({
[rule, userHasNoPermissions]
);
+ const handlePopoverOpen = useCallback(() => {
+ setIsPopoverOpen(!isPopoverOpen);
+ }, [setIsPopoverOpen, isPopoverOpen]);
+
+ const button = useMemo(
+ () => (
+
+
+
+ ),
+ [handlePopoverOpen, userHasNoPermissions]
+ );
+
return (
<>
- setIsPopoverOpen(!isPopoverOpen)}
- />
-
- }
+ button={button}
closePopover={() => setIsPopoverOpen(false)}
id="ruleActionsOverflow"
isOpen={isPopoverOpen}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/helpers.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/helpers.ts
new file mode 100644
index 0000000000000..263f602251ea7
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/helpers.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { RuleStatusType } from '../../../../../containers/detection_engine/rules';
+
+export const getStatusColor = (status: RuleStatusType | string | null) =>
+ status == null
+ ? 'subdued'
+ : status === 'succeeded'
+ ? 'success'
+ : status === 'failed'
+ ? 'danger'
+ : status === 'executing' || status === 'going to run'
+ ? 'warning'
+ : 'subdued';
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/index.tsx
new file mode 100644
index 0000000000000..2c9173cbeb694
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/index.tsx
@@ -0,0 +1,99 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import {
+ EuiButtonIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHealth,
+ EuiLoadingSpinner,
+ EuiText,
+} from '@elastic/eui';
+import { isEqual } from 'lodash/fp';
+import React, { memo, useCallback, useEffect, useState } from 'react';
+
+import { useRuleStatus, RuleInfoStatus } from '../../../../../containers/detection_engine/rules';
+import { FormattedDate } from '../../../../../components/formatted_date';
+import { getEmptyTagValue } from '../../../../../components/empty_value';
+import { getStatusColor } from './helpers';
+import * as i18n from './translations';
+
+interface RuleStatusProps {
+ ruleId: string | null;
+ ruleEnabled?: boolean | null;
+}
+
+const RuleStatusComponent: React.FC = ({ ruleId, ruleEnabled }) => {
+ const [loading, ruleStatus, fetchRuleStatus] = useRuleStatus(ruleId);
+ const [myRuleEnabled, setMyRuleEnabled] = useState(ruleEnabled ?? null);
+ const [currentStatus, setCurrentStatus] = useState(
+ ruleStatus?.current_status ?? null
+ );
+
+ useEffect(() => {
+ if (myRuleEnabled !== ruleEnabled && fetchRuleStatus != null && ruleId != null) {
+ fetchRuleStatus(ruleId);
+ if (myRuleEnabled !== ruleEnabled) {
+ setMyRuleEnabled(ruleEnabled ?? null);
+ }
+ }
+ }, [fetchRuleStatus, myRuleEnabled, ruleId, ruleEnabled, setMyRuleEnabled]);
+
+ useEffect(() => {
+ if (!isEqual(currentStatus, ruleStatus?.current_status)) {
+ setCurrentStatus(ruleStatus?.current_status ?? null);
+ }
+ }, [currentStatus, ruleStatus, setCurrentStatus]);
+
+ const handleRefresh = useCallback(() => {
+ if (fetchRuleStatus != null && ruleId != null) {
+ fetchRuleStatus(ruleId);
+ }
+ }, [fetchRuleStatus, ruleId]);
+
+ return (
+
+
+ {i18n.STATUS}
+ {':'}
+
+ {loading && (
+
+
+
+ )}
+ {!loading && (
+ <>
+
+
+ {currentStatus?.status ?? getEmptyTagValue()}
+
+
+ {currentStatus?.status_date != null && currentStatus?.status != null && (
+ <>
+
+ <>{i18n.STATUS_AT}>
+
+
+
+
+ >
+ )}
+
+
+
+ >
+ )}
+
+ );
+};
+
+export const RuleStatus = memo(RuleStatusComponent);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/translations.ts
new file mode 100644
index 0000000000000..e03cc252ad729
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_status/translations.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;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const STATUS = i18n.translate('xpack.siem.detectionEngine.ruleStatus.statusDescription', {
+ defaultMessage: 'Status',
+});
+
+export const STATUS_AT = i18n.translate(
+ 'xpack.siem.detectionEngine.ruleStatus.statusAtDescription',
+ {
+ defaultMessage: 'at',
+ }
+);
+
+export const STATUS_DATE = i18n.translate(
+ 'xpack.siem.detectionEngine.ruleStatus.statusDateDescription',
+ {
+ defaultMessage: 'Status date',
+ }
+);
+
+export const REFRESH = i18n.translate('xpack.siem.detectionEngine.ruleStatus.refreshButton', {
+ defaultMessage: 'Refresh',
+});
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx
index 9cb0323ed8987..09b7ecc9df982 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/rule_switch/index.tsx
@@ -36,6 +36,7 @@ export interface RuleSwitchProps {
isDisabled?: boolean;
isLoading?: boolean;
optionLabel?: string;
+ onChange?: (enabled: boolean) => void;
}
/**
@@ -48,6 +49,7 @@ export const RuleSwitchComponent = ({
isLoading,
enabled,
optionLabel,
+ onChange,
}: RuleSwitchProps) => {
const [myIsLoading, setMyIsLoading] = useState(false);
const [myEnabled, setMyEnabled] = useState(enabled ?? false);
@@ -65,6 +67,9 @@ export const RuleSwitchComponent = ({
enabled: event.target.checked!,
});
setMyEnabled(updatedRules[0].enabled);
+ if (onChange != null) {
+ onChange(updatedRules[0].enabled);
+ }
} catch {
setMyIsLoading(false);
}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/schedule_item_form/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/schedule_item_form/index.tsx
index 0ef104e6891df..3bde2087f26b1 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/schedule_item_form/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/schedule_item_form/index.tsx
@@ -150,7 +150,13 @@ export const ScheduleItem = ({
/>
}
>
-
+
);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts
index 328c4a0f96066..92aca1cecf9f3 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/default_value.ts
@@ -5,6 +5,7 @@
*/
import { AboutStepRule } from '../../types';
+import { DEFAULT_TIMELINE_TITLE } from '../../../../../components/timeline/search_super_select/translations';
export const threatsDefault = [
{
@@ -25,7 +26,7 @@ export const stepAboutDefaultValue: AboutStepRule = {
tags: [],
timeline: {
id: null,
- title: null,
+ title: DEFAULT_TIMELINE_TITLE,
},
threats: threatsDefault,
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx
index 0e03a11776fb7..73c07673a82f4 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_about_rule/index.tsx
@@ -5,10 +5,11 @@
*/
import { EuiButton, EuiHorizontalRule, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
-import { isEqual, get } from 'lodash/fp';
+import { isEqual } from 'lodash/fp';
import React, { FC, memo, useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
+import { setFieldValue } from '../../helpers';
import { RuleStepProps, RuleStep, AboutStepRule } from '../../types';
import * as RuleI18n from '../../translations';
import { AddItem } from '../add_item_form';
@@ -71,14 +72,7 @@ const StepAboutRuleComponent: FC = ({
isNew: false,
};
setMyStepData(myDefaultValues);
- if (!isReadOnlyView) {
- Object.keys(schema).forEach(key => {
- const val = get(key, myDefaultValues);
- if (val != null) {
- form.setFieldValue(key, val);
- }
- });
- }
+ setFieldValue(form, schema, myDefaultValues);
}
}, [defaultValues]);
@@ -88,7 +82,7 @@ const StepAboutRuleComponent: FC = ({
}
}, [form]);
- return isReadOnlyView && myStepData != null ? (
+ return isReadOnlyView && myStepData.name != null ? (
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx
index 6bdef4a69af1e..5409a5f161bba 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_define_rule/index.tsx
@@ -11,7 +11,7 @@ import {
EuiFlexItem,
EuiButton,
} from '@elastic/eui';
-import { isEmpty, isEqual, get } from 'lodash/fp';
+import { isEmpty, isEqual } from 'lodash/fp';
import React, { FC, memo, useCallback, useState, useEffect } from 'react';
import styled from 'styled-components';
@@ -19,6 +19,7 @@ import { IIndexPattern } from '../../../../../../../../../../src/plugins/data/pu
import { useFetchIndexPatterns } from '../../../../../containers/detection_engine/rules';
import { DEFAULT_INDEX_KEY } from '../../../../../../common/constants';
import { useUiSetting$ } from '../../../../../lib/kibana';
+import { setFieldValue } from '../../helpers';
import * as RuleI18n from '../../translations';
import { DefineStepRule, RuleStep, RuleStepProps } from '../../types';
import { StepRuleDescription } from '../description_step';
@@ -121,14 +122,7 @@ const StepDefineRuleComponent: FC = ({
if (!isEqual(myDefaultValues, myStepData)) {
setMyStepData(myDefaultValues);
setLocalUseIndicesConfig(isEqual(myDefaultValues.index, indicesConfig));
- if (!isReadOnlyView) {
- Object.keys(schema).forEach(key => {
- const val = get(key, myDefaultValues);
- if (val != null) {
- form.setFieldValue(key, val);
- }
- });
- }
+ setFieldValue(form, schema, myDefaultValues);
}
}
}, [defaultValues, indicesConfig]);
@@ -152,7 +146,7 @@ const StepDefineRuleComponent: FC = ({
setOpenTimelineSearch(false);
}, []);
- return isReadOnlyView && myStepData != null ? (
+ return isReadOnlyView && myStepData?.queryBar != null ? (
= ({
@@ -67,14 +68,7 @@ const StepScheduleRuleComponent: FC = ({
isNew: false,
};
setMyStepData(myDefaultValues);
- if (!isReadOnlyView) {
- Object.keys(schema).forEach(key => {
- const val = get(key, myDefaultValues);
- if (val != null) {
- form.setFieldValue(key, val);
- }
- });
- }
+ setFieldValue(form, schema, myDefaultValues);
}
}, [defaultValues]);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/schema.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/schema.tsx
index 4da17b88b9ad0..a951c1fab7cc8 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/schema.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/schema.tsx
@@ -14,13 +14,14 @@ export const schema: FormSchema = {
label: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepScheduleRule.fieldIntervalLabel',
{
- defaultMessage: 'Rule run interval & look-back',
+ defaultMessage: 'Runs every',
}
),
helpText: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepScheduleRule.fieldIntervalHelpText',
{
- defaultMessage: 'How often and how far back this rule will search specified indices.',
+ defaultMessage:
+ 'Rules run periodically and detect signals within the specified time frame.',
}
),
},
@@ -28,15 +29,14 @@ export const schema: FormSchema = {
label: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepScheduleRule.fieldAdditionalLookBackLabel',
{
- defaultMessage: 'Additional look-back',
+ defaultMessage: 'Additional look-back time',
}
),
labelAppend: OptionalFieldLabel,
helpText: i18n.translate(
'xpack.siem.detectionEngine.createRule.stepScheduleRule.fieldAdditionalLookBackHelpText',
{
- defaultMessage:
- 'Add more time to the look-back range in order to prevent potential gaps in signal reporting.',
+ defaultMessage: 'Adds time to the look-back period to prevent missed signals.',
}
),
},
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/translations.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/translations.tsx
index feaaf4e85b2af..67bcc1af8150b 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/translations.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/step_schedule_rule/translations.tsx
@@ -9,13 +9,13 @@ import { i18n } from '@kbn/i18n';
export const COMPLETE_WITHOUT_ACTIVATING = i18n.translate(
'xpack.siem.detectionEngine.createRule. stepScheduleRule.completeWithoutActivatingTitle',
{
- defaultMessage: 'Complete rule without activating',
+ defaultMessage: 'Create rule without activating it',
}
);
export const COMPLETE_WITH_ACTIVATING = i18n.translate(
'xpack.siem.detectionEngine.createRule. stepScheduleRule.completeWithActivatingTitle',
{
- defaultMessage: 'Complete rule & activate',
+ defaultMessage: 'Create & activate rule',
}
);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/create/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/create/index.tsx
index e5656f5b081fb..cbc60015d9c87 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/create/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/create/index.tsx
@@ -9,10 +9,11 @@ import React, { useCallback, useRef, useState } from 'react';
import { Redirect } from 'react-router-dom';
import styled from 'styled-components';
+import { usePersistRule } from '../../../../containers/detection_engine/rules';
import { HeaderPage } from '../../../../components/header_page';
import { DETECTION_ENGINE_PAGE_NAME } from '../../../../components/link_to/redirect_to_detection_engine';
import { WrapperPage } from '../../../../components/wrapper_page';
-import { usePersistRule } from '../../../../containers/detection_engine/rules';
+import { displaySuccessToast, useStateToaster } from '../../../../components/toasters';
import { SpyRoute } from '../../../../utils/route/spy_routes';
import { useUserInfo } from '../../components/user_info';
import { AccordionTitle } from '../components/accordion_title';
@@ -55,6 +56,7 @@ export const CreateRuleComponent = React.memo(() => {
canUserCRUD,
hasManageApiKey,
} = useUserInfo();
+ const [, dispatchToaster] = useStateToaster();
const [openAccordionId, setOpenAccordionId] = useState(RuleStep.defineRule);
const defineRuleRef = useRef(null);
const aboutRuleRef = useRef(null);
@@ -95,6 +97,7 @@ export const CreateRuleComponent = React.memo(() => {
const stepRuleIdx = stepsRuleOrder.findIndex(item => step === item);
if ([0, 1].includes(stepRuleIdx)) {
if (isStepRuleInReadOnlyView[stepsRuleOrder[stepRuleIdx + 1]]) {
+ setOpenAccordionId(stepsRuleOrder[stepRuleIdx + 1]);
setIsStepRuleInEditView({
...isStepRuleInReadOnlyView,
[step]: true,
@@ -203,12 +206,15 @@ export const CreateRuleComponent = React.memo(() => {
async (id: RuleStep) => {
const activeForm = await stepsForm.current[openAccordionId]?.submit();
if (activeForm != null && activeForm?.isValid) {
+ stepsData.current[openAccordionId] = {
+ ...stepsData.current[openAccordionId],
+ data: activeForm.data,
+ isValid: activeForm.isValid,
+ };
setOpenAccordionId(id);
- openCloseAccordion(openAccordionId);
-
setIsStepRuleInEditView({
...isStepRuleInReadOnlyView,
- [openAccordionId]: openAccordionId === RuleStep.scheduleRule ? false : true,
+ [openAccordionId]: true,
[id]: false,
});
}
@@ -217,6 +223,8 @@ export const CreateRuleComponent = React.memo(() => {
);
if (isSaved) {
+ const ruleName = (stepsData.current[RuleStep.aboutRule].data as AboutStepRule).name;
+ displaySuccessToast(i18n.SUCCESSFULLY_CREATED_RULES(ruleName), dispatchToaster);
return ;
}
@@ -224,7 +232,7 @@ export const CreateRuleComponent = React.memo(() => {
<>
{
{
{
+ i18n.translate('xpack.siem.detectionEngine.rules.create.successfullyCreatedRuleTitle', {
+ values: { ruleName },
+ defaultMessage: '{ruleName} was created',
+ });
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/failure_history.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/failure_history.tsx
index 3b49cd30c9aab..f660c1763d5e0 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/failure_history.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/failure_history.tsx
@@ -15,8 +15,7 @@ import {
} from '@elastic/eui';
import React, { memo } from 'react';
-import { useRuleStatus } from '../../../../containers/detection_engine/rules/use_rule_status';
-import { RuleStatus } from '../../../../containers/detection_engine/rules';
+import { useRuleStatus, RuleInfoStatus } from '../../../../containers/detection_engine/rules';
import { HeaderSection } from '../../../../components/header_section';
import * as i18n from './translations';
import { FormattedDate } from '../../../../components/formatted_date';
@@ -35,7 +34,7 @@ const FailureHistoryComponent: React.FC = ({ id }) => {
);
}
- const columns: Array> = [
+ const columns: Array> = [
{
name: i18n.COLUMN_STATUS_TYPE,
render: () => {i18n.TYPE_FAILED},
@@ -65,7 +64,9 @@ const FailureHistoryComponent: React.FC = ({ id }) => {
rs.last_failure_at != null) : []}
+ items={
+ ruleStatus != null ? ruleStatus?.failures.filter(rs => rs.last_failure_at != null) : []
+ }
sorting={{ sort: { field: 'status_date', direction: 'desc' } }}
/>
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx
index 099006a34920c..a23c681a5aab2 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/index.tsx
@@ -10,8 +10,8 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
- EuiHealth,
EuiTab,
+ EuiTabs,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { memo, useCallback, useMemo, useState } from 'react';
@@ -60,10 +60,10 @@ import { inputsSelectors } from '../../../../store/inputs';
import { State } from '../../../../store';
import { InputsRange } from '../../../../store/inputs/model';
import { setAbsoluteRangeDatePicker as dispatchSetAbsoluteRangeDatePicker } from '../../../../store/inputs/actions';
-import { getEmptyTagValue } from '../../../../components/empty_value';
+import { RuleActionsOverflow } from '../components/rule_actions_overflow';
import { RuleStatusFailedCallOut } from './status_failed_callout';
import { FailureHistory } from './failure_history';
-import { RuleActionsOverflow } from '../components/rule_actions_overflow';
+import { RuleStatus } from '../components/rule_status';
interface ReduxProps {
filters: esFilters.Filter[];
@@ -78,14 +78,19 @@ export interface DispatchProps {
}>;
}
+enum RuleDetailTabs {
+ signals = 'signals',
+ failures = 'failures',
+}
+
const ruleDetailTabs = [
{
- id: 'signal',
+ id: RuleDetailTabs.signals,
name: detectionI18n.SIGNAL,
disabled: false,
},
{
- id: 'failure',
+ id: RuleDetailTabs.failures,
name: i18n.FAILURE_HISTORY_TAB,
disabled: false,
},
@@ -106,7 +111,9 @@ const RuleDetailsComponent = memo(
} = useUserInfo();
const { ruleId } = useParams();
const [isLoading, rule] = useRule(ruleId);
- const [ruleDetailTab, setRuleDetailTab] = useState('signal');
+ // This is used to re-trigger api rule status when user de/activate rule
+ const [ruleEnabled, setRuleEnabled] = useState(null);
+ const [ruleDetailTab, setRuleDetailTab] = useState(RuleDetailTabs.signals);
const { aboutRuleData, defineRuleData, scheduleRuleData } = getStepsData({
rule,
detailsView: true,
@@ -175,34 +182,28 @@ const RuleDetailsComponent = memo(
filters,
]);
- const statusColor =
- rule?.status == null
- ? 'subdued'
- : rule?.status === 'succeeded'
- ? 'success'
- : rule?.status === 'failed'
- ? 'danger'
- : rule?.status === 'executing'
- ? 'warning'
- : 'subdued';
-
const tabs = useMemo(
- () =>
- ruleDetailTabs.map(tab => (
- setRuleDetailTab(tab.id)}
- isSelected={tab.id === ruleDetailTab}
- disabled={tab.disabled}
- key={tab.name}
- >
- {tab.name}
-
- )),
+ () => (
+
+ {ruleDetailTabs.map(tab => (
+ setRuleDetailTab(tab.id)}
+ isSelected={tab.id === ruleDetailTab}
+ disabled={tab.disabled}
+ key={tab.id}
+ >
+ {tab.name}
+
+ ))}
+
+ ),
[ruleDetailTabs, ruleDetailTab, setRuleDetailTab]
);
const ruleError = useMemo(
() =>
- rule?.status === 'failed' && ruleDetailTab === 'signal' && rule?.last_failure_at != null ? (
+ rule?.status === 'failed' &&
+ ruleDetailTab === RuleDetailTabs.signals &&
+ rule?.last_failure_at != null ? (
(
[setAbsoluteRangeDatePicker]
);
+ const handleOnChangeEnabledRule = useCallback(
+ (enabled: boolean) => {
+ if (ruleEnabled == null || enabled !== ruleEnabled) {
+ setRuleEnabled(enabled);
+ }
+ },
+ [ruleEnabled, setRuleEnabled]
+ );
+
return (
<>
{hasIndexWrite != null && !hasIndexWrite && }
@@ -238,7 +248,6 @@ const RuleDetailsComponent = memo(
href: `#${DETECTION_ENGINE_PAGE_NAME}/rules`,
text: i18n.BACK_TO_RULES,
}}
- badgeOptions={{ text: i18n.EXPERIMENTAL }}
border
subtitle={subTitle}
subtitle2={[
@@ -251,34 +260,7 @@ const RuleDetailsComponent = memo(
>,
]
: []),
-
-
- {i18n.STATUS}
- {':'}
-
-
-
- {rule?.status ?? getEmptyTagValue()}
-
-
- {rule?.status_date && (
- <>
-
- <>{i18n.STATUS_AT}>
-
-
-
-
- >
- )}
- ,
+ ,
]}
title={title}
>
@@ -289,6 +271,7 @@ const RuleDetailsComponent = memo(
isDisabled={userHasNoPermissions}
enabled={rule?.enabled ?? false}
optionLabel={i18n.ACTIVATE_RULE}
+ onChange={handleOnChangeEnabledRule}
/>
@@ -316,7 +299,7 @@ const RuleDetailsComponent = memo(
{ruleError}
{tabs}
- {ruleDetailTab === 'signal' && (
+ {ruleDetailTab === RuleDetailTabs.signals && (
<>
@@ -381,7 +364,9 @@ const RuleDetailsComponent = memo(
)}
>
)}
- {ruleDetailTab === 'failure' && }
+ {ruleDetailTab === RuleDetailTabs.failures && (
+
+ )}
)}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/translations.ts
index 9976abc8412bf..46b6984ab323f 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/details/translations.ts
@@ -13,7 +13,7 @@ export const PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.ruleDetails
export const BACK_TO_RULES = i18n.translate(
'xpack.siem.detectionEngine.ruleDetails.backToRulesDescription',
{
- defaultMessage: 'Back to rules',
+ defaultMessage: 'Back to signal detection rules',
}
);
@@ -35,24 +35,6 @@ export const UNKNOWN = i18n.translate('xpack.siem.detectionEngine.ruleDetails.un
defaultMessage: 'Unknown',
});
-export const STATUS = i18n.translate('xpack.siem.detectionEngine.ruleDetails.statusDescription', {
- defaultMessage: 'Status',
-});
-
-export const STATUS_AT = i18n.translate(
- 'xpack.siem.detectionEngine.ruleDetails.statusAtDescription',
- {
- defaultMessage: 'at',
- }
-);
-
-export const STATUS_DATE = i18n.translate(
- 'xpack.siem.detectionEngine.ruleDetails.statusDateDescription',
- {
- defaultMessage: 'Status date',
- }
-);
-
export const ERROR_CALLOUT_TITLE = i18n.translate(
'xpack.siem.detectionEngine.ruleDetails.errorCalloutTitle',
{
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/index.tsx
index e583461f52439..9b7833afd7f4d 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/index.tsx
@@ -17,11 +17,12 @@ import { FormattedMessage } from '@kbn/i18n/react';
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Redirect, useParams } from 'react-router-dom';
+import { useRule, usePersistRule } from '../../../../containers/detection_engine/rules';
import { HeaderPage } from '../../../../components/header_page';
import { WrapperPage } from '../../../../components/wrapper_page';
-import { SpyRoute } from '../../../../utils/route/spy_routes';
import { DETECTION_ENGINE_PAGE_NAME } from '../../../../components/link_to/redirect_to_detection_engine';
-import { useRule, usePersistRule } from '../../../../containers/detection_engine/rules';
+import { displaySuccessToast, useStateToaster } from '../../../../components/toasters';
+import { SpyRoute } from '../../../../utils/route/spy_routes';
import { useUserInfo } from '../../components/user_info';
import { FormHook, FormData } from '../components/shared_imports';
import { StepPanel } from '../components/step_panel';
@@ -48,6 +49,7 @@ interface ScheduleStepRuleForm extends StepRuleForm {
}
export const EditRuleComponent = memo(() => {
+ const [, dispatchToaster] = useStateToaster();
const {
loading: initLoading,
isSignalIndexExists,
@@ -271,6 +273,7 @@ export const EditRuleComponent = memo(() => {
}, []);
if (isSaved || (rule != null && rule.immutable)) {
+ displaySuccessToast(i18n.SUCCESSFULLY_SAVED_RULE(rule?.name ?? ''), dispatchToaster);
return ;
}
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/translations.ts
index b81ae58e565f0..f6e56dca19c21 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/edit/translations.ts
@@ -28,3 +28,9 @@ export const SORRY_ERRORS = i18n.translate(
export const BACK_TO = i18n.translate('xpack.siem.detectionEngine.editRule.backToDescription', {
defaultMessage: 'Back to',
});
+
+export const SUCCESSFULLY_SAVED_RULE = (ruleName: string) =>
+ i18n.translate('xpack.siem.detectionEngine.rules.update.successfullySavedRuleTitle', {
+ values: { ruleName },
+ defaultMessage: '{ruleName} was saved',
+ });
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx
index cc0882dd7e426..cfe6cb8da1cb0 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/helpers.tsx
@@ -4,11 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { pick } from 'lodash/fp';
+import { get, pick } from 'lodash/fp';
import { useLocation } from 'react-router-dom';
import { esFilters } from '../../../../../../../../src/plugins/data/public';
import { Rule } from '../../../containers/detection_engine/rules';
+import { FormData, FormHook, FormSchema } from './components/shared_imports';
import { AboutStepRule, DefineStepRule, IMitreEnterpriseAttack, ScheduleStepRule } from './types';
interface GetStepsData {
@@ -67,3 +68,15 @@ export const getStepsData = ({
};
export const useQuery = () => new URLSearchParams(useLocation().search);
+
+export const setFieldValue = (
+ form: FormHook,
+ schema: FormSchema,
+ defaultValues: unknown
+) =>
+ Object.keys(schema).forEach(key => {
+ const val = get(key, defaultValues);
+ if (val != null) {
+ form.setFieldValue(key, val);
+ }
+ });
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/translations.ts
index aeeef925d60e5..e1257007d44a3 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/translations.ts
@@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n';
export const BACK_TO_DETECTION_ENGINE = i18n.translate(
'xpack.siem.detectionEngine.rules.backOptionsHeader',
{
- defaultMessage: 'Back to detection engine',
+ defaultMessage: 'Back to detections',
}
);
@@ -18,11 +18,11 @@ export const IMPORT_RULE = i18n.translate('xpack.siem.detectionEngine.rules.impo
});
export const ADD_NEW_RULE = i18n.translate('xpack.siem.detectionEngine.rules.addNewRuleTitle', {
- defaultMessage: 'Add new rule',
+ defaultMessage: 'Create new rule',
});
export const PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.rules.pageTitle', {
- defaultMessage: 'Rules',
+ defaultMessage: 'Signal detection rules',
});
export const REFRESH = i18n.translate('xpack.siem.detectionEngine.rules.allRules.refreshTitle', {
@@ -32,7 +32,7 @@ export const REFRESH = i18n.translate('xpack.siem.detectionEngine.rules.allRules
export const BATCH_ACTIONS = i18n.translate(
'xpack.siem.detectionEngine.rules.allRules.batchActionsTitle',
{
- defaultMessage: 'Batch actions',
+ defaultMessage: 'Bulk actions',
}
);
@@ -75,10 +75,10 @@ export const BATCH_ACTION_EXPORT_SELECTED = i18n.translate(
}
);
-export const BATCH_ACTION_EDIT_INDEX_PATTERNS = i18n.translate(
- 'xpack.siem.detectionEngine.rules.allRules.batchActions.editIndexPatternsTitle',
+export const BATCH_ACTION_DUPLICATE_SELECTED = i18n.translate(
+ 'xpack.siem.detectionEngine.rules.allRules.batchActions.duplicateSelectedTitle',
{
- defaultMessage: 'Edit selected index patterns…',
+ defaultMessage: 'Duplicate selected…',
}
);
@@ -243,7 +243,7 @@ export const COLUMN_TAGS = i18n.translate(
export const COLUMN_ACTIVATE = i18n.translate(
'xpack.siem.detectionEngine.rules.allRules.columns.activateTitle',
{
- defaultMessage: 'Activate',
+ defaultMessage: 'Activated',
}
);
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts
index e5f830d3a49b0..ab785a8ad2c6d 100644
--- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/translations.ts
@@ -6,8 +6,8 @@
import { i18n } from '@kbn/i18n';
-export const PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.pageTitle', {
- defaultMessage: 'Detection engine',
+export const PAGE_TITLE = i18n.translate('xpack.siem.detectionEngine.detectionsPageTitle', {
+ defaultMessage: 'Detections',
});
export const LAST_SIGNAL = i18n.translate('xpack.siem.detectionEngine.lastSignalTitle', {
@@ -22,8 +22,12 @@ export const SIGNAL = i18n.translate('xpack.siem.detectionEngine.signalTitle', {
defaultMessage: 'Signals',
});
+export const ALERT = i18n.translate('xpack.siem.detectionEngine.alertTitle', {
+ defaultMessage: 'Third-party alerts',
+});
+
export const BUTTON_MANAGE_RULES = i18n.translate('xpack.siem.detectionEngine.buttonManageRules', {
- defaultMessage: 'Manage rules',
+ defaultMessage: 'Manage signal detection rules',
});
export const PANEL_SUBTITLE_SHOWING = i18n.translate(
diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/types.ts b/x-pack/legacy/plugins/siem/public/pages/detection_engine/types.ts
new file mode 100644
index 0000000000000..d529d99ad3ad4
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/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;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export enum DetectionEngineTab {
+ signals = 'signals',
+ alerts = 'alerts',
+}
diff --git a/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx b/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx
index 220f8a958aa43..c0e959c5e97fa 100644
--- a/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/home/home_navigations.tsx
@@ -36,12 +36,12 @@ export const navTabs: SiemNavTab = {
disabled: false,
urlKey: 'network',
},
- [SiemPageName.detectionEngine]: {
- id: SiemPageName.detectionEngine,
+ [SiemPageName.detections]: {
+ id: SiemPageName.detections,
name: i18n.DETECTION_ENGINE,
href: getDetectionEngineUrl(),
disabled: false,
- urlKey: 'detection-engine',
+ urlKey: 'detections',
},
[SiemPageName.timelines]: {
id: SiemPageName.timelines,
diff --git a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx
index a545be447796d..b5bfdbde306ca 100644
--- a/x-pack/legacy/plugins/siem/public/pages/home/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/home/index.tsx
@@ -105,7 +105,7 @@ export const HomePage: React.FC = () => (
)}
/>
(
)}
diff --git a/x-pack/legacy/plugins/siem/public/pages/home/translations.ts b/x-pack/legacy/plugins/siem/public/pages/home/translations.ts
index b87ea1c17a117..80800a3bd4198 100644
--- a/x-pack/legacy/plugins/siem/public/pages/home/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/home/translations.ts
@@ -19,7 +19,7 @@ export const NETWORK = i18n.translate('xpack.siem.navigation.network', {
});
export const DETECTION_ENGINE = i18n.translate('xpack.siem.navigation.detectionEngine', {
- defaultMessage: 'Detection engine',
+ defaultMessage: 'Detections',
});
export const TIMELINES = i18n.translate('xpack.siem.navigation.timelines', {
diff --git a/x-pack/legacy/plugins/siem/public/pages/home/types.ts b/x-pack/legacy/plugins/siem/public/pages/home/types.ts
index 101c6a69b08d1..678de6dbcc128 100644
--- a/x-pack/legacy/plugins/siem/public/pages/home/types.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/home/types.ts
@@ -10,7 +10,7 @@ export enum SiemPageName {
overview = 'overview',
hosts = 'hosts',
network = 'network',
- detectionEngine = 'detection-engine',
+ detections = 'detections',
timelines = 'timelines',
}
@@ -18,7 +18,7 @@ export type SiemNavTabKey =
| SiemPageName.overview
| SiemPageName.hosts
| SiemPageName.network
- | SiemPageName.detectionEngine
+ | SiemPageName.detections
| SiemPageName.timelines;
export type SiemNavTab = Record;
diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/authentications_query_tab_body.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/authentications_query_tab_body.tsx
index 0bb9563296316..0109eeef91463 100644
--- a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/authentications_query_tab_body.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/authentications_query_tab_body.tsx
@@ -25,7 +25,7 @@ const AuthenticationTableManage = manageQuery(AuthenticationTable);
const ID = 'authenticationsOverTimeQuery';
const authStackByOptions: MatrixHistogramOption[] = [
{
- text: i18n.NAVIGATION_AUTHENTICATIONS_STACK_BY_EVENT_TYPE,
+ text: 'event.type',
value: 'event.type',
},
];
@@ -71,7 +71,6 @@ export const AuthenticationsQueryTabBody = ({
isAuthenticationsHistogram={true}
dataKey="AuthenticationsHistogram"
defaultStackByOption={authStackByOptions[0]}
- deleteQuery={deleteQuery}
endDate={endDate}
errorMessage={i18n.ERROR_FETCHING_AUTHENTICATIONS_DATA}
filterQuery={filterQuery}
diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx
index a07cbc8484a1b..85bca90cc8e04 100644
--- a/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/hosts/navigation/events_query_tab_body.tsx
@@ -20,11 +20,11 @@ const EVENTS_HISTOGRAM_ID = 'eventsOverTimeQuery';
export const eventsStackByOptions: MatrixHistogramOption[] = [
{
- text: i18n.NAVIGATION_EVENTS_STACK_BY_EVENT_ACTION,
+ text: 'event.action',
value: 'event.action',
},
{
- text: i18n.NAVIGATION_EVENTS_STACK_BY_EVENT_DATASET,
+ text: 'event.dataset',
value: 'event.dataset',
},
];
@@ -50,7 +50,6 @@ export const EventsQueryTabBody = ({
void;
filters?: esFilters.Filter[];
from: number;
+ hideHeaderChildren?: boolean;
indexPattern: IIndexPattern;
query?: Query;
setAbsoluteRangeDatePicker: SetAbsoluteRangeDatePicker;
@@ -60,14 +60,24 @@ export const AlertsByCategory = React.memo(
deleteQuery,
filters = NO_FILTERS,
from,
+ hideHeaderChildren = false,
indexPattern,
query = DEFAULT_QUERY,
setAbsoluteRangeDatePicker,
setQuery,
to,
}) => {
+ useEffect(() => {
+ return () => {
+ if (deleteQuery) {
+ deleteQuery({ id: ID });
+ }
+ };
+ }, []);
+
const kibana = useKibana();
const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT);
+
const updateDateRangeCallback = useCallback(
(min: number, max: number) => {
setAbsoluteRangeDatePicker!({ id: 'global', from: min, to: max });
@@ -76,17 +86,11 @@ export const AlertsByCategory = React.memo(
);
const alertsCountViewAlertsButton = useMemo(
() => (
-
- {i18n.VIEW_ALERTS}
-
+ {i18n.VIEW_ALERTS}
),
[]
);
- const getTitle = useCallback(
- (option: MatrixHistogramOption) => i18n.ALERTS_COUNT_BY(option.text),
- []
- );
const getSubtitle = useCallback(
(totalCount: number) =>
`${SHOWING}: ${numeral(totalCount).format(defaultNumberFormat)} ${UNIT(totalCount)}`,
@@ -96,7 +100,6 @@ export const AlertsByCategory = React.memo(
return (
(
queries: [query],
filters,
})}
- headerChildren={alertsCountViewAlertsButton}
+ headerChildren={hideHeaderChildren ? null : alertsCountViewAlertsButton}
id={ID}
isAlertsHistogram={true}
legendPosition={'right'}
@@ -115,7 +118,7 @@ export const AlertsByCategory = React.memo(
sourceId="default"
stackByOptions={alertsStackByOptions}
startDate={from}
- title={getTitle}
+ title={i18n.ALERTS_GRAPH_TITLE}
subtitle={getSubtitle}
type={HostsType.page}
updateDateRange={updateDateRangeCallback}
diff --git a/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx b/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx
index 52084c4bfc280..191b4a2592695 100644
--- a/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/overview/events_by_dataset/index.tsx
@@ -6,7 +6,7 @@
import { EuiButton } from '@elastic/eui';
import numeral from '@elastic/numeral';
-import React, { useCallback, useMemo } from 'react';
+import React, { useCallback, useEffect, useMemo } from 'react';
import { esFilters, IIndexPattern, Query } from 'src/plugins/data/public';
import styled from 'styled-components';
@@ -66,8 +66,17 @@ export const EventsByDataset = React.memo(
setQuery,
to,
}) => {
+ useEffect(() => {
+ return () => {
+ if (deleteQuery) {
+ deleteQuery({ id: ID });
+ }
+ };
+ }, []);
+
const kibana = useKibana();
const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT);
+
const updateDateRangeCallback = useCallback(
(min: number, max: number) => {
setAbsoluteRangeDatePicker!({ id: 'global', from: min, to: max });
@@ -96,7 +105,6 @@ export const EventsByDataset = React.memo(
return (
defaultMessage: 'Alerts count by {groupByField}',
});
+export const ALERTS_GRAPH_TITLE = i18n.translate('xpack.siem.overview.alertsGraphTitle', {
+ defaultMessage: 'Alert detection frequency',
+});
+
export const EVENTS_COUNT_BY = (groupByField: string) =>
i18n.translate('xpack.siem.overview.eventsCountByTitle', {
values: { groupByField },
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts
index 30a8d9d935128..a84fcb64d9ff7 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts
@@ -18,9 +18,9 @@ import {
DETECTION_ENGINE_PREPACKAGED_URL,
} from '../../../../../common/constants';
import { RuleAlertType, IRuleSavedAttributesSavedObjectAttributes } from '../../rules/types';
-import { RuleAlertParamsRest } from '../../types';
+import { RuleAlertParamsRest, PrepackagedRules } from '../../types';
-export const fullRuleAlertParamsRest = (): RuleAlertParamsRest => ({
+export const mockPrepackagedRule = (): PrepackagedRules => ({
rule_id: 'rule-1',
description: 'Detecting root and admin users',
index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'],
@@ -51,8 +51,6 @@ export const fullRuleAlertParamsRest = (): RuleAlertParamsRest => ({
false_positives: [],
saved_id: 'some-id',
max_signals: 100,
- created_at: '2019-12-13T16:40:33.400Z',
- updated_at: '2019-12-13T16:40:33.400Z',
timeline_id: 'timeline-id',
timeline_title: 'timeline-title',
});
@@ -393,7 +391,7 @@ export const getMockPrivileges = () => ({
},
},
application: {},
- isAuthenticated: false,
+ is_authenticated: false,
});
export const getFindResultStatus = (): SavedObjectsFindResponse => ({
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts
index 240200af8b585..803d9d645aadb 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts
@@ -30,7 +30,7 @@ export const createReadPrivilegesRulesRoute = (server: ServerFacade): Hapi.Serve
const index = getIndex(request, server);
const permissions = await readPrivileges(callWithRequest, index);
return merge(permissions, {
- isAuthenticated: request?.auth?.isAuthenticated ?? false,
+ is_authenticated: request?.auth?.isAuthenticated ?? false,
});
} catch (err) {
return transformError(err);
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts
index 5ceecdb058e5f..3c9cad8dc4d4b 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts
@@ -36,8 +36,10 @@ export const createAddPrepackedRulesRoute = (server: ServerFacade): Hapi.ServerR
const actionsClient = isFunction(request.getActionsClient)
? request.getActionsClient()
: null;
-
- if (!alertsClient || !actionsClient) {
+ const savedObjectsClient = isFunction(request.getSavedObjectsClient)
+ ? request.getSavedObjectsClient()
+ : null;
+ if (!alertsClient || !actionsClient || !savedObjectsClient) {
return headers.response().code(404);
}
@@ -59,7 +61,13 @@ export const createAddPrepackedRulesRoute = (server: ServerFacade): Hapi.ServerR
}
}
await installPrepackagedRules(alertsClient, actionsClient, rulesToInstall, spaceIndex);
- await updatePrepackagedRules(alertsClient, actionsClient, rulesToUpdate, spaceIndex);
+ await updatePrepackagedRules(
+ alertsClient,
+ actionsClient,
+ savedObjectsClient,
+ rulesToUpdate,
+ spaceIndex
+ );
return {
rules_installed: rulesToInstall.length,
rules_updated: rulesToUpdate.length,
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts
index 9c18f9040008c..00a1d2eb980ec 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts
@@ -55,7 +55,6 @@ export const createCreateRulesBulkRoute = (server: ServerFacade): Hapi.ServerRou
enabled,
false_positives: falsePositives,
from,
- immutable,
query,
language,
output_index: outputIndex,
@@ -109,7 +108,7 @@ export const createCreateRulesBulkRoute = (server: ServerFacade): Hapi.ServerRou
enabled,
falsePositives,
from,
- immutable,
+ immutable: false,
query,
language,
outputIndex: finalIndex,
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
index aa535d325f4b9..23acd12d341ed 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts
@@ -39,7 +39,6 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute =
enabled,
false_positives: falsePositives,
from,
- immutable,
query,
language,
output_index: outputIndex,
@@ -96,7 +95,7 @@ export const createCreateRulesRoute = (server: ServerFacade): Hapi.ServerRoute =
enabled,
falsePositives,
from,
- immutable,
+ immutable: false,
query,
language,
outputIndex: finalIndex,
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts
index e56c440f5a415..545c2e488b1c8 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/find_rules_status_route.ts
@@ -13,10 +13,16 @@ import { findRulesStatusesSchema } from '../schemas/find_rules_statuses_schema';
import {
FindRulesStatusesRequest,
IRuleSavedAttributesSavedObjectAttributes,
+ RuleStatusResponse,
+ IRuleStatusAttributes,
} from '../../rules/types';
import { ruleStatusSavedObjectType } from '../../rules/saved_object_mappings';
-const convertToSnakeCase = (obj: IRuleSavedAttributesSavedObjectAttributes) => {
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const convertToSnakeCase = >(obj: T): Partial | null => {
+ if (!obj) {
+ return null;
+ }
return Object.keys(obj).reduce((acc, item) => {
const newKey = snakeCase(item);
return { ...acc, [newKey]: obj[item] };
@@ -53,7 +59,7 @@ export const createFindRulesStatusRoute: Hapi.ServerRoute = {
"anotherAlertId": ...
}
*/
- const statuses = await query.ids.reduce(async (acc, id) => {
+ const statuses = await query.ids.reduce>(async (acc, id) => {
const lastFiveErrorsForId = await savedObjectsClient.find<
IRuleSavedAttributesSavedObjectAttributes
>({
@@ -64,15 +70,21 @@ export const createFindRulesStatusRoute: Hapi.ServerRoute = {
search: id,
searchFields: ['alertId'],
});
- const toDisplay =
- lastFiveErrorsForId.saved_objects.length <= 5
- ? lastFiveErrorsForId.saved_objects
- : lastFiveErrorsForId.saved_objects.slice(1);
+ const accumulated = await acc;
+ const currentStatus = convertToSnakeCase(
+ lastFiveErrorsForId.saved_objects[0]?.attributes
+ );
+ const failures = lastFiveErrorsForId.saved_objects
+ .slice(1)
+ .map(errorItem => convertToSnakeCase(errorItem.attributes));
return {
- ...(await acc),
- [id]: toDisplay.map(errorItem => convertToSnakeCase(errorItem.attributes)),
+ ...accumulated,
+ [id]: {
+ current_status: currentStatus,
+ failures,
+ },
};
- }, {});
+ }, Promise.resolve({}));
return statuses;
},
};
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts
index e312b5fc6bb10..6efaa1fea60d0 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts
@@ -52,8 +52,10 @@ export const createImportRulesRoute = (server: ServerFacade): Hapi.ServerRoute =
const actionsClient = isFunction(request.getActionsClient)
? request.getActionsClient()
: null;
-
- if (!alertsClient || !actionsClient) {
+ const savedObjectsClient = isFunction(request.getSavedObjectsClient)
+ ? request.getSavedObjectsClient()
+ : null;
+ if (!alertsClient || !actionsClient || !savedObjectsClient) {
return headers.response().code(404);
}
const { filename } = request.payload.file.hapi;
@@ -161,6 +163,7 @@ export const createImportRulesRoute = (server: ServerFacade): Hapi.ServerRoute =
const updatedRule = await updateRules({
alertsClient,
actionsClient,
+ savedObjectsClient,
description,
enabled,
falsePositives,
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts
index 180a75bdaaeea..e0d2672cf356a 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts
@@ -7,12 +7,16 @@
import Hapi from 'hapi';
import { isFunction } from 'lodash/fp';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
-import { BulkUpdateRulesRequest } from '../../rules/types';
+import {
+ BulkUpdateRulesRequest,
+ IRuleSavedAttributesSavedObjectAttributes,
+} from '../../rules/types';
import { ServerFacade } from '../../../../types';
import { transformOrBulkError, getIdBulkError } from './utils';
import { transformBulkError } from '../utils';
import { updateRulesBulkSchema } from '../schemas/update_rules_bulk_schema';
import { updateRules } from '../../rules/update_rules';
+import { ruleStatusSavedObjectType } from '../../rules/saved_object_mappings';
export const createUpdateRulesBulkRoute = (server: ServerFacade): Hapi.ServerRoute => {
return {
@@ -32,8 +36,10 @@ export const createUpdateRulesBulkRoute = (server: ServerFacade): Hapi.ServerRou
const actionsClient = isFunction(request.getActionsClient)
? request.getActionsClient()
: null;
-
- if (!alertsClient || !actionsClient) {
+ const savedObjectsClient = isFunction(request.getSavedObjectsClient)
+ ? request.getSavedObjectsClient()
+ : null;
+ if (!alertsClient || !actionsClient || !savedObjectsClient) {
return headers.response().code(404);
}
@@ -44,7 +50,6 @@ export const createUpdateRulesBulkRoute = (server: ServerFacade): Hapi.ServerRou
enabled,
false_positives: falsePositives,
from,
- immutable,
query,
language,
output_index: outputIndex,
@@ -77,11 +82,11 @@ export const createUpdateRulesBulkRoute = (server: ServerFacade): Hapi.ServerRou
enabled,
falsePositives,
from,
- immutable,
query,
language,
outputIndex,
savedId,
+ savedObjectsClient,
timelineId,
timelineTitle,
meta,
@@ -102,7 +107,17 @@ export const createUpdateRulesBulkRoute = (server: ServerFacade): Hapi.ServerRou
version,
});
if (rule != null) {
- return transformOrBulkError(rule.id, rule);
+ const ruleStatuses = await savedObjectsClient.find<
+ IRuleSavedAttributesSavedObjectAttributes
+ >({
+ type: ruleStatusSavedObjectType,
+ perPage: 1,
+ sortField: 'statusDate',
+ sortOrder: 'desc',
+ search: rule.id,
+ searchFields: ['alertId'],
+ });
+ return transformOrBulkError(rule.id, rule, ruleStatuses.saved_objects[0]);
} else {
return getIdBulkError({ id, ruleId });
}
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
index 147f3f9afa549..49c9304ae2d25 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts
@@ -33,7 +33,6 @@ export const createUpdateRulesRoute: Hapi.ServerRoute = {
enabled,
false_positives: falsePositives,
from,
- immutable,
query,
language,
output_index: outputIndex,
@@ -75,11 +74,11 @@ export const createUpdateRulesRoute: Hapi.ServerRoute = {
enabled,
falsePositives,
from,
- immutable,
query,
language,
outputIndex,
savedId,
+ savedObjectsClient,
timelineId,
timelineTitle,
meta,
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts
index 1993948808ef4..abdd5a0c7b508 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts
@@ -4,20 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { UpdateRuleAlertParamsRest } from '../../rules/types';
-import { ThreatParams, RuleAlertParamsRest } from '../../types';
+import { ThreatParams, PrepackagedRules } from '../../types';
import { addPrepackagedRulesSchema } from './add_prepackaged_rules_schema';
describe('add prepackaged rules schema', () => {
test('empty objects do not validate', () => {
- expect(
- addPrepackagedRulesSchema.validate>({}).error
- ).toBeTruthy();
+ expect(addPrepackagedRulesSchema.validate>({}).error).toBeTruthy();
});
test('made up values do not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
madeUp: 'hi',
}).error
).toBeTruthy();
@@ -25,7 +22,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
}).error
).toBeTruthy();
@@ -33,7 +30,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
}).error
@@ -42,7 +39,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -52,7 +49,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -63,7 +60,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, name] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -75,7 +72,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, name, severity] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -88,7 +85,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, name, severity, type] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -102,7 +99,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -117,7 +114,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -133,7 +130,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, name, severity, type, query, index, interval, version] does validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -152,7 +149,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does not validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -170,7 +167,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, version] does validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -190,7 +187,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, output_index] does not validate because output_index is not allowed', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -211,7 +208,7 @@ describe('add prepackaged rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, version] does validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -229,7 +226,7 @@ describe('add prepackaged rules schema', () => {
test('You can send in an empty array to threats', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -251,7 +248,7 @@ describe('add prepackaged rules schema', () => {
});
test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, version, threats] does validate', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -286,7 +283,7 @@ describe('add prepackaged rules schema', () => {
test('allows references to be sent as valid', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -307,7 +304,7 @@ describe('add prepackaged rules schema', () => {
test('defaults references to an array', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -327,7 +324,7 @@ describe('add prepackaged rules schema', () => {
test('defaults immutable to true', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -347,7 +344,7 @@ describe('add prepackaged rules schema', () => {
test('immutable cannot be false', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -368,7 +365,7 @@ describe('add prepackaged rules schema', () => {
test('immutable can be true', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -389,7 +386,7 @@ describe('add prepackaged rules schema', () => {
test('defaults enabled to false', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -409,7 +406,7 @@ describe('add prepackaged rules schema', () => {
test('rule_id is required', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
risk_score: 50,
description: 'some description',
from: 'now-5m',
@@ -429,7 +426,7 @@ describe('add prepackaged rules schema', () => {
test('references cannot be numbers', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & { references: number[] }
+ Partial> & { references: number[] }
>({
rule_id: 'rule-1',
risk_score: 50,
@@ -454,7 +451,7 @@ describe('add prepackaged rules schema', () => {
test('indexes cannot be numbers', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & { index: number[] }
+ Partial> & { index: number[] }
>({
rule_id: 'rule-1',
risk_score: 50,
@@ -477,7 +474,7 @@ describe('add prepackaged rules schema', () => {
test('defaults interval to 5 min', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -494,7 +491,7 @@ describe('add prepackaged rules schema', () => {
test('defaults max signals to 100', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -512,7 +509,7 @@ describe('add prepackaged rules schema', () => {
test('saved_id is required when type is saved_query and will not validate without out', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -530,7 +527,7 @@ describe('add prepackaged rules schema', () => {
test('saved_id is required when type is saved_query and validates with it', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -549,7 +546,7 @@ describe('add prepackaged rules schema', () => {
test('saved_query type can have filters with it', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -570,7 +567,7 @@ describe('add prepackaged rules schema', () => {
test('filters cannot be a string', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial & { filters: string }>
+ Partial & { filters: string }>
>({
rule_id: 'rule-1',
risk_score: 50,
@@ -591,7 +588,7 @@ describe('add prepackaged rules schema', () => {
test('language validates with kuery', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -612,7 +609,7 @@ describe('add prepackaged rules schema', () => {
test('language validates with lucene', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -633,7 +630,7 @@ describe('add prepackaged rules schema', () => {
test('language does not validate with something made up', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -654,7 +651,7 @@ describe('add prepackaged rules schema', () => {
test('max_signals cannot be negative', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -676,7 +673,7 @@ describe('add prepackaged rules schema', () => {
test('max_signals cannot be zero', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -698,7 +695,7 @@ describe('add prepackaged rules schema', () => {
test('max_signals can be 1', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -720,7 +717,7 @@ describe('add prepackaged rules schema', () => {
test('You can optionally send in an array of tags', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -744,7 +741,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot send in an array of tags that are numbers', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & { tags: number[] }
+ Partial> & { tags: number[] }
>({
rule_id: 'rule-1',
risk_score: 50,
@@ -771,7 +768,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot send in an array of threats that are missing "framework"', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & {
+ Partial> & {
threats: Array>>;
}
>({
@@ -815,7 +812,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot send in an array of threats that are missing "tactic"', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & {
+ Partial> & {
threats: Array>>;
}
>({
@@ -855,7 +852,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot send in an array of threats that are missing "techniques"', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & {
+ Partial> & {
threats: Array>>;
}
>({
@@ -892,7 +889,7 @@ describe('add prepackaged rules schema', () => {
test('You can optionally send in an array of false positives', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -916,7 +913,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot send in an array of false positives that are numbers', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & { false_positives: number[] }
+ Partial> & { false_positives: number[] }
>({
rule_id: 'rule-1',
risk_score: 50,
@@ -942,7 +939,7 @@ describe('add prepackaged rules schema', () => {
test('You can optionally set the immutable to be true', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -966,7 +963,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot set the immutable to be a number', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial> & { immutable: number }
+ Partial> & { immutable: number }
>({
rule_id: 'rule-1',
risk_score: 50,
@@ -990,7 +987,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot set the risk_score to 101', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 101,
description: 'some description',
@@ -1013,7 +1010,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot set the risk_score to -1', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: -1,
description: 'some description',
@@ -1036,7 +1033,7 @@ describe('add prepackaged rules schema', () => {
test('You can set the risk_score to 0', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 0,
description: 'some description',
@@ -1059,7 +1056,7 @@ describe('add prepackaged rules schema', () => {
test('You can set the risk_score to 100', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 100,
description: 'some description',
@@ -1082,7 +1079,7 @@ describe('add prepackaged rules schema', () => {
test('You can set meta to any object you want', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1109,7 +1106,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot create meta as a string', () => {
expect(
addPrepackagedRulesSchema.validate<
- Partial & { meta: string }>
+ Partial & { meta: string }>
>({
rule_id: 'rule-1',
risk_score: 50,
@@ -1134,7 +1131,7 @@ describe('add prepackaged rules schema', () => {
test('You can omit the query string when filters are present', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1157,7 +1154,7 @@ describe('add prepackaged rules schema', () => {
test('validates with timeline_id and timeline_title', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1180,7 +1177,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot omit timeline_title when timeline_id is present', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1204,7 +1201,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot have a null value for timeline_title when timeline_id is present', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1229,7 +1226,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot have empty string for timeline_title when timeline_id is present', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1254,7 +1251,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot have timeline_title with an empty timeline_id', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -1279,7 +1276,7 @@ describe('add prepackaged rules schema', () => {
test('You cannot have timeline_title without timeline_id', () => {
expect(
- addPrepackagedRulesSchema.validate>({
+ addPrepackagedRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts
index 15f4fa7f05648..c76071047434c 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts
@@ -884,7 +884,6 @@ describe('create rules schema', () => {
description: 'some description',
from: 'now-5m',
to: 'now',
- immutable: true,
index: ['index-1'],
name: 'some-name',
severity: 'severity',
@@ -907,7 +906,6 @@ describe('create rules schema', () => {
description: 'some description',
from: 'now-5m',
to: 'now',
- immutable: true,
index: ['index-1'],
name: 'some-name',
severity: 'severity',
@@ -999,7 +997,6 @@ describe('create rules schema', () => {
description: 'some description',
from: 'now-5m',
to: 'now',
- immutable: true,
index: ['index-1'],
name: 'some-name',
severity: 'severity',
diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts
index bed64cc6e7a02..20f418c57b5db 100644
--- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts
+++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts
@@ -9,18 +9,18 @@ import {
importRulesQuerySchema,
importRulesPayloadSchema,
} from './import_rules_schema';
-import { ThreatParams, RuleAlertParamsRest, ImportRuleAlertRest } from '../../types';
+import { ThreatParams, ImportRuleAlertRest } from '../../types';
import { ImportRulesRequest } from '../../rules/types';
describe('import rules schema', () => {
describe('importRulesSchema', () => {
test('empty objects do not validate', () => {
- expect(importRulesSchema.validate>({}).error).toBeTruthy();
+ expect(importRulesSchema.validate>({}).error).toBeTruthy();
});
test('made up values do not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
madeUp: 'hi',
}).error
).toBeTruthy();
@@ -28,7 +28,7 @@ describe('import rules schema', () => {
test('[rule_id] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
}).error
).toBeTruthy();
@@ -36,7 +36,7 @@ describe('import rules schema', () => {
test('[rule_id, description] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
}).error
@@ -45,7 +45,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -55,7 +55,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -66,7 +66,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, name] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -78,7 +78,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, name, severity] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -91,7 +91,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, name, severity, type] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -105,7 +105,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -120,7 +120,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -136,7 +136,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, name, severity, type, query, index, interval] does validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -154,7 +154,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does not validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -172,7 +172,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score] does validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
description: 'some description',
@@ -191,7 +191,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, output_index] does validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -211,7 +211,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score] does validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
description: 'some description',
from: 'now-5m',
@@ -228,7 +228,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index] does validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -246,7 +246,7 @@ describe('import rules schema', () => {
test('You can send in an empty array to threats', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -269,7 +269,7 @@ describe('import rules schema', () => {
test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index, threats] does validate', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -304,7 +304,7 @@ describe('import rules schema', () => {
test('allows references to be sent as valid', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -325,7 +325,7 @@ describe('import rules schema', () => {
test('defaults references to an array', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -346,7 +346,7 @@ describe('import rules schema', () => {
test('references cannot be numbers', () => {
expect(
importRulesSchema.validate<
- Partial> & { references: number[] }
+ Partial> & { references: number[] }
>({
rule_id: 'rule-1',
output_index: '.siem-signals',
@@ -371,7 +371,7 @@ describe('import rules schema', () => {
test('indexes cannot be numbers', () => {
expect(
importRulesSchema.validate<
- Partial> & { index: number[] }
+ Partial> & { index: number[] }
>({
rule_id: 'rule-1',
output_index: '.siem-signals',
@@ -394,7 +394,7 @@ describe('import rules schema', () => {
test('defaults interval to 5 min', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -411,7 +411,7 @@ describe('import rules schema', () => {
test('defaults max signals to 100', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -429,7 +429,7 @@ describe('import rules schema', () => {
test('saved_id is required when type is saved_query and will not validate without out', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -447,7 +447,7 @@ describe('import rules schema', () => {
test('saved_id is required when type is saved_query and validates with it', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
output_index: '.siem-signals',
@@ -466,7 +466,7 @@ describe('import rules schema', () => {
test('saved_query type can have filters with it', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -487,7 +487,7 @@ describe('import rules schema', () => {
test('filters cannot be a string', () => {
expect(
importRulesSchema.validate<
- Partial & { filters: string }>
+ Partial & { filters: string }>
>({
rule_id: 'rule-1',
output_index: '.siem-signals',
@@ -508,7 +508,7 @@ describe('import rules schema', () => {
test('language validates with kuery', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -529,7 +529,7 @@ describe('import rules schema', () => {
test('language validates with lucene', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
risk_score: 50,
output_index: '.siem-signals',
@@ -550,7 +550,7 @@ describe('import rules schema', () => {
test('language does not validate with something made up', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -571,7 +571,7 @@ describe('import rules schema', () => {
test('max_signals cannot be negative', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -593,7 +593,7 @@ describe('import rules schema', () => {
test('max_signals cannot be zero', () => {
expect(
- importRulesSchema.validate>({
+ importRulesSchema.validate>({
rule_id: 'rule-1',
output_index: '.siem-signals',
risk_score: 50,
@@ -615,7 +615,7 @@ describe('import rules schema', () => {
test('max_signals can be 1', () => {
expect(
- importRulesSchema.validate |