mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution] Display unavailable ML jobs (#205483)](https://github.com/elastic/kibana/pull/205483) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Nikita Indik","email":"nikita.indik@elastic.co"},"sourceCommit":{"committedDate":"2025-01-06T12:33:10Z","message":"[Security Solution] Display unavailable ML jobs (#205483)\n\n**Resolves: https://github.com/elastic/kibana/issues/202700**\n\n## Summary\nThis PR resolves an issue where an ML job referenced by a rule does not\nappear in the Rule Details, Upgrade flyout, or Rule Editing pages if the\njob is missing or not yet created.\n\nFor example, if you had an ML rule with a single selected job and this\njob was not available, you would see a blank space instead of job name.\n\n## Screenshots\n**Rule Details: Before**\n<img width=\"578\" alt=\"Schermafbeelding 2025-01-03 om 13 20 32\"\nsrc=\"https://github.com/user-attachments/assets/e8bc073f-0420-4888-8dd9-b4dc70fd0682\"\n/>\n\n**Rule Details: After**\n<img width=\"578\" alt=\"Schermafbeelding 2025-01-03 om 13 20 05\"\nsrc=\"https://github.com/user-attachments/assets/bd4d0f91-8adf-45c5-8d31-b42ac483027b\"\n/>\n\n**Rule Edit: Before**\n<img width=\"427\" alt=\"Schermafbeelding 2025-01-03 om 13 21 21\"\nsrc=\"https://github.com/user-attachments/assets/bffcb871-8cfc-4f50-8d19-c14b122c0be4\"\n/>\n\n**Rule Edit: After**\n<img width=\"427\" alt=\"Schermafbeelding 2025-01-03 om 13 21 09\"\nsrc=\"https://github.com/user-attachments/assets/be8f60b9-17a6-48d2-978c-cfa63c426a08\"\n/>\n\n**Upgrade flyout: Before**\n<img width=\"1066\" alt=\"Schermafbeelding 2025-01-03 om 13 22 30\"\nsrc=\"https://github.com/user-attachments/assets/553ff837-95cf-4670-91f1-dffb169ec505\"\n/>\n\n**Upgrade flyout: After**\n<img width=\"1066\" alt=\"Schermafbeelding 2025-01-03 om 13 21 55\"\nsrc=\"https://github.com/user-attachments/assets/150cfb82-bc69-4aeb-a20a-03f54c7edc70\"\n/>\n\n## Testing\nYou can test by removing an ML job referenced by a rule in\n`http://localhost:<port>/kbn/app/ml/jobs`.","sha":"e04b20018a441e679848e114df68ba688976c83c","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Detections and Resp","Team: SecuritySolution","Team:Detection Rule Management","Feature:Prebuilt Detection Rules","Feature:Rule Creation","Feature:Rule Details","Feature:Rule Edit","backport:version","v8.18.0"],"title":"[Security Solution] Display unavailable ML jobs","number":205483,"url":"https://github.com/elastic/kibana/pull/205483","mergeCommit":{"message":"[Security Solution] Display unavailable ML jobs (#205483)\n\n**Resolves: https://github.com/elastic/kibana/issues/202700**\n\n## Summary\nThis PR resolves an issue where an ML job referenced by a rule does not\nappear in the Rule Details, Upgrade flyout, or Rule Editing pages if the\njob is missing or not yet created.\n\nFor example, if you had an ML rule with a single selected job and this\njob was not available, you would see a blank space instead of job name.\n\n## Screenshots\n**Rule Details: Before**\n<img width=\"578\" alt=\"Schermafbeelding 2025-01-03 om 13 20 32\"\nsrc=\"https://github.com/user-attachments/assets/e8bc073f-0420-4888-8dd9-b4dc70fd0682\"\n/>\n\n**Rule Details: After**\n<img width=\"578\" alt=\"Schermafbeelding 2025-01-03 om 13 20 05\"\nsrc=\"https://github.com/user-attachments/assets/bd4d0f91-8adf-45c5-8d31-b42ac483027b\"\n/>\n\n**Rule Edit: Before**\n<img width=\"427\" alt=\"Schermafbeelding 2025-01-03 om 13 21 21\"\nsrc=\"https://github.com/user-attachments/assets/bffcb871-8cfc-4f50-8d19-c14b122c0be4\"\n/>\n\n**Rule Edit: After**\n<img width=\"427\" alt=\"Schermafbeelding 2025-01-03 om 13 21 09\"\nsrc=\"https://github.com/user-attachments/assets/be8f60b9-17a6-48d2-978c-cfa63c426a08\"\n/>\n\n**Upgrade flyout: Before**\n<img width=\"1066\" alt=\"Schermafbeelding 2025-01-03 om 13 22 30\"\nsrc=\"https://github.com/user-attachments/assets/553ff837-95cf-4670-91f1-dffb169ec505\"\n/>\n\n**Upgrade flyout: After**\n<img width=\"1066\" alt=\"Schermafbeelding 2025-01-03 om 13 21 55\"\nsrc=\"https://github.com/user-attachments/assets/150cfb82-bc69-4aeb-a20a-03f54c7edc70\"\n/>\n\n## Testing\nYou can test by removing an ML job referenced by a rule in\n`http://localhost:<port>/kbn/app/ml/jobs`.","sha":"e04b20018a441e679848e114df68ba688976c83c"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/205483","number":205483,"mergeCommit":{"message":"[Security Solution] Display unavailable ML jobs (#205483)\n\n**Resolves: https://github.com/elastic/kibana/issues/202700**\n\n## Summary\nThis PR resolves an issue where an ML job referenced by a rule does not\nappear in the Rule Details, Upgrade flyout, or Rule Editing pages if the\njob is missing or not yet created.\n\nFor example, if you had an ML rule with a single selected job and this\njob was not available, you would see a blank space instead of job name.\n\n## Screenshots\n**Rule Details: Before**\n<img width=\"578\" alt=\"Schermafbeelding 2025-01-03 om 13 20 32\"\nsrc=\"https://github.com/user-attachments/assets/e8bc073f-0420-4888-8dd9-b4dc70fd0682\"\n/>\n\n**Rule Details: After**\n<img width=\"578\" alt=\"Schermafbeelding 2025-01-03 om 13 20 05\"\nsrc=\"https://github.com/user-attachments/assets/bd4d0f91-8adf-45c5-8d31-b42ac483027b\"\n/>\n\n**Rule Edit: Before**\n<img width=\"427\" alt=\"Schermafbeelding 2025-01-03 om 13 21 21\"\nsrc=\"https://github.com/user-attachments/assets/bffcb871-8cfc-4f50-8d19-c14b122c0be4\"\n/>\n\n**Rule Edit: After**\n<img width=\"427\" alt=\"Schermafbeelding 2025-01-03 om 13 21 09\"\nsrc=\"https://github.com/user-attachments/assets/be8f60b9-17a6-48d2-978c-cfa63c426a08\"\n/>\n\n**Upgrade flyout: Before**\n<img width=\"1066\" alt=\"Schermafbeelding 2025-01-03 om 13 22 30\"\nsrc=\"https://github.com/user-attachments/assets/553ff837-95cf-4670-91f1-dffb169ec505\"\n/>\n\n**Upgrade flyout: After**\n<img width=\"1066\" alt=\"Schermafbeelding 2025-01-03 om 13 21 55\"\nsrc=\"https://github.com/user-attachments/assets/150cfb82-bc69-4aeb-a20a-03f54c7edc70\"\n/>\n\n## Testing\nYou can test by removing an ML job referenced by a rule in\n`http://localhost:<port>/kbn/app/ml/jobs`.","sha":"e04b20018a441e679848e114df68ba688976c83c"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Nikita Indik <nikita.indik@elastic.co>
This commit is contained in:
parent
8f66e213cf
commit
b44cff196e
8 changed files with 86 additions and 28 deletions
|
@ -170,14 +170,6 @@
|
|||
"avcBanner.body": "Elastic Security passe avec brio le test de protection contre les malwares réalisé par AV-Comparatives",
|
||||
"avcBanner.readTheBlog.link": "Lire le blog",
|
||||
"avcBanner.title": "Protection à 100 % sans aucun faux positif.",
|
||||
"bfetch.advancedSettings.disableBfetchCompressionDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.",
|
||||
"bfetch.advancedSettings.disableBfetchDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.",
|
||||
"bfetch.disableBfetch": "Désactiver la mise en lots de requêtes",
|
||||
"bfetch.disableBfetchCompression": "Désactiver la compression par lots",
|
||||
"bfetch.disableBfetchCompressionDesc": "Vous pouvez désactiver la compression par lots. Cela permet de déboguer des requêtes individuelles, mais augmente la taille des réponses.",
|
||||
"bfetch.disableBfetchDesc": "Désactive la mise en lot des requêtes. Cette option augmente le nombre de requêtes HTTP depuis Kibana, mais permet de les déboguer individuellement.",
|
||||
"bfetchError.networkError": "Vérifiez votre connexion réseau et réessayez.",
|
||||
"bfetchError.networkErrorWithStatus": "Vérifiez votre connexion réseau et réessayez. Code {code}",
|
||||
"cases.components.status.closed": "Fermé",
|
||||
"cases.components.status.inProgress": "En cours",
|
||||
"cases.components.status.open": "Ouvrir",
|
||||
|
|
|
@ -170,14 +170,6 @@
|
|||
"avcBanner.body": "AV-Comparativesのマルウェア保護テストで高い評価を受けたElastic Security",
|
||||
"avcBanner.readTheBlog.link": "ブログを読む",
|
||||
"avcBanner.title": "誤検知がゼロの100%保護。",
|
||||
"bfetch.advancedSettings.disableBfetchCompressionDeprecation": "この設定はサポートが終了し、Kibana 9.0では削除されます。",
|
||||
"bfetch.advancedSettings.disableBfetchDeprecation": "この設定はサポートが終了し、Kibana 9.0では削除されます。",
|
||||
"bfetch.disableBfetch": "リクエストバッチを無効にする",
|
||||
"bfetch.disableBfetchCompression": "バッチ圧縮を無効にする",
|
||||
"bfetch.disableBfetchCompressionDesc": "バッチ圧縮を無効にします。個別の要求をデバッグできますが、応答サイズが大きくなります。",
|
||||
"bfetch.disableBfetchDesc": "リクエストバッチを無効にします。これにより、KibanaからのHTTPリクエスト数は減りますが、個別にリクエストをデバッグできます。",
|
||||
"bfetchError.networkError": "ネットワーク接続を確認して再試行してください。",
|
||||
"bfetchError.networkErrorWithStatus": "ネットワーク接続を確認して再試行してください。コード{code}",
|
||||
"cases.components.status.closed": "終了",
|
||||
"cases.components.status.inProgress": "進行中",
|
||||
"cases.components.status.open": "オープン",
|
||||
|
|
|
@ -198,14 +198,6 @@
|
|||
"avcBanner.body": "在 AV-Comparatives 进行的恶意软件防护测试中,Elastic Security 表现突出",
|
||||
"avcBanner.readTheBlog.link": "阅读博客",
|
||||
"avcBanner.title": "提供全面保护,误报率为零。",
|
||||
"bfetch.advancedSettings.disableBfetchCompressionDeprecation": "此设置已过时,将在 Kibana 9.0 中移除。",
|
||||
"bfetch.advancedSettings.disableBfetchDeprecation": "此设置已过时,将在 Kibana 9.0 中移除。",
|
||||
"bfetch.disableBfetch": "禁用请求批处理",
|
||||
"bfetch.disableBfetchCompression": "禁用批量压缩",
|
||||
"bfetch.disableBfetchCompressionDesc": "禁用批量压缩。这允许您对单个请求进行故障排查,但会增加响应大小。",
|
||||
"bfetch.disableBfetchDesc": "禁用请求批处理。这会增加来自 Kibana 的 HTTP 请求数,但允许对单个请求进行故障排查。",
|
||||
"bfetchError.networkError": "检查您的网络连接,然后重试。",
|
||||
"bfetchError.networkErrorWithStatus": "检查您的网络连接,然后重试。代码 {code}",
|
||||
"cases.components.status.closed": "已关闭",
|
||||
"cases.components.status.inProgress": "进行中",
|
||||
"cases.components.status.open": "打开",
|
||||
|
|
|
@ -21,7 +21,7 @@ describe('MlJobSelect', () => {
|
|||
|
||||
it('renders correctly', () => {
|
||||
const Component = () => {
|
||||
const field = useFormFieldMock<string[]>();
|
||||
const field = useFormFieldMock<string[]>({ value: [] });
|
||||
|
||||
return <MlJobSelect field={field} loading={false} jobs={[]} />;
|
||||
};
|
||||
|
|
|
@ -57,6 +57,21 @@ export const MlJobSelect: React.FC<MlJobSelectProps> = ({
|
|||
label: `${job.customSettings?.security_app_display_name} ${job.id}`,
|
||||
}));
|
||||
|
||||
// If rule's ML job is no longer available or has not yet become available, we still want it to appear in the dropdown.
|
||||
selectedJobIds.forEach((selectedJobId) => {
|
||||
const isSelectedJobAvailable = jobOptions.some((job) => job.value.id === selectedJobId);
|
||||
if (!isSelectedJobAvailable) {
|
||||
jobOptions.push({
|
||||
value: {
|
||||
id: selectedJobId,
|
||||
description: '',
|
||||
name: selectedJobId,
|
||||
},
|
||||
label: selectedJobId,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const selectedJobOptions = jobOptions
|
||||
.filter((option) => selectedJobIds.includes(option.value.id))
|
||||
// 'label' defines what is rendered inside the selected ComboBoxPill
|
||||
|
|
|
@ -9,6 +9,7 @@ import type { FC, ReactNode } from 'react';
|
|||
import React, { memo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
|
||||
import type { MlSummaryJob } from '@kbn/ml-plugin/public';
|
||||
import * as i18n from './translations';
|
||||
|
@ -21,6 +22,7 @@ import { MlJobStatusBadge } from '../ml_job_status_badge';
|
|||
|
||||
const Wrapper = styled.div`
|
||||
overflow: hidden;
|
||||
margin-bottom: ${euiThemeVars.euiSizeS};
|
||||
`;
|
||||
|
||||
const MlJobItemComponent: FC<{
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiFlexGroup,
|
||||
EuiLoadingSpinner,
|
||||
EuiButtonIcon,
|
||||
EuiPopover,
|
||||
} from '@elastic/eui';
|
||||
import type { EuiDescriptionListProps } from '@elastic/eui';
|
||||
import type {
|
||||
|
@ -24,6 +26,7 @@ import type { Filter } from '@kbn/es-query';
|
|||
import type { SavedQuery } from '@kbn/data-plugin/public';
|
||||
import { mapAndFlattenFilters } from '@kbn/data-plugin/public';
|
||||
import { FilterItems } from '@kbn/unified-search-plugin/public';
|
||||
import useToggle from 'react-use/lib/useToggle';
|
||||
import { isDataView } from '../../../../common/components/query_bar';
|
||||
import type {
|
||||
AlertSuppressionMissingFieldsStrategy,
|
||||
|
@ -237,7 +240,7 @@ interface MachineLearningJobListProps {
|
|||
}
|
||||
|
||||
export const MachineLearningJobList = ({ jobIds, isInteractive }: MachineLearningJobListProps) => {
|
||||
const { jobs } = useSecurityJobs();
|
||||
const { jobs: availableJobs } = useSecurityJobs();
|
||||
|
||||
if (!jobIds) {
|
||||
return null;
|
||||
|
@ -245,11 +248,20 @@ export const MachineLearningJobList = ({ jobIds, isInteractive }: MachineLearnin
|
|||
|
||||
const jobIdsArray = Array.isArray(jobIds) ? jobIds : [jobIds];
|
||||
|
||||
const unavailableJobIds = jobIdsArray.filter(
|
||||
(jobId) => !availableJobs.some((job) => job.id === jobId)
|
||||
);
|
||||
|
||||
if (isInteractive) {
|
||||
return <MlJobsDescription jobIds={jobIdsArray} />;
|
||||
return (
|
||||
<>
|
||||
<MlJobsDescription jobIds={jobIdsArray} />
|
||||
<UnavailableMlJobs unavailableJobIds={unavailableJobIds} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const relevantJobs = jobs.filter((job) => jobIdsArray.includes(job.id));
|
||||
const relevantJobs = availableJobs.filter((job) => jobIdsArray.includes(job.id));
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -260,10 +272,48 @@ export const MachineLearningJobList = ({ jobIds, isInteractive }: MachineLearnin
|
|||
jobName={job.customSettings?.security_app_display_name}
|
||||
/>
|
||||
))}
|
||||
<UnavailableMlJobs unavailableJobIds={unavailableJobIds} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface UnavailableMlJobsProps {
|
||||
unavailableJobIds: string[];
|
||||
}
|
||||
|
||||
const UnavailableMlJobs = ({ unavailableJobIds }: UnavailableMlJobsProps) => {
|
||||
return unavailableJobIds.map((jobId) => (
|
||||
<div key={jobId}>
|
||||
<UnavailableMlJobLink jobId={jobId} />
|
||||
</div>
|
||||
));
|
||||
};
|
||||
|
||||
interface UnavailableMlJobLinkProps {
|
||||
jobId: string;
|
||||
}
|
||||
|
||||
const UnavailableMlJobLink: React.FC<UnavailableMlJobLinkProps> = ({ jobId }) => {
|
||||
const [isPopoverOpen, togglePopover] = useToggle(false);
|
||||
|
||||
const button = (
|
||||
<EuiButtonIcon
|
||||
iconType="questionInCircle"
|
||||
onClick={togglePopover}
|
||||
aria-label={i18n.MACHINE_LEARNING_JOB_NOT_AVAILABLE}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiText component="span" color="subdued" size="s">
|
||||
{jobId}
|
||||
<EuiPopover button={button} isOpen={isPopoverOpen} closePopover={togglePopover}>
|
||||
{i18n.MACHINE_LEARNING_JOB_NOT_AVAILABLE}
|
||||
</EuiPopover>
|
||||
</EuiText>
|
||||
);
|
||||
};
|
||||
|
||||
const getRuleTypeDescription = (ruleType: Type) => {
|
||||
switch (ruleType) {
|
||||
case 'machine_learning':
|
||||
|
|
|
@ -273,6 +273,21 @@ export const MACHINE_LEARNING_JOB_ID_FIELD_LABEL = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const MACHINE_LEARNING_JOB_NOT_AVAILABLE = i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.ruleDetails.machineLearning.mlJobNotAvailable',
|
||||
{
|
||||
defaultMessage:
|
||||
'This job is currently unavailable. Please ensure that all related ML integrations are installed and configured.',
|
||||
}
|
||||
);
|
||||
|
||||
export const OPEN_HELP_POPOVER_ARIA_LABEL = i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.ruleDetails.machineLearning.mlJobNotAvailable.openHelpPopoverAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Open help popover',
|
||||
}
|
||||
);
|
||||
|
||||
export const ANOMALY_THRESHOLD_FIELD_LABEL = i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.ruleDetails.anomalyThresholdFieldLabel',
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue