Skip to content

Commit

Permalink
[Security Solution] Update prebuilt rule customization UI copy (#210817)
Browse files Browse the repository at this point in the history
**Resolves: elastic/security-docs#6238
**Deployed here:
[link](https://nikitaindik-pr-210817-prebuilt-rule-customization-update-ui.kbndev.co/app/security/rules/updates?rulesTable=(field:name,order:asc,searchTerm:'Shared%20Object%20Created%20or%20Changed%20by%20Previously%20Unknown%20Process')&sourcerer=(default:(id:security-solution-default,selectedPatterns:!()))&timerange=(global:(linkTo:!(timeline),timerange:(from:'2025-02-11T23:00:00.000Z',fromStr:now/d,kind:absolute,to:'2025-02-12T22:59:59.999Z',toStr:now/d)),timeline:(linkTo:!(global),timerange:(from:'2025-02-11T23:00:00.000Z',fromStr:now/d,kind:absolute,to:'2025-02-12T22:59:59.999Z',toStr:now/d)))&timeline=(activeTab:query,graphEventId:'',isOpen:!f))**

> ⚠️ CI fails are caused by an issue unrelated to this PR

## Summary

Changes in this PR:
- UI copy is updated in accordance with
[recommendations](https://docs.google.com/document/d/1Yl6DyN9pertqgB-iIKIEN3xdvlDM50oscJ00G-WwtyA/edit?tab=t.0)
(internal link) from Security Documentation team
- Text color for "No update" fields in upgrade flyout changed from green
to default.
- Fixed a minor bug with placeholder not displaying for "Setup guide"
and "Investigation guide" fields on Rule Creation/Editing page


<details>
<summary><strong>A few screenshots taken in Serverless</strong> (click
to expand)</summary>

<img width="523" alt="serverless_rep_tooltip"
src="https://github.com/user-attachments/assets/825e1514-a191-45c2-90ca-0f15a8c9da7b"
/>
  
<img width="836" alt="serverless_bulk_action_error"
src="https://github.com/user-attachments/assets/8aa38c77-5aaa-49cf-9b4e-8c992382a1d2"
/>
  
<img width="1102" alt="serverless_upgrade_callout"
src="https://github.com/user-attachments/assets/cf947c73-d52d-4c85-abd6-369f616b8421"
/>
  
<img width="1004" alt="no_update_white"
src="https://github.com/user-attachments/assets/f720f24c-0c97-432f-b2d5-7ff7e5919ba0"
/>



</details>

## Testing
You can use [this
deployment](https://nikitaindik-pr-210817-prebuilt-rule-customization-update-ui.kbndev.co)
(default credentials) test to changes on ESS Enterprise license.
Here's a couple rules that has field updates of different kinds:
 - Unusual User Privilege Enumeration via id
 - Shared Object Created or Changed by Previously Unknown Process

To test on Serverless or with other licenses, you'll need to run it
locally. Reach out to me if you need help with this.

Work started: 11-Feb-2025
  • Loading branch information
nikitaindik authored Feb 20, 2025
1 parent 1f35d7a commit 994201c
Show file tree
Hide file tree
Showing 34 changed files with 225 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34935,8 +34935,6 @@
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.guideLabel": "Guide d'investigation",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.maxAlertsFieldLessThanWarning": "Kibana ne permet qu'un maximum de {maxNumber} {maxNumber, plural, =1 {alerte} other {alertes}} par exécution de règle.",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.nameFieldRequiredError": "Nom obligatoire.",
"xpack.securitySolution.detectionEngine.createRule.stepAboutrule.noteHelpText": "Ajouter un guide d'investigation sur les règles...",
"xpack.securitySolution.detectionEngine.createRule.stepAboutrule.setupHelpText": "Ajouter le guide de configuration de règle...",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.setupHelpText": "Fournissez des instructions sur les conditions préalables à la règle, telles que les intégrations requises, les étapes de configuration et tout ce qui est nécessaire au bon fonctionnement de la règle.",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.setupLabel": "Guide de configuration",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.tagFieldEmptyError": "Une balise ne doit pas être vide",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34796,8 +34796,6 @@
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.guideLabel": "調査ガイド",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.maxAlertsFieldLessThanWarning": "Kibanaで許可される最大数は、1回の実行につき、{maxNumber} {maxNumber, plural, other {アラート}}です。",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.nameFieldRequiredError": "名前が必要です。",
"xpack.securitySolution.detectionEngine.createRule.stepAboutrule.noteHelpText": "ルール調査ガイドを追加...",
"xpack.securitySolution.detectionEngine.createRule.stepAboutrule.setupHelpText": "ルールセットアップガイドを追加...",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.setupHelpText": "必要な統合、構成ステップ、ルールが正常に動作するために必要な他のすべての項目といった、ルール前提条件に関する指示を入力します。",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.setupLabel": "セットアップガイド",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.tagFieldEmptyError": "タグを空にすることはできません",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34266,8 +34266,6 @@
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.guideLabel": "调查指南",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.maxAlertsFieldLessThanWarning": "每次规则运行时,Kibana 最多只允许 {maxNumber} 个{maxNumber, plural, other {告警}}。",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.nameFieldRequiredError": "名称必填。",
"xpack.securitySolution.detectionEngine.createRule.stepAboutrule.noteHelpText": "添加规则调查指南......",
"xpack.securitySolution.detectionEngine.createRule.stepAboutrule.setupHelpText": "添加规则设置指南......",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.setupHelpText": "提供有关规则先决条件的说明,如所需集成、配置步骤,以及规则正常运行所需的任何其他内容。",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.setupLabel": "设置指南",
"xpack.securitySolution.detectionEngine.createRule.stepAboutRule.tagFieldEmptyError": "标签不得为空",
Expand Down
21 changes: 19 additions & 2 deletions x-pack/solutions/security/packages/upselling/messages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,27 @@ export const UPGRADE_NOTES_MANAGEMENT_USER_FILTER = (requiredLicense: string) =>
},
});

export const UPGRADE_PREBUILT_RULE_CUSTOMIZATION = (requiredLicense: string) =>
export const PREBUILT_RULE_CUSTOMIZATION = (requiredLicense: string, licenseKind: string) =>
i18n.translate('securitySolutionPackages.ruleManagement.prebuiltRuleCustomization.upsell', {
defaultMessage: 'Upgrade to {requiredLicense} to enable prebuilt rule customization',
defaultMessage: '{requiredLicense} {licenseKind} is required to customize prebuilt rules',
values: {
requiredLicense,
licenseKind,
},
});

export const PREBUILT_RULE_CUSTOMIZATION_DESCRIPTION = (
requiredLicense: string,
licenseKind: string
) =>
i18n.translate(
'securitySolutionPackages.ruleManagement.prebuiltRuleCustomization.descriptionUpsell',
{
defaultMessage:
"Without the {requiredLicense} {licenseKind}, prebuilt rules can't be customized. To access this feature, upgrade your {licenseKind} or contact your admin for assistance.",
values: {
requiredLicense,
licenseKind,
},
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export type UpsellingMessageId =
| 'alert_suppression_rule_form'
| 'alert_suppression_rule_details'
| 'note_management_user_filter'
| 'prebuilt_rule_customization';
| 'prebuilt_rule_customization'
| 'prebuilt_rule_customization_description';
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface MarkdownEditorProps {
autoFocusDisabled?: boolean;
setIsMarkdownInvalid: (value: boolean) => void;
includePlugins?: boolean;
placeholder?: string;
}

type EuiMarkdownEditorRef = ElementRef<typeof EuiMarkdownEditor>;
Expand All @@ -56,6 +57,7 @@ const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProp
autoFocusDisabled,
setIsMarkdownInvalid,
includePlugins = true,
placeholder,
},
ref
) => {
Expand Down Expand Up @@ -118,6 +120,7 @@ const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProp
errors={markdownErrorMessages}
data-test-subj={dataTestSubj}
height={height}
placeholder={placeholder}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type MarkdownEditorFormProps = EuiMarkdownEditorProps & {

export const MarkdownEditorForm = React.memo(
forwardRef<MarkdownEditorRef, MarkdownEditorFormProps>(
({ field, dataTestSubj, idAria, includePlugins }, ref) => {
({ field, dataTestSubj, idAria, includePlugins, placeholder }, ref) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
const [isMarkdownInvalid, setIsMarkdownInvalid] = useState(false);

Expand All @@ -48,6 +48,7 @@ export const MarkdownEditorForm = React.memo(
data-test-subj={`${dataTestSubj}-markdown-editor`}
setIsMarkdownInvalid={setIsMarkdownInvalid}
includePlugins={includePlugins}
placeholder={placeholder}
/>
</EuiFormRow>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export const BUILDING_BLOCK_LABEL = i18n.translate(
export const BUILDING_BLOCK_DESCRIPTION = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleDescription.buildingBlockDescription',
{
defaultMessage: 'All generated alerts will be marked as "building block" alerts',
defaultMessage: 'All generated alerts will be marked as building block alerts',
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
<EuiToolTip
content={
ruleSource?.type === 'external'
? I18n.AUTHOR_IMMUTABLE_FIELD_TOOLTIP_TEXT
? I18n.FIELD_NOT_EDITABLE_TOOLTIP_TEXT(I18n.AUTHOR_FIELD_LABEL)
: undefined
}
display="block"
Expand All @@ -307,7 +307,7 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
<EuiToolTip
content={
ruleSource?.type === 'external'
? I18n.LICENSE_IMMUTABLE_FIELD_TOOLTIP_TEXT
? I18n.FIELD_NOT_EDITABLE_TOOLTIP_TEXT(I18n.LICENSE_FIELD_LABEL)
: undefined
}
display="block"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,7 @@ const { emptyField } = fieldValidators;
export const schema: FormSchema<AboutStepRule> = {
author: {
type: FIELD_TYPES.COMBO_BOX,
label: i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldAuthorLabel',
{
defaultMessage: 'Author',
}
),
label: I18n.AUTHOR_FIELD_LABEL,
helpText: i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldAuthorHelpText',
{
Expand Down Expand Up @@ -209,12 +204,7 @@ export const schema: FormSchema<AboutStepRule> = {
},
license: {
type: FIELD_TYPES.TEXT,
label: i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldLicenseLabel',
{
defaultMessage: 'License',
}
),
label: I18n.LICENSE_FIELD_LABEL,
helpText: i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldLicenseHelpText',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,29 +85,40 @@ export const URL_FORMAT_INVALID = i18n.translate(
);

export const ADD_RULE_NOTE_HELP_TEXT = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutrule.noteHelpText',
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.noteHelpText',
{
defaultMessage: 'Add rule investigation guide...',
}
);

export const ADD_RULE_SETUP_HELP_TEXT = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutrule.setupHelpText',
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.addRuleSetupHelpText',
{
defaultMessage: 'Add rule setup guide...',
}
);

export const AUTHOR_IMMUTABLE_FIELD_TOOLTIP_TEXT = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutrule.authorImmutableFieldTooltipText',
export const AUTHOR_FIELD_LABEL = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldAuthorLabel',
{
defaultMessage: 'Author is not editable for Elastic rules',
defaultMessage: 'Author',
}
);

export const LICENSE_IMMUTABLE_FIELD_TOOLTIP_TEXT = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutrule.licenseImmutableFieldTooltipText',
export const LICENSE_FIELD_LABEL = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldLicenseLabel',
{
defaultMessage: 'License is not editable for Elastic rules',
defaultMessage: 'License',
}
);

export const FIELD_NOT_EDITABLE_TOOLTIP_TEXT = (fieldName: string) =>
i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldNotEditableTooltipText',
{
defaultMessage: "{fieldName} can't be edited for Elastic rules.",
values: {
fieldName,
},
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => {
usePrebuiltRulesCustomizationStatus();
const canEditRule = isRulesCustomizationEnabled || !rule.immutable;

const prebuiltCustomizationUpsellingMessage = usePrebuiltRuleCustomizationUpsellingMessage();
const prebuiltCustomizationUpsellingMessage = usePrebuiltRuleCustomizationUpsellingMessage(
'prebuilt_rule_customization_description'
);

const { detailName: ruleId } = useParams<{ detailName: string }>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import React from 'react';
import useToggle from 'react-use/lib/useToggle';
import { EuiPopover, EuiText, EuiButtonIcon } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { TITLE } from './translations';
import * as i18n from './translations';
import type { VersionsPickerOptionEnum } from './versions_picker/versions_picker';
import { useFieldUpgradeContext } from '../rule_upgrade/field_upgrade_context';
import { getOptionDetails } from './utils';

/**
Expand All @@ -30,10 +29,7 @@ interface ComparisonSideHelpInfoProps {
export function ComparisonSideHelpInfo({ options }: ComparisonSideHelpInfoProps): JSX.Element {
const [isPopoverOpen, togglePopover] = useToggle(false);

const { hasResolvedValueDifferentFromSuggested } = useFieldUpgradeContext();
const optionsWithDescriptions = options.map((option) =>
getOptionDetails(option, hasResolvedValueDifferentFromSuggested)
);
const optionsWithDescriptions = options.map((option) => getOptionDetails(option));

const button = (
<EuiButtonIcon
Expand All @@ -48,25 +44,20 @@ export function ComparisonSideHelpInfo({ options }: ComparisonSideHelpInfoProps)
<EuiText style={{ width: POPOVER_WIDTH }} size="s">
<FormattedMessage
id="xpack.securitySolution.detectionEngine.rules.upgradeRules.comparisonSide.upgradeHelpText"
defaultMessage="The {title} lets you compare the values of a field across different versions of a rule: {versions} Differences are shown as JSON, with red lines showing what was removed, green lines showing additions, and bold text highlighting changes. Use {title} to review and understand changes across versions."
defaultMessage="The {title} lets you compare the values of a field across different versions of a rule:"
values={{
title: <strong>{TITLE}</strong>,
versions: (
<>
<br />
<ul>
{optionsWithDescriptions.map(
({ title: displayName, description: explanation }) => (
<li key={displayName}>
<strong>{displayName}</strong> {'-'} {explanation}
</li>
)
)}
</ul>
</>
),
title: <strong>{i18n.TITLE}</strong>,
}}
/>
<ul>
{optionsWithDescriptions.map(({ title: displayName, description: explanation }) => (
<li key={displayName}>
<strong>{displayName}</strong>
{':'} {explanation}
</li>
))}
</ul>
<p>{i18n.DIFF_FORMAT_AND_COLORS_EXPLANATION}</p>
</EuiText>
</EuiPopover>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function FieldComparisonSide(): JSX.Element {
) {
setSelectedOption(VersionsPickerOptionEnum.MyChanges);
}
}, [hasResolvedValueDifferentFromSuggested, selectedOption, prevResolvedValue, resolvedValue]);
}, [selectedOption, prevResolvedValue, resolvedValue]);

return (
<>
Expand All @@ -73,7 +73,6 @@ export function FieldComparisonSide(): JSX.Element {
options={options}
selectedOption={selectedOption}
onChange={setSelectedOption}
hasResolvedValueDifferentFromSuggested={hasResolvedValueDifferentFromSuggested}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,40 @@ export const NO_CHANGES = i18n.translate(
export const UPDATE_FROM_ELASTIC_TITLE = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.updateFromElasticTitle',
{
defaultMessage: 'Update from Elastic',
defaultMessage: 'Changes from Elastic',
}
);

export const UPDATE_FROM_ELASTIC_EXPLANATION = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.updateFromElasticExplanation',
{
defaultMessage: 'view the changes in Elastic’s latest update',
defaultMessage:
"Compare the field's original value with changes from the Elastic update. Your changes aren't displayed.",
}
);

export const MY_CHANGES_TITLE = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myChangesTitle',
export const MY_CHANGES_AND_FINAL_UPDATES_TITLE = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myChangesAndFinalUpdatesTitle',
{
defaultMessage: 'My changes',
defaultMessage: 'My changes and final updates',
}
);

export const MY_CHANGES_EXPLANATION = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myChangesExplanation',
export const MY_CHANGES_AND_FINAL_UPDATES_EXPLANATION = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myChangesAndFinalUpdatesExplanation',
{
defaultMessage: `view what you have changed in your installed rule and in the {finalUpdateSectionLabel} section`,
defaultMessage:
"Compare the field's original value with your changes or changes made in the {finalUpdateSectionLabel} section.",
values: {
finalUpdateSectionLabel: FINAL_UPDATE,
},
}
);

export const MY_CHANGES_IN_RULE_UPGRADE_WORKFLOW_EXPLANATION = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myChangesFinalUpdateOnlyExplanation',
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myChangesInRuleUpdateWorkflowOnlyExplanation',
{
defaultMessage: `view the changes you made in the {finalUpdateSectionLabel} section`,
defaultMessage: 'View the changes you made in the {finalUpdateSectionLabel} section.',
values: {
finalUpdateSectionLabel: FINAL_UPDATE,
},
Expand All @@ -66,30 +68,40 @@ export const MY_CHANGES_IN_RULE_UPGRADE_WORKFLOW_EXPLANATION = i18n.translate(
export const MERGED_CHANGES_TITLE = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.mergedChangesTitle',
{
defaultMessage: 'My changes merged with Elastic’s',
defaultMessage: "My changes merged with Elastic's",
}
);

export const MERGED_CHANGES_EXPLANATION = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.mergedChangesExplanation',
{
defaultMessage: 'view an update suggestion that combines your changes with Elastic’s',
defaultMessage:
"Compare the field's original value with a version that combines your changes with those in the Elastic update. This version is only a suggestion.",
}
);

export const MY_ORIGINAL_CHANGES_TITLE = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myOriginalChangesTitle',
{
defaultMessage: 'My original changes',
defaultMessage: 'My changes only',
}
);

export const MY_ORIGINAL_CHANGES_EXPLANATION = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myCustomizationExplanation',
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.myOriginalChangesExplanation',
{
defaultMessage: `view what you have changed in your installed rule. Doesn’t include changes made in the {finalUpdateSectionLabel} section.`,
defaultMessage:
"Compare the field's original value with your changes. Modifications in the {finalUpdateSectionLabel} section aren't displayed.",
values: {
finalUpdateSectionLabel: FINAL_UPDATE,
},
}
);

export const DIFF_FORMAT_AND_COLORS_EXPLANATION = i18n.translate(
'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.diffFormatAndColorsExplanation',
{
defaultMessage:
"Differences are shown in JSON and color-coded or bolded. Lines that are highlighted in green were added. Lines that are highlighted in red were removed. Text that's bolded was changed.",
}
);
Loading

0 comments on commit 994201c

Please sign in to comment.