Skip to content

Commit

Permalink
[Security Solution] [Entity Analytics] Correct References under 'Usef…
Browse files Browse the repository at this point in the history
…ul Links' in Risk Score Enablement page (#171089)

## Summary

Get rid of `Host/User` distinction in risk scoring and replace it with
`Entity`, as per:
[#7920](elastic/security-team#7920)


### Checklist

Delete any items that are not applicable to this PR.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [x] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)



### For maintainers

- [x] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: Sergi Massaneda <sergi.massaneda@gmail.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 23, 2023
1 parent 49d1b6d commit 3ec310b
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 95 deletions.
4 changes: 2 additions & 2 deletions x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ export const RISKY_HOSTS_DOC_LINK =
'https://www.elastic.co/guide/en/security/current/host-risk-score.html';
export const RISKY_USERS_DOC_LINK =
'https://www.elastic.co/guide/en/security/current/user-risk-score.html';
export const DETECTION_ENTITY_DASHBOARD =
'https://www.elastic.co/guide/en/security/current/detection-entity-dashboard.html';
export const RISKY_ENTITY_SCORE_DOC_LINK =
'https://www.elastic.co/guide/en/security/current/advanced-entity-analytics-overview.html#entity-risk-scoring';

export const MAX_NUMBER_OF_NEW_TERMS_FIELDS = 3;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,17 @@ import {
EuiAccordion,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import {
DETECTION_ENTITY_DASHBOARD,
RISKY_HOSTS_DOC_LINK,
RISKY_USERS_DOC_LINK,
} from '../../../common/constants';
import { LinkAnchor } from '@kbn/security-solution-navigation/links';
import { SecurityPageName } from '@kbn/security-solution-navigation';
import * as i18n from '../translations';
import { useRiskEngineStatus } from '../api/hooks/use_risk_engine_status';
import { useInitRiskEngineMutation } from '../api/hooks/use_init_risk_engine_mutation';
import { useEnableRiskEngineMutation } from '../api/hooks/use_enable_risk_engine_mutation';
import { useDisableRiskEngineMutation } from '../api/hooks/use_disable_risk_engine_mutation';
import { RiskEngineStatus, MAX_SPACES_COUNT } from '../../../common/risk_engine';

const docsLinks = [
{
link: DETECTION_ENTITY_DASHBOARD,
label: i18n.EA_DOCS_DASHBOARD,
},
{
link: RISKY_HOSTS_DOC_LINK,
label: i18n.EA_DOCS_RISK_HOSTS,
},
{
link: RISKY_USERS_DOC_LINK,
label: i18n.EA_DOCS_RISK_USERS,
},
];
import { RiskInformationFlyout } from '../../explore/components/risk_score/risk_information';
import { useOnOpenCloseHandler } from '../../helper_hooks';

const MIN_WIDTH_TO_PREVENT_LABEL_FROM_MOVING = '50px';

Expand Down Expand Up @@ -209,6 +194,8 @@ export const RiskScoreEnableSection = () => {
const closeModal = () => setIsModalVisible(false);
const showModal = () => setIsModalVisible(true);

const [isFlyoutVisible, handleOnOpen, handleOnClose] = useOnOpenCloseHandler();

const isLoading =
initRiskEngineMutation.isLoading ||
enableRiskEngineMutation.isLoading ||
Expand Down Expand Up @@ -345,14 +332,17 @@ export const RiskScoreEnableSection = () => {
</EuiTitle>
<EuiSpacer />
<ul>
{docsLinks.map(({ link, label }) => (
<li key={link}>
<EuiLink href={link} target="_blank" external>
{label}
</EuiLink>
<EuiSpacer size="s" />
</li>
))}
<li>
<LinkAnchor id={SecurityPageName.entityAnalytics}>{i18n.EA_DASHBOARD_LINK}</LinkAnchor>
<EuiSpacer size="s" />
</li>
<li>
<EuiLink onClick={handleOnOpen} data-test-subj="open-risk-information-flyout-trigger">
{i18n.EA_DOCS_ENTITY_RISK_SCORE}
</EuiLink>
{isFlyoutVisible && <RiskInformationFlyout handleOnClose={handleOnClose} />}
<EuiSpacer size="s" />
</li>
</ul>
</>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const RISK_SCORE_MODULE_STATUS_OFF = i18n.translate(
export const ENTITY_RISK_SCORING = i18n.translate(
'xpack.securitySolution.riskScore.riskScorePreview.entityRiskScoring',
{
defaultMessage: 'Entity risk scoring',
defaultMessage: 'Entity risk score',
}
);

Expand All @@ -70,10 +70,10 @@ export const USEFUL_LINKS = i18n.translate(
}
);

export const EA_DOCS_DASHBOARD = i18n.translate(
export const EA_DASHBOARD_LINK = i18n.translate(
'xpack.securitySolution.riskScore.riskScorePreview.eaDocsDashboard',
{
defaultMessage: 'Entity Analytics documentation',
defaultMessage: 'Entity Analytics dashboard',
}
);

Expand All @@ -91,6 +91,13 @@ export const EA_DOCS_RISK_USERS = i18n.translate(
}
);

export const EA_DOCS_ENTITY_RISK_SCORE = i18n.translate(
'xpack.securitySolution.riskScore.riskScorePreview.eaDocsEntities',
{
defaultMessage: 'How is the risk score calculated?',
}
);

export const PREVIEW = i18n.translate('xpack.securitySolution.riskScore.riskScorePreview.preview', {
defaultMessage: 'Preview',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ import {
import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { css } from '@emotion/react';
import { getRiskEntityTranslation } from '../translations';

import * as i18n from './translations';
import { useOnOpenCloseHandler } from '../../../../helper_hooks';
import { RiskScoreLevel } from '../severity/common';
import { RiskScoreEntity, RiskSeverity } from '../../../../../common/search_strategy';
import { RiskScoreDocLink } from '../risk_score_onboarding/risk_score_doc_link';
import { BETA } from '../risk_score_onboarding/translations';

const getTableColumns = (riskEntity: RiskScoreEntity): Array<EuiBasicTableColumn<TableItem>> => [
const getTableColumns = (riskEntity?: RiskScoreEntity): Array<EuiBasicTableColumn<TableItem>> => [
{
field: 'level',
name: i18n.INFORMATION_LEVEL_HEADER,
Expand Down Expand Up @@ -85,9 +85,7 @@ export const RiskInformationButtonIcon = ({ riskEntity }: { riskEntity: RiskScor
}
data-test-subj="open-risk-information-flyout-trigger"
/>
{isFlyoutVisible && (
<RiskInformationFlyout riskEntity={riskEntity} handleOnClose={handleOnClose} />
)}
{isFlyoutVisible && <RiskInformationFlyout handleOnClose={handleOnClose} />}
</>
);
};
Expand All @@ -100,20 +98,12 @@ export const RiskInformationButtonEmpty = ({ riskEntity }: { riskEntity: RiskSco
<EuiButtonEmpty onClick={handleOnOpen} data-test-subj="open-risk-information-flyout-trigger">
{i18n.INFO_BUTTON_TEXT}
</EuiButtonEmpty>
{isFlyoutVisible && (
<RiskInformationFlyout riskEntity={riskEntity} handleOnClose={handleOnClose} />
)}
{isFlyoutVisible && <RiskInformationFlyout handleOnClose={handleOnClose} />}
</>
);
};

const RiskInformationFlyout = ({
handleOnClose,
riskEntity,
}: {
handleOnClose: () => void;
riskEntity: RiskScoreEntity;
}) => {
export const RiskInformationFlyout = ({ handleOnClose }: { handleOnClose: () => void }) => {
const { euiTheme } = useEuiTheme();
const simpleFlyoutTitleId = useGeneratedHtmlId({
prefix: 'RiskInformation',
Expand Down Expand Up @@ -157,15 +147,13 @@ const RiskInformationFlyout = ({
<p>
<FormattedMessage
id="xpack.securitySolution.riskInformation.riskScoreFieldText"
defaultMessage="The {riskScoreField} field represents the normalized risk of the {riskEntity} as a single numerical value. You can use this value as a relative indicator of risk in triaging and response playbooks."
defaultMessage="The {riskScoreField} field represents the normalized risk of the Entity as a single numerical value. You can use this value as a relative indicator of risk in triaging and response playbooks."
values={{
riskEntity,
riskScoreField: (
<b>
<FormattedMessage
id="xpack.securitySolution.riskInformation.riskScoreFieldLabel"
defaultMessage="{riskEntity} risk score"
values={{ riskEntity }}
defaultMessage="Entity risk score"
/>
</b>
),
Expand All @@ -176,15 +164,13 @@ const RiskInformationFlyout = ({
<FormattedMessage
id="xpack.securitySolution.riskInformation.riskScoreLevelText"
defaultMessage="The {riskLevelField} field represents one of the six risk level of
the {riskEntity} based on a predefined risk metrics."
the Entity based on a predefined risk metrics."
values={{
riskEntity,
riskLevelField: (
<b>
<FormattedMessage
id="xpack.securitySolution.riskInformation.riskScoreLevelLabel"
defaultMessage="{riskEntity} risk level"
values={{ riskEntity }}
defaultMessage="Entity risk level"
/>
</b>
),
Expand Down Expand Up @@ -236,26 +222,22 @@ const RiskInformationFlyout = ({
<FormattedMessage
id="xpack.securitySolution.riskInformation.intro"
defaultMessage="Finally, the engine assigns a risk level by mapping the normalized risk score to the
below 6 risk levels."
below 5 risk levels."
/>
</p>
</EuiText>
<EuiSpacer />
<EuiBasicTable
columns={getTableColumns(riskEntity)}
columns={getTableColumns()}
items={tableItems}
data-test-subj="risk-information-table"
/>
<EuiSpacer size="l" />
<RiskScoreDocLink
riskScoreEntity={riskEntity}
title={
<FormattedMessage
id="xpack.securitySolution.riskInformation.learnMore"
defaultMessage="Learn more about {riskEntity} risk"
values={{
riskEntity: getRiskEntityTranslation(riskEntity, true),
}}
defaultMessage="Learn more about Entity risk"
/>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const INFORMATION_ARIA_LABEL = i18n.translate(
}
);

export const INFORMATION_RISK_HEADER = (riskEntity: RiskScoreEntity) =>
export const INFORMATION_RISK_HEADER = (riskEntity?: RiskScoreEntity) =>
i18n.translate('xpack.securitySolution.riskInformation.riskHeader', {
defaultMessage: '{riskEntity} risk score range',
values: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,31 @@
*/

import { EuiLink } from '@elastic/eui';
import React from 'react';
import React, { useMemo } from 'react';
import { RiskScoreEntity } from '../../../../../common/search_strategy';
import { RISKY_HOSTS_DOC_LINK, RISKY_USERS_DOC_LINK } from '../../../../../common/constants';
import {
RISKY_HOSTS_DOC_LINK,
RISKY_USERS_DOC_LINK,
RISKY_ENTITY_SCORE_DOC_LINK,
} from '../../../../../common/constants';
import { LEARN_MORE } from '../../../../overview/components/entity_analytics/risk_score/translations';

const RiskScoreDocLinkComponent = ({
riskScoreEntity,
title,
}: {
riskScoreEntity: RiskScoreEntity;
riskScoreEntity?: RiskScoreEntity;
title?: string | React.ReactNode;
}) => {
const docLink =
riskScoreEntity === RiskScoreEntity.user ? RISKY_USERS_DOC_LINK : RISKY_HOSTS_DOC_LINK;
const docLink = useMemo(() => {
if (!riskScoreEntity) {
return RISKY_ENTITY_SCORE_DOC_LINK;
}
if (riskScoreEntity === RiskScoreEntity.user) {
return RISKY_USERS_DOC_LINK;
}
return RISKY_HOSTS_DOC_LINK;
}, [riskScoreEntity]);

return (
<EuiLink target="_blank" rel="noopener nofollow noreferrer" href={docLink}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export const USERS = i18n.translate('xpack.securitySolution.riskScore.overview.u
defaultMessage: 'Users',
});

export const ENTITY = i18n.translate('xpack.securitySolution.riskScore.overview.entityTitle', {
defaultMessage: 'Entity',
});

export const ENTITIES = i18n.translate('xpack.securitySolution.riskScore.overview.entities', {
defaultMessage: 'Entities',
});

export const RISK_SCORE_TITLE = (riskEntity: RiskScoreEntity) =>
i18n.translate('xpack.securitySolution.riskScore.overview.riskScoreTitle', {
defaultMessage: '{riskEntity} Risk Score',
Expand All @@ -41,22 +49,26 @@ export const ENTITY_RISK_LEVEL = (riskEntity: RiskScoreEntity) =>
});

export const getRiskEntityTranslation = (
riskEntity: RiskScoreEntity,
riskEntity?: RiskScoreEntity,
lowercase = false,
plural = false
) => {
if (lowercase) {
if (plural) {
return (riskEntity === RiskScoreEntity.host ? HOSTS : USERS).toLowerCase();
}
const text = getRiskEntityTranslationText(riskEntity, plural);
return lowercase ? text.toLowerCase() : text;
};

return (riskEntity === RiskScoreEntity.host ? HOST : USER).toLowerCase();
}
if (plural) {
return riskEntity === RiskScoreEntity.host ? HOSTS : USERS;
export const getRiskEntityTranslationText = (
riskEntity: RiskScoreEntity | undefined,
plural: boolean
) => {
switch (riskEntity) {
case RiskScoreEntity.host:
return plural ? HOSTS : HOST;
case RiskScoreEntity.user:
return plural ? USERS : USER;
default:
return plural ? ENTITIES : ENTITY;
}

return riskEntity === RiskScoreEntity.host ? HOST : USER;
};

export const ALERTS = i18n.translate('xpack.securitySolution.riskScore.overview.alerts', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const VIEW_ALL = i18n.translate(
}
);

export const LEARN_MORE = (riskEntity: RiskScoreEntity) =>
export const LEARN_MORE = (riskEntity?: RiskScoreEntity) =>
i18n.translate('xpack.securitySolution.entityAnalytics.riskDashboard.learnMore', {
defaultMessage: 'Learn more about {riskEntity} risk',
values: {
Expand Down
5 changes: 0 additions & 5 deletions x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -32342,12 +32342,7 @@
"xpack.securitySolution.responseActionsList.list.recordRange": "Affichage de {range} sur {total} {recordsLabel}",
"xpack.securitySolution.responseActionsList.list.recordRangeLabel": "{records, plural, one {action de réponse} many {actions de réponse} other {actions de réponse}}",
"xpack.securitySolution.riskInformation.howCalculatedText": "Le dispositif Entity Risk s'exécute toutes les heures afin de regrouper les alertes \"Open\" et \"Acknowledged\" des 30 derniers jours et attribue un score de risque à l'hôte ou à l'utilisateur. Il agrège ensuite les scores de risque individuels et les normalise dans une fourchette de 0 à 100 à l'aide de {riemannZetaLink} .",
"xpack.securitySolution.riskInformation.learnMore": "En savoir plus sur les risques {riskEntity}.",
"xpack.securitySolution.riskInformation.riskHeader": "Plage de scores de risque de {riskEntity}",
"xpack.securitySolution.riskInformation.riskScoreFieldLabel": "Score de risque de {riskEntity}",
"xpack.securitySolution.riskInformation.riskScoreFieldText": "Le champ {riskScoreField} représente le risque normalisé du {riskEntity} sous la forme d'une valeur numérique unique. Vous pouvez utiliser cette valeur comme indicateur relatif du risque dans les playbooks de triage et de réponse.",
"xpack.securitySolution.riskInformation.riskScoreLevelLabel": "Niveau de risque {riskEntity}",
"xpack.securitySolution.riskInformation.riskScoreLevelText": "Le champ {riskLevelField} représente l'un des six niveaux de risque de {riskEntity}, sur la base d'indicateurs de risque prédéfinis.",
"xpack.securitySolution.riskScore.api.ingestPipeline.delete.errorMessageTitle": "Impossible de supprimer {totalCount, plural, =1 {pipeline} one {pipelines} many {pipelines} other {pipelines}} d'ingestion",
"xpack.securitySolution.riskScore.api.transforms.delete.errorMessageTitle": "Impossible de supprimer {totalCount, plural, =1 {Transformer} one {Transformations} many {Transformations} other {Transformations}}",
"xpack.securitySolution.riskScore.api.transforms.start.errorMessageTitle": "Impossible de démarrer {totalCount, plural, =1 {Transformer} one {Transformations} many {Transformations} other {Transformations}}",
Expand Down
5 changes: 0 additions & 5 deletions x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -32340,12 +32340,7 @@
"xpack.securitySolution.responseActionsList.list.recordRange": "{total} {recordsLabel}件中{range}を表示中",
"xpack.securitySolution.responseActionsList.list.recordRangeLabel": "{records, plural, other {対応アクション}}",
"xpack.securitySolution.riskInformation.howCalculatedText": "エンティティリスクエンジンは、過去30日間の\"オープン\"および\"確認済み\"アラートを集約し、ホストまたはユーザーにリスクスコアを割り当てるために1時間ごとに実行されます。次に、個々のリスクスコアを集約し、{riemannZetaLink}を使用して0~100の範囲に正規化します。",
"xpack.securitySolution.riskInformation.learnMore": "{riskEntity}リスクの詳細",
"xpack.securitySolution.riskInformation.riskHeader": "{riskEntity}リスクスコア範囲",
"xpack.securitySolution.riskInformation.riskScoreFieldLabel": "{riskEntity}リスクスコア",
"xpack.securitySolution.riskInformation.riskScoreFieldText": "{riskScoreField}フィールドは{riskEntity}の正規化されたリスクを1つの数値として表します。この値は、トリアージとレスポンスのプレイブックでリスクの相対的な指標として使用できます。",
"xpack.securitySolution.riskInformation.riskScoreLevelLabel": "{riskEntity}リスクレベル",
"xpack.securitySolution.riskInformation.riskScoreLevelText": "{riskLevelField}フィールドは、定義済みのリスクメトリックに基づく{riskEntity}の6つのリスクレベルのうちの1つを表します。",
"xpack.securitySolution.riskScore.api.ingestPipeline.delete.errorMessageTitle": "インジェスト{totalCount, plural, =1 {パイプライン} other {パイプライン}}を削除できませんでした",
"xpack.securitySolution.riskScore.api.transforms.delete.errorMessageTitle": "{totalCount, plural, =1 {変換} other {変換}}の削除に失敗しました",
"xpack.securitySolution.riskScore.api.transforms.start.errorMessageTitle": "{totalCount, plural, =1 {変換} other {変換}}の開始に失敗しました",
Expand Down
5 changes: 0 additions & 5 deletions x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -32336,12 +32336,7 @@
"xpack.securitySolution.responseActionsList.list.recordRange": "正在显示第 {range} 个(共 {total} 个){recordsLabel}",
"xpack.securitySolution.responseActionsList.list.recordRangeLabel": "{records, plural, other {响应操作}}",
"xpack.securitySolution.riskInformation.howCalculatedText": "实体风险引擎每小时运行一次,以聚合过去 30 天出现的“未结”和“已确认”告警,并为主机或用户分配风险分数。然后,它会聚合各个风险分数并使用 {riemannZetaLink} 将其标准化为 0-100 范围。",
"xpack.securitySolution.riskInformation.learnMore": "详细了解 {riskEntity} 风险",
"xpack.securitySolution.riskInformation.riskHeader": "{riskEntity} 风险分数范围",
"xpack.securitySolution.riskInformation.riskScoreFieldLabel": "{riskEntity} 风险分数",
"xpack.securitySolution.riskInformation.riskScoreFieldText": "{riskScoreField} 字段以单个数字值表示 {riskEntity} 的标准化风险。您可以在分类和响应 playbook 中将此值用作相对风险指标。",
"xpack.securitySolution.riskInformation.riskScoreLevelLabel": "{riskEntity} 风险级别",
"xpack.securitySolution.riskInformation.riskScoreLevelText": "{riskLevelField} 字段根据预定义的风险指标表示 {riskEntity} 的六个风险级别之一。",
"xpack.securitySolution.riskScore.api.ingestPipeline.delete.errorMessageTitle": "无法删除采集{totalCount, plural, =1 {管道} other {管道}}",
"xpack.securitySolution.riskScore.api.transforms.delete.errorMessageTitle": "无法删除{totalCount, plural, =1 {转换} other {转换}}",
"xpack.securitySolution.riskScore.api.transforms.start.errorMessageTitle": "无法启动{totalCount, plural, =1 {转换} other {转换}}",
Expand Down

0 comments on commit 3ec310b

Please sign in to comment.