diff --git a/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_components.tsx b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_components.tsx
index d5a3cfdefe64..82d4c5b5a3e2 100644
--- a/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_components.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_components.tsx
@@ -22,3 +22,10 @@ export const DetectionsRequirementsLink = () => (
linkText={i18n.DETECTIONS_REQUIREMENTS_LINK_TEXT}
/>
);
+
+export const MlJobCompatibilityLink = () => (
+
+);
diff --git a/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_translations.ts b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_translations.ts
index fc38899e7ff8..a495d95b3cf3 100644
--- a/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_translations.ts
+++ b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_translations.ts
@@ -33,3 +33,11 @@ export const DETECTIONS_REQUIREMENTS_LINK_TEXT = i18n.translate(
defaultMessage: 'Detections prerequisites and requirements',
}
);
+
+export const ML_JOB_COMPATIBILITY_LINK_PATH = 'alerts-ui-monitor.html#ml-job-compatibility';
+export const ML_JOB_COMPATIBILITY_LINK_TEXT = i18n.translate(
+ 'xpack.securitySolution.documentationLinks.mlJobCompatibility.text',
+ {
+ defaultMessage: 'ML job compatibility',
+ }
+);
diff --git a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts
index 605fc6c09a94..7bdad2514c82 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts
+++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts
@@ -31,7 +31,7 @@ export interface UseInstalledSecurityJobsReturn {
* necessary (running jobs, etc).
*
* NOTE: If you need to include jobs that are not currently installed, try the
- * {@link useInstalledSecurityJobs} hook.
+ * {@link useSecurityJobs} hook.
*
*/
export const useInstalledSecurityJobs = (): UseInstalledSecurityJobsReturn => {
diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/affected_job_ids.ts b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/affected_job_ids.ts
new file mode 100644
index 000000000000..8228a5c314c2
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/affected_job_ids.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+// These are the job IDs of ML jobs that are dependent on specific ECS data. If
+// any of them is installed, we want to notify the user that they potentially
+// have incompatibility between their beats, rules, and jobs.
+// There are four modules of jobs that are affected. However, because the API
+// that returns installed jobs does not include those jobs' modules, hardcoding
+// the IDs from those modules (as found in e.g.
+// x-pack/plugins/ml/server/models/data_recognizer/modules/security_windows/manifest.json)
+// allows us to make this determination from a single API call.
+export const affectedJobIds: string[] = [
+ // security_linux module
+ 'v2_rare_process_by_host_linux_ecs',
+ 'v2_linux_rare_metadata_user',
+ 'v2_linux_rare_metadata_process',
+ 'v2_linux_anomalous_user_name_ecs',
+ 'v2_linux_anomalous_process_all_hosts_ecs',
+ 'v2_linux_anomalous_network_port_activity_ecs',
+ // security_windows module
+ 'v2_rare_process_by_host_windows_ecs',
+ 'v2_windows_anomalous_network_activity_ecs',
+ 'v2_windows_anomalous_path_activity_ecs',
+ 'v2_windows_anomalous_process_all_hosts_ecs',
+ 'v2_windows_anomalous_process_creation',
+ 'v2_windows_anomalous_user_name_ecs',
+ 'v2_windows_rare_metadata_process',
+ 'v2_windows_rare_metadata_user',
+ // siem_auditbeat module
+ 'rare_process_by_host_linux_ecs',
+ 'linux_anomalous_network_activity_ecs',
+ 'linux_anomalous_network_port_activity_ecs',
+ 'linux_anomalous_network_service',
+ 'linux_anomalous_network_url_activity_ecs',
+ 'linux_anomalous_process_all_hosts_ecs',
+ 'linux_anomalous_user_name_ecs',
+ 'linux_rare_metadata_process',
+ 'linux_rare_metadata_user',
+ 'linux_rare_user_compiler',
+ 'linux_rare_kernel_module_arguments',
+ 'linux_rare_sudo_user',
+ 'linux_system_user_discovery',
+ 'linux_system_information_discovery',
+ 'linux_system_process_discovery',
+ 'linux_network_connection_discovery',
+ 'linux_network_configuration_discovery',
+ // siem_winlogbeat module
+ 'rare_process_by_host_windows_ecs',
+ 'windows_anomalous_network_activity_ecs',
+ 'windows_anomalous_path_activity_ecs',
+ 'windows_anomalous_process_all_hosts_ecs',
+ 'windows_anomalous_process_creation',
+ 'windows_anomalous_script',
+ 'windows_anomalous_service',
+ 'windows_anomalous_user_name_ecs',
+ 'windows_rare_user_runas_event',
+ 'windows_rare_metadata_process',
+ 'windows_rare_metadata_user',
+];
diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.test.tsx
new file mode 100644
index 000000000000..23f6eea435d7
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.test.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { mount } from 'enzyme';
+import React from 'react';
+
+import { TestProviders } from '../../../../common/mock';
+import { useInstalledSecurityJobs } from '../../../../common/components/ml/hooks/use_installed_security_jobs';
+import { MlJobCompatibilityCallout } from './index';
+
+jest.mock('../../../../common/components/ml/hooks/use_installed_security_jobs');
+
+describe('MlJobCompatibilityCallout', () => {
+ it('renders when new affected jobs are installed', () => {
+ (useInstalledSecurityJobs as jest.Mock).mockReturnValue({
+ loading: false,
+ jobs: [{ id: 'v2_linux_rare_metadata_process' }],
+ });
+ const wrapper = mount(
+
+
+
+ );
+ expect(wrapper.exists('[data-test-subj="callout-ml-job-compatibility"]')).toEqual(true);
+ });
+
+ it('renders when old affected jobs are installed', () => {
+ (useInstalledSecurityJobs as jest.Mock).mockReturnValue({
+ loading: false,
+ jobs: [{ id: 'linux_rare_metadata_process' }],
+ });
+ const wrapper = mount(
+
+
+
+ );
+ expect(wrapper.exists('[data-test-subj="callout-ml-job-compatibility"]')).toEqual(true);
+ });
+
+ it('does not render if no affected jobs are installed', () => {
+ (useInstalledSecurityJobs as jest.Mock).mockReturnValue({
+ loading: false,
+ jobs: [{ id: 'windows_rare_user_type10_remote_login' }],
+ });
+ const wrapper = mount(
+
+
+
+ );
+ expect(wrapper.exists('[data-test-subj="callout-ml-job-compatibility"]')).toEqual(false);
+ });
+
+ it('does not render while jobs are loading', () => {
+ (useInstalledSecurityJobs as jest.Mock).mockReturnValue({
+ loading: true,
+ jobs: [],
+ });
+ const wrapper = mount(
+
+
+
+ );
+ expect(wrapper.exists('[data-test-subj="callout-ml-job-compatibility"]')).toEqual(false);
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.tsx
new file mode 100644
index 000000000000..ff266cfd859b
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React, { memo } from 'react';
+
+import { CallOutMessage, CallOutSwitcher } from '../../../../common/components/callouts';
+import { useInstalledSecurityJobs } from '../../../../common/components/ml/hooks/use_installed_security_jobs';
+import { affectedJobIds } from './affected_job_ids';
+import * as i18n from './translations';
+
+const mlJobCompatibilityCalloutMessage: CallOutMessage = {
+ type: 'primary',
+ id: 'ml-job-compatibility',
+ title: i18n.ML_JOB_COMPATIBILITY_CALLOUT_TITLE,
+ description: ,
+};
+
+const MlJobCompatibilityCalloutComponent = () => {
+ const { loading, jobs } = useInstalledSecurityJobs();
+ const newJobsInstalled = jobs.some((job) => affectedJobIds.includes(job.id));
+
+ return (
+
+ );
+};
+
+export const MlJobCompatibilityCallout = memo(MlJobCompatibilityCalloutComponent);
diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/translations.tsx
new file mode 100644
index 000000000000..35ffdb6f7abf
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/translations.tsx
@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { MlJobCompatibilityLink } from '../../../../common/components/links_to_docs';
+
+export const ML_JOB_COMPATIBILITY_CALLOUT_TITLE = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.mlJobCompatibilityCallout.messageTitle',
+ {
+ defaultMessage: 'Your ML jobs may be incompatible with your data sources and/or ML rules',
+ }
+);
+
+export const MlJobCompatibilityCalloutBody = () => (
+
+
+
+ ),
+ docs: (
+
+ ),
+ }}
+ />
+);
diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx
index 89cec1685101..57566986e47d 100644
--- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx
+++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx
@@ -36,6 +36,7 @@ import { SecurityPageName } from '../../../../app/types';
import { LinkButton } from '../../../../common/components/links';
import { useFormatUrl } from '../../../../common/components/link_to';
import { NeedAdminForUpdateRulesCallOut } from '../../../components/callouts/need_admin_for_update_callout';
+import { MlJobCompatibilityCallout } from '../../../components/callouts/ml_job_compatibility_callout';
type Func = () => Promise;
@@ -161,6 +162,7 @@ const RulesPageComponent: React.FC = () => {
<>
+
setShowValueListsModal(false)}