From ca25160fd8e42100ba9c0e9769e584fd12b00f52 Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Mon, 11 Sep 2023 14:54:11 +0200 Subject: [PATCH 1/8] Refactor Rule Details page --- .../pages/rule_details/index.tsx | 26 +--- .../rule_details/rule_about_section.tsx | 81 +++++++----- .../rule_details/rule_definition_section.tsx | 123 ++++++++++++++++-- .../rule_details/rule_overview_tab.tsx | 5 +- .../components/rule_details/translations.ts | 28 ++++ .../rules/description_step/translations.ts | 7 + .../rules/step_about_rule_details/index.tsx | 11 +- 7 files changed, 210 insertions(+), 71 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index 97f02b8e35cf2..aadca25f8b480 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -63,8 +63,6 @@ import { SpyRoute } from '../../../../common/utils/route/spy_routes'; import { StepAboutRuleToggleDetails } from '../../../../detections/components/rules/step_about_rule_details'; import { AlertsHistogramPanel } from '../../../../detections/components/alerts_kpis/alerts_histogram_panel'; import { useUserData } from '../../../../detections/components/user_info'; -import { StepDefineRuleReadOnly } from '../../../../detections/components/rules/step_define_rule'; -import { StepScheduleRuleReadOnly } from '../../../../detections/components/rules/step_schedule_rule'; import { StepRuleActionsReadOnly } from '../../../../detections/components/rules/step_rule_actions'; import { buildAlertsFilter, @@ -140,6 +138,8 @@ import { RuleSnoozeBadge } from '../../../rule_management/components/rule_snooze import { useRuleIndexPattern } from '../../../rule_creation_ui/pages/form'; import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; import { useBoolState } from '../../../../common/hooks/use_bool_state'; +import { RuleDefinitionSection } from '../../../rule_management/components/rule_details/rule_definition_section'; +import { RuleScheduleSection } from '../../../rule_management/components/rule_details/rule_schedule_section'; // eslint-disable-next-line no-restricted-imports import { useLegacyUrlRedirect } from './use_redirect_legacy_url'; import { RuleDetailTabs, useRuleDetailsTabs } from './use_rule_details_tabs'; @@ -671,6 +671,7 @@ const RuleDetailsPageComponent: React.FC = ({ loading={isLoading} stepData={aboutRuleData} stepDataDetails={modifiedAboutRuleDetailsData} + rule={rule} /> @@ -681,30 +682,15 @@ const RuleDetailsPageComponent: React.FC = ({ loading={isLoading || isSavedQueryLoading} title={ruleI18n.DEFINITION} > - {defineRuleData != null && !isSavedQueryLoading && !isStartingJobs && ( - + {rule != null && !isSavedQueryLoading && !isStartingJobs && ( + )} - {scheduleRuleData != null && ( - - )} + {rule != null && } {hasActions && ( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx index aef4eccaa4299..7a133b3b81400 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx @@ -53,11 +53,17 @@ const StyledEuiLink = styled(EuiLink)` word-break: break-word; `; +interface NameProps { + name: string; +} + +const Name = ({ name }: NameProps) => {name}; + interface DescriptionProps { description: string; } -const Description = ({ description }: DescriptionProps) => ( +export const Description = ({ description }: DescriptionProps) => ( {description} ); @@ -217,10 +223,29 @@ interface TagsProps { const Tags = ({ tags }: TagsProps) => ; -const prepareAboutSectionListItems = (rule: RuleResponse): EuiDescriptionListProps['listItems'] => { +// eslint-disable-next-line complexity +const prepareAboutSectionListItems = ( + rule: Partial, + hideName?: boolean, + hideDescription?: boolean +): EuiDescriptionListProps['listItems'] => { const aboutSectionListItems: EuiDescriptionListProps['listItems'] = []; - if (rule.author.length > 0) { + if (!hideName && rule.name) { + aboutSectionListItems.push({ + title: i18n.NAME_FIELD_LABEL, + description: , + }); + } + + if (!hideDescription && rule.description) { + aboutSectionListItems.push({ + title: i18n.DESCRIPTION_FIELD_LABEL, + description: , + }); + } + + if (rule.author && rule.author.length > 0) { aboutSectionListItems.push({ title: i18n.AUTHOR_FIELD_LABEL, description: , @@ -234,12 +259,14 @@ const prepareAboutSectionListItems = (rule: RuleResponse): EuiDescriptionListPro }); } - aboutSectionListItems.push({ - title: i18n.SEVERITY_FIELD_LABEL, - description: , - }); + if (rule.severity) { + aboutSectionListItems.push({ + title: i18n.SEVERITY_FIELD_LABEL, + description: , + }); + } - if (rule.severity_mapping.length > 0) { + if (rule.severity_mapping && rule.severity_mapping.length > 0) { aboutSectionListItems.push( ...rule.severity_mapping .filter((severityMappingItem) => severityMappingItem.field !== '') @@ -252,12 +279,14 @@ const prepareAboutSectionListItems = (rule: RuleResponse): EuiDescriptionListPro ); } - aboutSectionListItems.push({ - title: i18n.RISK_SCORE_FIELD_LABEL, - description: , - }); + if (rule.risk_score) { + aboutSectionListItems.push({ + title: i18n.RISK_SCORE_FIELD_LABEL, + description: , + }); + } - if (rule.risk_score_mapping.length > 0) { + if (rule.risk_score_mapping && rule.risk_score_mapping.length > 0) { aboutSectionListItems.push( ...rule.risk_score_mapping .filter((riskScoreMappingItem) => riskScoreMappingItem.field !== '') @@ -270,14 +299,14 @@ const prepareAboutSectionListItems = (rule: RuleResponse): EuiDescriptionListPro ); } - if (rule.references.length > 0) { + if (rule.references && rule.references.length > 0) { aboutSectionListItems.push({ title: i18n.REFERENCES_FIELD_LABEL, description: , }); } - if (rule.false_positives.length > 0) { + if (rule.false_positives && rule.false_positives.length > 0) { aboutSectionListItems.push({ title: i18n.FALSE_POSITIVES_FIELD_LABEL, description: , @@ -307,7 +336,7 @@ const prepareAboutSectionListItems = (rule: RuleResponse): EuiDescriptionListPro }); } - if (rule.threat.length > 0) { + if (rule.threat && rule.threat.length > 0) { aboutSectionListItems.push({ title: i18n.THREAT_FIELD_LABEL, description: , @@ -328,7 +357,7 @@ const prepareAboutSectionListItems = (rule: RuleResponse): EuiDescriptionListPro }); } - if (rule.tags.length > 0) { + if (rule.tags && rule.tags.length > 0) { aboutSectionListItems.push({ title: i18n.TAGS_FIELD_LABEL, description: , @@ -339,24 +368,16 @@ const prepareAboutSectionListItems = (rule: RuleResponse): EuiDescriptionListPro }; export interface RuleAboutSectionProps { - rule: RuleResponse; + rule: Partial; + hideName?: boolean; + hideDescription?: boolean; } -export const RuleAboutSection = ({ rule }: RuleAboutSectionProps) => { - const aboutSectionListItems = prepareAboutSectionListItems(rule); +export const RuleAboutSection = ({ rule, hideName, hideDescription }: RuleAboutSectionProps) => { + const aboutSectionListItems = prepareAboutSectionListItems(rule, hideName, hideDescription); return (
- {rule.description && ( - , - }, - ]} - /> - )} ( interface MachineLearningJobListProps { jobIds: string[]; + isInteractive: boolean; } -const MachineLearningJobList = ({ jobIds }: MachineLearningJobListProps) => { +const MachineLearningJobList = ({ jobIds, isInteractive }: MachineLearningJobListProps) => { const { jobs } = useSecurityJobs(); + if (isInteractive) { + return ; + } + const relevantJobs = jobs.filter((job) => jobIds.includes(job.id)); return ( @@ -301,6 +311,49 @@ const ThreatMapping = ({ threatMapping }: ThreatMappingProps) => { return {description}; }; +interface TitleWithTechnicalPreviewBadgeProps { + title: string; +} + +const TitleWithTechnicalPreviewBadge = ({ title }: TitleWithTechnicalPreviewBadgeProps) => { + const license = useLicense(); + + return ; +}; + +interface SuppressAlertsByFieldProps { + fields: string[]; +} + +const SuppressAlertsByField = ({ fields }: SuppressAlertsByFieldProps) => ( + +); + +interface SuppressAlertsDurationProps { + duration?: Duration; +} + +const SuppressAlertsDuration = ({ duration }: SuppressAlertsDurationProps) => { + const durationDescription = duration + ? `${duration.value}${duration.unit}` + : descriptionStepI18n.ALERT_SUPPRESSION_PER_RULE_EXECUTION; + + return {durationDescription}; +}; + +interface MissingFieldsStrategyProps { + missingFieldsStrategy?: AlertSuppressionMissingFieldsStrategy; +} + +const MissingFieldsStrategy = ({ missingFieldsStrategy }: MissingFieldsStrategyProps) => { + const missingFieldsDescription = + missingFieldsStrategy === AlertSuppressionMissingFieldsStrategy.Suppress + ? descriptionStepI18n.ALERT_SUPPRESSION_SUPPRESS_ON_MISSING_FIELDS + : descriptionStepI18n.ALERT_SUPPRESSION_DO_NOT_SUPPRESS_ON_MISSING_FIELDS; + + return {missingFieldsDescription}; +}; + interface NewTermsFieldsProps { newTermsFields: string[]; } @@ -321,7 +374,8 @@ const HistoryWindowSize = ({ historyWindowStart }: HistoryWindowSizeProps) => { // eslint-disable-next-line complexity const prepareDefinitionSectionListItems = ( - rule: RuleResponse, + rule: Partial, + isInteractive: boolean, savedQuery?: SavedQuery ): EuiDescriptionListProps['listItems'] => { const definitionSectionListItems: EuiDescriptionListProps['listItems'] = []; @@ -376,16 +430,25 @@ const prepareDefinitionSectionListItems = ( } if ('query' in rule && rule.query) { + let title = descriptionStepI18n.QUERY_LABEL; + if (rule.type === 'saved_query') { + title = descriptionStepI18n.SAVED_QUERY_LABEL; + } else if (rule.type === 'eql') { + title = descriptionStepI18n.EQL_QUERY_LABEL; + } + definitionSectionListItems.push({ - title: savedQuery ? descriptionStepI18n.SAVED_QUERY_LABEL : descriptionStepI18n.QUERY_LABEL, + title, description: , }); } - definitionSectionListItems.push({ - title: i18n.RULE_TYPE_FIELD_LABEL, - description: , - }); + if (rule.type) { + definitionSectionListItems.push({ + title: i18n.RULE_TYPE_FIELD_LABEL, + description: , + }); + } if ('anomaly_threshold' in rule && rule.anomaly_threshold) { definitionSectionListItems.push({ @@ -397,11 +460,16 @@ const prepareDefinitionSectionListItems = ( if ('machine_learning_job_id' in rule) { definitionSectionListItems.push({ title: i18n.MACHINE_LEARNING_JOB_ID_FIELD_LABEL, - description: , + description: ( + + ), }); } - if (rule.related_integrations.length > 0) { + if (rule.related_integrations && rule.related_integrations.length > 0) { definitionSectionListItems.push({ title: i18n.RELATED_INTEGRATIONS_FIELD_LABEL, description: ( @@ -410,7 +478,7 @@ const prepareDefinitionSectionListItems = ( }); } - if (rule.required_fields.length > 0) { + if (rule.required_fields && rule.required_fields.length > 0) { definitionSectionListItems.push({ title: i18n.REQUIRED_FIELDS_FIELD_LABEL, description: , @@ -469,6 +537,27 @@ const prepareDefinitionSectionListItems = ( }); } + if ('alert_suppression' in rule && rule.alert_suppression) { + definitionSectionListItems.push({ + title: , + description: , + }); + + definitionSectionListItems.push({ + title: , + description: , + }); + + definitionSectionListItems.push({ + title: , + description: ( + + ), + }); + } + if ('new_terms_fields' in rule && rule.new_terms_fields && rule.new_terms_fields.length > 0) { definitionSectionListItems.push({ title: i18n.NEW_TERMS_FIELDS_FIELD_LABEL, @@ -487,16 +576,24 @@ const prepareDefinitionSectionListItems = ( }; export interface RuleDefinitionSectionProps { - rule: RuleResponse; + rule: Partial; + isInteractive?: boolean; } -export const RuleDefinitionSection = ({ rule }: RuleDefinitionSectionProps) => { +export const RuleDefinitionSection = ({ + rule, + isInteractive = false, +}: RuleDefinitionSectionProps) => { const { savedQuery } = useGetSavedQuery({ savedQueryId: rule.type === 'saved_query' ? rule.saved_id : '', ruleType: rule.type, }); - const definitionSectionListItems = prepareDefinitionSectionListItems(rule, savedQuery); + const definitionSectionListItems = prepareDefinitionSectionListItems( + rule, + isInteractive, + savedQuery + ); return (
diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx index aa9b42abe6ba7..3d4501bd1f797 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx @@ -15,7 +15,7 @@ import { useGeneratedHtmlId, } from '@elastic/eui'; import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; -import { RuleAboutSection } from './rule_about_section'; +import { RuleAboutSection, Description } from './rule_about_section'; import { RuleDefinitionSection } from './rule_definition_section'; import { RuleScheduleSection } from './rule_schedule_section'; import { RuleSetupGuideSection } from './rule_setup_guide_section'; @@ -103,7 +103,8 @@ export const RuleOverviewTab = ({ isOpen={expandedOverviewSections.about} toggle={toggleOverviewSection.about} > - + {rule.description && } + = ({ stepData, stepDataDetails, loading, + rule, }) => { const [selectedToggleOption, setToggleOption] = useState('details'); const [aboutPanelHeight, setAboutPanelHeight] = useState(0); @@ -124,11 +127,7 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ - +
)} From 17adabe6d06b6e802f107914ad29ebc700ac80c8 Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Tue, 19 Sep 2023 16:44:47 +0200 Subject: [PATCH 2/8] Change "Data view" -> "Data view ID" --- .../rule_management/components/rule_details/translations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts index e26cdeadb5e39..a062e5a13d99f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts @@ -192,7 +192,7 @@ export const INDEX_FIELD_LABEL = i18n.translate( export const DATA_VIEW_ID_FIELD_LABEL = i18n.translate( 'xpack.securitySolution.detectionEngine.ruleDetails.dataViewIdFieldLabel', { - defaultMessage: 'Data view', + defaultMessage: 'Data view ID', } ); From dc1f62b1e06e766015e27efa5c7a507970d32280 Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Fri, 22 Sep 2023 12:46:33 +0200 Subject: [PATCH 3/8] Fix a few type and i18n issues --- .../pages/rule_details/index.tsx | 42 ++----------------- .../rules/description_step/translations.ts | 4 +- .../translations/translations/fr-FR.json | 2 +- .../translations/translations/ja-JP.json | 2 +- .../translations/translations/zh-CN.json | 2 +- 5 files changed, 8 insertions(+), 44 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index aadca25f8b480..6faf663f520c9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -117,7 +117,6 @@ import * as ruleI18n from '../../../../detections/pages/detection_engine/rules/t import { RuleDetailsContextProvider } from './rule_details_context'; // eslint-disable-next-line no-restricted-imports import { LegacyUrlConflictCallOut } from './legacy_url_conflict_callout'; -import { useGetSavedQuery } from '../../../../detections/pages/detection_engine/rules/use_get_saved_query'; import * as i18n from './translations'; import { NeedAdminForUpdateRulesCallOut } from '../../../../detections/components/callouts/need_admin_for_update_callout'; import { MissingPrivilegesCallOut } from '../../../../detections/components/callouts/missing_privileges_callout'; @@ -135,8 +134,6 @@ import { useBulkDuplicateExceptionsConfirmation } from '../../../rule_management import { BulkActionDuplicateExceptionsConfirmation } from '../../../rule_management_ui/components/rules_table/bulk_actions/bulk_duplicate_exceptions_confirmation'; import { useAsyncConfirmation } from '../../../rule_management_ui/components/rules_table/rules_table/use_async_confirmation'; import { RuleSnoozeBadge } from '../../../rule_management/components/rule_snooze_badge'; -import { useRuleIndexPattern } from '../../../rule_creation_ui/pages/form'; -import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; import { useBoolState } from '../../../../common/hooks/use_bool_state'; import { RuleDefinitionSection } from '../../../rule_management/components/rule_details/rule_definition_section'; import { RuleScheduleSection } from '../../../rule_management/components/rule_details/rule_schedule_section'; @@ -175,7 +172,6 @@ const RuleDetailsPageComponent: React.FC = ({ clearSelected, }) => { const { - data, application: { navigateToApp, capabilities: { actions }, @@ -260,38 +256,14 @@ const RuleDetailsPageComponent: React.FC = ({ onFinish: hideDeleteConfirmation, }); - const { - aboutRuleData, - modifiedAboutRuleDetailsData, - defineRuleData, - scheduleRuleData, - ruleActionsData, - } = + const { aboutRuleData, modifiedAboutRuleDetailsData, ruleActionsData } = rule != null ? getStepsData({ rule, detailsView: true }) : { aboutRuleData: null, modifiedAboutRuleDetailsData: null, - defineRuleData: null, - scheduleRuleData: null, ruleActionsData: null, }; - const [dataViewTitle, setDataViewTitle] = useState(); - useEffect(() => { - const fetchDataViewTitle = async () => { - if (defineRuleData?.dataViewId != null && defineRuleData?.dataViewId !== '') { - const dataView = await data.dataViews.get(defineRuleData?.dataViewId); - setDataViewTitle(dataView.title); - } - }; - fetchDataViewTitle(); - }, [data.dataViews, defineRuleData?.dataViewId]); - - const { indexPattern: ruleIndexPattern } = useRuleIndexPattern({ - dataSourceType: defineRuleData?.dataSourceType ?? DataSourceType.IndexPatterns, - index: defineRuleData?.index ?? [], - dataViewId: defineRuleData?.dataViewId, - }); const { showBuildingBlockAlerts, setShowBuildingBlockAlerts, showOnlyThreatIndicatorAlerts } = useDataTableFilters(TableId.alertsOnRuleDetailsPage); @@ -300,11 +272,6 @@ const RuleDetailsPageComponent: React.FC = ({ const { globalFullScreen } = useGlobalFullScreen(); const [filterGroup, setFilterGroup] = useState(FILTER_OPEN); - const { isSavedQueryLoading, savedQueryBar } = useGetSavedQuery({ - savedQueryId: rule?.saved_id, - ruleType: rule?.type, - }); - // TODO: Refactor license check + hasMlAdminPermissions to common check const hasMlPermissions = hasMlLicense(mlCapabilities) && hasMlAdminPermissions(mlCapabilities); @@ -678,11 +645,8 @@ const RuleDetailsPageComponent: React.FC = ({ - - {rule != null && !isSavedQueryLoading && !isStartingJobs && ( + + {rule != null && !isStartingJobs && ( )} diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.ts index d9bc9cceaa4e8..42e9bad349618 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/translations.ts @@ -15,14 +15,14 @@ export const FILTERS_LABEL = i18n.translate( ); export const QUERY_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.QueryLabel', + 'xpack.securitySolution.detectionEngine.createRule.queryLabel', { defaultMessage: 'Custom query', } ); export const EQL_QUERY_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.QueryLabel', + 'xpack.securitySolution.detectionEngine.createRule.eqlQueryLabel', { defaultMessage: 'EQL query', } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index ed5d0042c8030..a854c1c957450 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -30632,7 +30632,7 @@ "xpack.securitySolution.detectionEngine.createRule.mlRuleTypeDescription": "Machine Learning", "xpack.securitySolution.detectionEngine.createRule.newTermsRuleTypeDescription": "Nouveaux termes", "xpack.securitySolution.detectionEngine.createRule.pageTitle": "Créer une nouvelle règle", - "xpack.securitySolution.detectionEngine.createRule.QueryLabel": "Requête personnalisée", + "xpack.securitySolution.detectionEngine.createRule.queryLabel": "Requête personnalisée", "xpack.securitySolution.detectionEngine.createRule.queryRuleTypeDescription": "Requête", "xpack.securitySolution.detectionEngine.createRule.ruleActionsField.ruleActionsFormErrorsTitle": "Veuillez corriger les problèmes répertoriés ci-dessous", "xpack.securitySolution.detectionEngine.createRule.rulePreviewDescription": "L'aperçu des règles reflète la configuration actuelle de vos paramètres et exceptions de règles. Cliquez sur l'icône d'actualisation pour afficher l'aperçu mis à jour.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 07f770568b038..f06e39e4191f9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -30631,7 +30631,7 @@ "xpack.securitySolution.detectionEngine.createRule.mlRuleTypeDescription": "機械学習", "xpack.securitySolution.detectionEngine.createRule.newTermsRuleTypeDescription": "新しい用語", "xpack.securitySolution.detectionEngine.createRule.pageTitle": "新規ルールを作成", - "xpack.securitySolution.detectionEngine.createRule.QueryLabel": "カスタムクエリ", + "xpack.securitySolution.detectionEngine.createRule.queryLabel": "カスタムクエリ", "xpack.securitySolution.detectionEngine.createRule.queryRuleTypeDescription": "クエリ", "xpack.securitySolution.detectionEngine.createRule.ruleActionsField.ruleActionsFormErrorsTitle": "次の一覧の問題を解決してください", "xpack.securitySolution.detectionEngine.createRule.rulePreviewDescription": "ルールプレビューには、ルール設定と例外の現在の構成が反映されます。更新アイコンをクリックすると、更新されたプレビューが表示されます。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 4369612f97b4a..7489c37fbb9c1 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -30627,7 +30627,7 @@ "xpack.securitySolution.detectionEngine.createRule.mlRuleTypeDescription": "Machine Learning", "xpack.securitySolution.detectionEngine.createRule.newTermsRuleTypeDescription": "新字词", "xpack.securitySolution.detectionEngine.createRule.pageTitle": "创建新规则", - "xpack.securitySolution.detectionEngine.createRule.QueryLabel": "定制查询", + "xpack.securitySolution.detectionEngine.createRule.queryLabel": "定制查询", "xpack.securitySolution.detectionEngine.createRule.queryRuleTypeDescription": "查询", "xpack.securitySolution.detectionEngine.createRule.ruleActionsField.ruleActionsFormErrorsTitle": "请修复下面所列的问题", "xpack.securitySolution.detectionEngine.createRule.rulePreviewDescription": "规则预览反映了您的规则设置和例外的当前配置,单击刷新图标可查看已更新的预览。", From e29dc685c1421b4b4eb5ebd75068b6c9956071af Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Fri, 22 Sep 2023 16:59:09 +0200 Subject: [PATCH 4/8] Fix Jest tests --- .../step_about_rule_details/index.test.tsx | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx index ae46ccef9e859..8ec9c52e0b773 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx @@ -11,7 +11,10 @@ import { EuiProgress, EuiButtonGroup } from '@elastic/eui'; import { ThemeProvider } from 'styled-components'; import { StepAboutRuleToggleDetails } from '.'; -import { mockAboutStepRule } from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; +import { + mockRule, + mockAboutStepRule, +} from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import { HeaderSection } from '../../../../common/components/header_section'; import { StepAboutRule } from '../step_about_rule'; import type { AboutStepRule } from '../../../pages/detection_engine/rules/types'; @@ -24,10 +27,10 @@ const mockTheme = getMockTheme({ }); describe('StepAboutRuleToggleDetails', () => { - let mockRule: AboutStepRule; + let stepDataMock: AboutStepRule; beforeEach(() => { - mockRule = mockAboutStepRule(); + stepDataMock = mockAboutStepRule(); }); test('it renders loading component when "loading" is true', () => { @@ -35,11 +38,12 @@ describe('StepAboutRuleToggleDetails', () => { ); @@ -49,7 +53,12 @@ describe('StepAboutRuleToggleDetails', () => { test('it does not render details if stepDataDetails is null', () => { const wrapper = shallow( - + ); expect(wrapper.find(StepAboutRule).exists()).toBeFalsy(); @@ -65,6 +74,7 @@ describe('StepAboutRuleToggleDetails', () => { setup: '', }} stepData={null} + rule={mockRule('mocked-rule-id')} /> ); @@ -74,7 +84,7 @@ describe('StepAboutRuleToggleDetails', () => { describe('note value is empty string', () => { test('it does not render toggle buttons', () => { const mockAboutStepWithoutNote = { - ...mockRule, + ...stepDataMock, note: '', }; const wrapper = shallow( @@ -82,10 +92,11 @@ describe('StepAboutRuleToggleDetails', () => { loading={false} stepDataDetails={{ note: '', - description: mockRule.description, + description: stepDataMock.description, setup: '', }} stepData={mockAboutStepWithoutNote} + rule={mockRule('mocked-rule-id')} /> ); @@ -103,11 +114,12 @@ describe('StepAboutRuleToggleDetails', () => { ); @@ -123,11 +135,12 @@ describe('StepAboutRuleToggleDetails', () => { ); @@ -151,11 +164,12 @@ describe('StepAboutRuleToggleDetails', () => { ); @@ -180,11 +194,12 @@ describe('StepAboutRuleToggleDetails', () => { ); @@ -203,11 +218,12 @@ describe('StepAboutRuleToggleDetails', () => { ); @@ -224,11 +240,12 @@ describe('StepAboutRuleToggleDetails', () => { ); @@ -254,11 +271,12 @@ describe('StepAboutRuleToggleDetails', () => { ); From 33a0f79835ede3d1cfebd34343e28303c780ffca Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Wed, 27 Sep 2023 12:21:52 +0200 Subject: [PATCH 5/8] Add a TS workaround --- .../cast_rule_as_rule_response.ts | 24 +++++++++++++++++ .../pages/rule_details/index.tsx | 26 ++++++++++++------- .../rule_details/rule_schedule_section.tsx | 6 ++++- .../rules/step_about_rule_details/index.tsx | 7 ++++- 4 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response.ts new file mode 100644 index 0000000000000..fb1fdfc1fcc99 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Rule } from '../../../rule_management/logic'; +import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; + +/* + * This is a temporary workaround to suppress TS errors when using + * rule section components on the rule details page. + * + * The rule details page passes a Rule object to the rule section components, + * but section components expect a RuleResponse object. Rule and RuleResponse + * are basically same object type with only a few minor differences. + * This function casts the Rule object to RuleResponse. + * + * In the near future we'll start using codegen to generate proper response + * types and the rule details page will start passing RuleResponse objects, + * so this workaround will no longer be needed. + */ +export const castRuleAsRuleResponse = (rule: Rule) => rule as Partial; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index 6faf663f520c9..678f31f519fbe 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -140,6 +140,7 @@ import { RuleScheduleSection } from '../../../rule_management/components/rule_de // eslint-disable-next-line no-restricted-imports import { useLegacyUrlRedirect } from './use_redirect_legacy_url'; import { RuleDetailTabs, useRuleDetailsTabs } from './use_rule_details_tabs'; +import { castRuleAsRuleResponse } from './cast_rule_as_rule_response'; const RULE_EXCEPTION_LIST_TYPES = [ ExceptionListTypeEnum.DETECTION, @@ -634,27 +635,34 @@ const RuleDetailsPageComponent: React.FC = ({ - + {rule !== null && ( + + )} - {rule != null && !isStartingJobs && ( - + {rule !== null && !isStartingJobs && ( + )} - {rule != null && } + {rule != null && ( + + )} {hasActions && ( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx index 1d4f4290c4b03..3883084b11f5e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx @@ -28,10 +28,14 @@ const From = ({ from, interval }: FromProps) => ( ); export interface RuleScheduleSectionProps { - rule: RuleResponse; + rule: Partial; } export const RuleScheduleSection = ({ rule }: RuleScheduleSectionProps) => { + if (!rule.interval || !rule.from) { + return null; + } + const ruleSectionListItems = []; ruleSectionListItems.push( diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx index 0cf8be19dbdb8..c0d1db9f837fe 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx @@ -29,6 +29,7 @@ import type { AboutStepRule, AboutStepRuleDetails, } from '../../../pages/detection_engine/rules/types'; +import { castRuleAsRuleResponse } from '../../../../detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response'; import * as i18n from './translations'; import { fullHeight } from './styles'; @@ -127,7 +128,11 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ - +
)} From f4637e9ba9d5ca724a3a0e023e9facbb85423d09 Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Wed, 27 Sep 2023 22:58:36 +0200 Subject: [PATCH 6/8] Fix some Cypress tests --- .../rule_details_ui/pages/rule_details/index.tsx | 1 + .../components/rule_details/rule_about_section.tsx | 1 + .../components/rule_details/rule_definition_section.tsx | 5 ++++- .../components/rule_details/rule_schedule_section.tsx | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index 678f31f519fbe..e5c047145d965 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -653,6 +653,7 @@ const RuleDetailsPageComponent: React.FC = ({ )} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx index 7a133b3b81400..7c1ada1c6e1bc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx @@ -384,6 +384,7 @@ export const RuleAboutSection = ({ rule, hideName, hideDescription }: RuleAboutS listItems={aboutSectionListItems} columnWidths={DESCRIPTION_LIST_COLUMN_WIDTHS} rowGutterSize="m" + data-test-subj="listItemColumnStepRuleDescription" /> ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx index fee2da4760794..4f314c73f4ec5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx @@ -578,11 +578,13 @@ const prepareDefinitionSectionListItems = ( export interface RuleDefinitionSectionProps { rule: Partial; isInteractive?: boolean; + dataTestSubj?: string; } export const RuleDefinitionSection = ({ rule, isInteractive = false, + dataTestSubj, }: RuleDefinitionSectionProps) => { const { savedQuery } = useGetSavedQuery({ savedQueryId: rule.type === 'saved_query' ? rule.saved_id : '', @@ -596,12 +598,13 @@ export const RuleDefinitionSection = ({ ); return ( -
+
); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx index 3883084b11f5e..b805b0a0a878e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx @@ -50,7 +50,7 @@ export const RuleScheduleSection = ({ rule }: RuleScheduleSectionProps) => { ); return ( -
+
Date: Thu, 28 Sep 2023 01:15:41 +0200 Subject: [PATCH 7/8] Fix more tests --- .../components/rule_details/rule_definition_section.tsx | 7 +++++++ .../rule_creation/event_correlation_rule.cy.ts | 4 ++-- .../cypress/screens/rule_details.ts | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx index 4f314c73f4ec5..d75beef8ef942 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx @@ -412,6 +412,13 @@ const prepareDefinitionSectionListItems = ( description: , }); } + + if (typeof savedQuery.attributes.query.query === 'string') { + definitionSectionListItems.push({ + title: descriptionStepI18n.SAVED_QUERY_LABEL, + description: , + }); + } } if ('filters' in rule && 'data_view_id' in rule && rule.filters?.length) { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts index 66c506e0f2157..1984ef5a5eda4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_creation/event_correlation_rule.cy.ts @@ -22,7 +22,7 @@ import { ABOUT_INVESTIGATION_NOTES, ABOUT_RULE_DESCRIPTION, ADDITIONAL_LOOK_BACK_DETAILS, - CUSTOM_QUERY_DETAILS, + EQL_QUERY_DETAILS, DEFINITION_DETAILS, FALSE_POSITIVES_DETAILS, removeExternalLinkText, @@ -115,7 +115,7 @@ describe('EQL rules', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join('')); - getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.query); + getDetails(EQL_QUERY_DETAILS).should('have.text', rule.query); getDetails(RULE_TYPE_DETAILS).should('have.text', 'Event Correlation'); getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None'); }); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts b/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts index d061f4a49114d..35f1fb7a159cb 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/rule_details.ts @@ -23,6 +23,8 @@ export const ANOMALY_SCORE_DETAILS = 'Anomaly score'; export const CUSTOM_QUERY_DETAILS = 'Custom query'; +export const EQL_QUERY_DETAILS = 'EQL query'; + export const SAVED_QUERY_NAME_DETAILS = 'Saved query name'; export const SAVED_QUERY_DETAILS = /^Saved query$/; From 43c86b5917af11e689bd2390ab75f38e9cd17ee3 Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Mon, 2 Oct 2023 05:10:59 +0200 Subject: [PATCH 8/8] Update the test plan --- .../installation_and_upgrade.md | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md index 09198dd2d9ef8..9b2651fbbec5f 100644 --- a/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md +++ b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/installation_and_upgrade.md @@ -529,6 +529,197 @@ When user opens the Rule Management page Then user should NOT see the Rule Updates tab until the package installation is completed and there are rules available for upgrade ``` +### Previewing a rule before installation or upgrade +Assumptions: + - if a section in the Overview tab doesn't contain any properties, it should not be displayed + +```Gherkin +Shared properties examples: + | section | shared_property | + | About | Author | + | About | Building block | + | About | Severity | + | About | Severity override | + | About | Risk score | + | About | Risk score override | + | About | Reference URLs | + | About | False positive examples | + | About | Custom highlighted fields | + | About | License | + | About | Rule name override | + | About | MITRE ATT&CK™ | + | About | Timestamp override | + | About | Tags | + | Definition | Related integrations | + | Definition | Required fields | + | Definition | Timeline template | + | Schedule | Runs every | + | Schedule | Additional look-back time | + +Custom query properties examples: + | custom_query_property | + | Custom query | + | Filters | + +Saved query properties examples: + | saved_query_property | + | Saved query name | + | Saved query filters | + | Saved query | +``` + +#### **Scenario: Custom Query rule - Overview tab** +**Automation**: 1 e2e test +```Gherkin +Given a Custom Query rule +When the user opens the rule preview +Then the "Rule type" property under the Definition section should be "Custom query" +And if the rule has index patterns then the "Index patterns" label should be displayed under the Definition section along with a list of index patters +And if the rule has a data view then "Data view ID" and "Data view index pattern" labels should be displayed under the Definition section along with their values +And if the rule has a custom query then for each defined in the rule a corresponding value should be displayed under the Definition section +And if the rule has a saved query then for each defined in the rule a corresponding value should be displayed under the Definition section +And if the rule has alert suppression settings then for each defined in the rule a corresponding value should be displayed under the Definition section +And all the properties defined in the rule should be displayed along with their values under their respective
+And if the rule has a setup guide then it should be displayed under the Setup Guide section + +Alert suppression examples: + | alert_suppression_property | + | Suppress alerts by | + | Suppress alerts for | + | If a suppression field is missing | +``` + +#### **Scenario: Machine Learning rule - Overview tab** +**Automation**: 1 e2e test +```Gherkin +Given a Machine Learning rule +When the user opens the rule preview +Then the "Rule type" property under the Definition section should be "Machine Learning" +And all the properties should be displayed along with their values under the Definition section +And all the properties defined in the rule should be displayed along with their values under their respective
+And if the rule has a setup guide then it should be displayed under the Setup Guide section + +Machine Learning properties examples: + | machine_learning_property | + | Anomaly score threshold | + | Machine Learning job | +``` + +#### **Scenario: Threshold rule - Overview tab** +**Automation**: 1 e2e test +```Gherkin +Given a Threshold rule +When the user opens the rule preview +Then the "Rule type" property under the Definition section should be "Threshold" +And the Threshold field should be displayed under the Definition section along with its value +And if the rule has index patterns then the "Index patterns" label should be displayed under the Definition section along with a list of index patters +And if the rule has a data view then "Data view ID" and "Data view index pattern" labels should be displayed under the Definition section along with their values +And for each defined in the rule a corresponding value should be displayed under the Definition section +And all the properties defined in the rule should be displayed along with their values under their respective
+And if the rule has a setup guide then it should be displayed under the Setup Guide section +``` + +#### **Scenario: EQL rule - Overview tab** +**Automation**: 1 e2e test +```Gherkin +Given a EQL rule +When the user opens the rule preview +Then the "Rule type" property under the Definition section should be "Event Correlation" +And the "EQL query" field should be displayed under the Definition section along with its value +And if EQL filters are defined in the rule then the "Filters" label should be displayed under the Definition section along with its value +And if the rule has index patterns then the "Index patterns" label should be displayed under the Definition section along with a list of index patters +And if the rule has a data view then "Data view ID" and "Data view index pattern" labels should be displayed under the Definition section along with their values +And all the properties defined in the rule should be displayed along with their values under their respective
+And if the rule has a setup guide then it should be displayed under the Setup Guide section +``` + +#### **Scenario: Indicator Match rule - Overview tab** +**Automation**: 1 e2e test +```Gherkin +Given an Indicator Match rule +When the user opens the rule preview +Then the "Rule type" property under the Definition section should be "Indicator Match" +And for each defined in the rule a corresponding value should be displayed under the Definition section +And if the rule has index patterns then the "Index patterns" label should be displayed under the Definition section along with a list of index patters +And if the rule has a data view then "Data view ID" and "Data view index pattern" labels should be displayed under the Definition section along with their values +And for each defined in the rule a corresponding value should be displayed under the Definition section +And all the properties defined in the rule should be displayed along with their values under their respective
+And if the rule has a setup guide then it should be displayed under the Setup Guide section + +Examples: + | indicator_match_property | + | Indicator index patterns | + | Indicator mapping | + | Indicator filters | + | Indicator index query | +``` + +#### **Scenario: New Terms rule - Overview tab** +**Automation**: 1 e2e test +```Gherkin +Given a New Terms rule +When the user opens the rule preview +Then the "Rule type" property under the Definition section should be "New Terms" +And for each defined in the rule a corresponding value should be displayed under the Definition section +And if the rule has index patterns then the "Index patterns" label should be displayed under the Definition section along with a list of index patters +And if the rule has a data view then "Data view ID" and "Data view index pattern" labels should be displayed under the Definition section along with their values +And for each defined in the rule a corresponding value should be displayed under the Definition section +And all the properties defined in the rule should be displayed along with their values under their respective
+And if the rule has a setup guide then it should be displayed under the Setup Guide section + +Examples: + | new_terms_property | + | Fields | + | History Window Size | +``` + +#### **Scenario: ES|QL rule - Overview tab** +**Automation**: 1 e2e test +```Gherkin +"Rule type" should be "ES|QL" +Might have setup guide +Includes all shared About section properties. +Includes all shared Schedule section properties. + +Given an ES|QL rule +When the user opens the rule preview +Then the "Rule type" property under the Definition section should be "ES|QL" +And "ES|QL query" field should be displayed under the Definition section along with its value +And all the properties defined in the rule should be displayed along with their values under their respective
+And if the rule has a setup guide then it should be displayed under the Setup Guide section +``` + +#### **Scenario: All rule types - Investigation guide** +**Automation**: 1 e2e test +```Gherkin + Given a rule of any type + When the user opens the rule preview + Then the "Investigation guide" tab should be displayed if the rule has an investigation guide + But the "Investigation guide" tab should not be displayed if the rule doesn't have an investigation guide +``` + +#### **Scenario: All rule types - Installing a rule** +**Automation**: 1 e2e test +```Gherkin + Given a not installed prebuilt rule + When the user opens the rule preview + Then the "Install" button should be displayed and enabled + And clicking the "Install" button should install the rule + And a newly installed rule should be displayed on the Rule Management page +``` + +#### **Scenario: All rule types - Upgrading a rule** +**Automation**: 1 e2e test +```Gherkin + Given an installed prebuilt rule that has a new version available + When the user opens the rule preview for this rule + Then the new version of the rule should be displayed + And the "Upgrade" button should be displayed and enabled + And clicking the "Upgrade" button should install the upgraded version of the rule +``` + + + ### Error handling #### **Scenario: Error is handled when any operation on prebuilt rules fails**