Skip to content

Commit

Permalink
[8.x] [Cloud Security] User Name Misconfiguration Table and Preview C…
Browse files Browse the repository at this point in the history
…ontextual Flyout (#192946) (#193438)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Cloud Security] User Name Misconfiguration Table and Preview
Contextual Flyout
(#192946)](#192946)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Rickyanto
Ang","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-09-18T17:55:00Z","message":"[Cloud
Security] User Name Misconfiguration Table and Preview Contextual Flyout
(#192946)\n\n## Summary\r\n\r\nThis PR is the implementation of
Misconfiguration Preview and Data table\r\non user.name flyout in Alerts
Page.\r\n<img width=\"1717\" alt=\"Screenshot 2024-09-14 at 12 54
37 AM\"\r\nsrc=\"https://github.com/user-attachments/assets/ad405a4a-9820-4bb1-87f0-7e915eeb003b\">\r\nHow
to test:\r\nPre req: In order to test this, you need to generate some
fake alerts.\r\nThis
[repo](https://github.com/elastic/security-documents-generator)\r\nwill
help you do that\r\n\r\n1. Generate Some Alerts\r\n2. Use the Reindex
API to get some Findings data in (change the\r\nhost.name field to match
the host.name from alerts generated if you want\r\nto test Findings
table in the left panel flyout)\r\n3. Turn on Risky Entity Score if you
want to test if both Risk\r\nContribution and Insights tabs shows up,
follow
this\r\n[guide](https://www.elastic.co/guide/en/security/current/turn-on-risk-engine.html)\r\nto
turn on Risk Entity
Score","sha":"4d4afa55b378deb09936259d826f05a7bfeead12","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Cloud
Security","backport:prev-minor","ci:project-deploy-security","v8.16.0"],"title":"[Cloud
Security] User Name Misconfiguration Table and Preview Contextual
Flyout","number":192946,"url":"https://github.com/elastic/kibana/pull/192946","mergeCommit":{"message":"[Cloud
Security] User Name Misconfiguration Table and Preview Contextual Flyout
(#192946)\n\n## Summary\r\n\r\nThis PR is the implementation of
Misconfiguration Preview and Data table\r\non user.name flyout in Alerts
Page.\r\n<img width=\"1717\" alt=\"Screenshot 2024-09-14 at 12 54
37 AM\"\r\nsrc=\"https://github.com/user-attachments/assets/ad405a4a-9820-4bb1-87f0-7e915eeb003b\">\r\nHow
to test:\r\nPre req: In order to test this, you need to generate some
fake alerts.\r\nThis
[repo](https://github.com/elastic/security-documents-generator)\r\nwill
help you do that\r\n\r\n1. Generate Some Alerts\r\n2. Use the Reindex
API to get some Findings data in (change the\r\nhost.name field to match
the host.name from alerts generated if you want\r\nto test Findings
table in the left panel flyout)\r\n3. Turn on Risky Entity Score if you
want to test if both Risk\r\nContribution and Insights tabs shows up,
follow
this\r\n[guide](https://www.elastic.co/guide/en/security/current/turn-on-risk-engine.html)\r\nto
turn on Risk Entity
Score","sha":"4d4afa55b378deb09936259d826f05a7bfeead12"}},"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/192946","number":192946,"mergeCommit":{"message":"[Cloud
Security] User Name Misconfiguration Table and Preview Contextual Flyout
(#192946)\n\n## Summary\r\n\r\nThis PR is the implementation of
Misconfiguration Preview and Data table\r\non user.name flyout in Alerts
Page.\r\n<img width=\"1717\" alt=\"Screenshot 2024-09-14 at 12 54
37 AM\"\r\nsrc=\"https://github.com/user-attachments/assets/ad405a4a-9820-4bb1-87f0-7e915eeb003b\">\r\nHow
to test:\r\nPre req: In order to test this, you need to generate some
fake alerts.\r\nThis
[repo](https://github.com/elastic/security-documents-generator)\r\nwill
help you do that\r\n\r\n1. Generate Some Alerts\r\n2. Use the Reindex
API to get some Findings data in (change the\r\nhost.name field to match
the host.name from alerts generated if you want\r\nto test Findings
table in the left panel flyout)\r\n3. Turn on Risky Entity Score if you
want to test if both Risk\r\nContribution and Insights tabs shows up,
follow
this\r\n[guide](https://www.elastic.co/guide/en/security/current/turn-on-risk-engine.html)\r\nto
turn on Risk Entity
Score","sha":"4d4afa55b378deb09936259d826f05a7bfeead12"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Rickyanto Ang <[email protected]>
  • Loading branch information
kibanamachine and animehart authored Sep 19, 2024
1 parent 5185338 commit d4ffb9b
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,55 +6,16 @@
*/

import React, { memo } from 'react';
import { EuiButtonGroup, EuiSpacer } from '@elastic/eui';
import type { EuiButtonGroupOptionProps } from '@elastic/eui/src/components/button/button_group/button_group';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { useExpandableFlyoutState } from '@kbn/expandable-flyout';
import { EuiSpacer } from '@elastic/eui';
import { MisconfigurationFindingsDetailsTable } from './misconfiguration_findings_details_table';

enum InsightsTabCspTab {
MISCONFIGURATION = 'misconfigurationTabId',
}

const insightsButtons: EuiButtonGroupOptionProps[] = [
{
id: InsightsTabCspTab.MISCONFIGURATION,
label: (
<FormattedMessage
id="xpack.securitySolution.flyout.left.insights.misconfigurationButtonLabel"
defaultMessage="Misconfiguration"
/>
),
'data-test-subj': 'misconfigurationTabDataTestId',
},
];

/**
* Insights view displayed in the document details expandable flyout left section
*/
export const InsightsTabCsp = memo(
({ name, fieldName }: { name: string; fieldName: 'host.name' | 'user.name' }) => {
const panels = useExpandableFlyoutState();
const activeInsightsId = panels.left?.path?.subTab ?? 'misconfigurationTabId';

return (
<>
<EuiButtonGroup
color="primary"
legend={i18n.translate(
'xpack.securitySolution.flyout.left.insights.optionsButtonGroups',
{
defaultMessage: 'Insights options',
}
)}
options={insightsButtons}
idSelected={activeInsightsId}
onChange={() => {}}
buttonSize="compressed"
isFullWidth
data-test-subj={'insightButtonGroupsTestId'}
/>
<EuiSpacer size="xl" />
<MisconfigurationFindingsDetailsTable fieldName={fieldName} queryName={name} />
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ export const MisconfigurationFindingsDetailsTable = memo(

const navToFindings = useNavigateFindings();

const navToFindingsByHostName = (hostName: string) => {
navToFindings({ 'host.name': hostName }, ['rule.name']);
};

const navToFindingsByRuleAndResourceId = (ruleId: string, resourceId: string) => {
navToFindings({ 'rule.id': ruleId, 'resource.id': resourceId });
};

const navToFindingsByName = (name: string, queryField: 'host.name' | 'user.name') => {
navToFindings({ [queryField]: name }, ['rule.name']);
};

const columns: Array<EuiBasicTableColumn<MisconfigurationFindingDetailFields>> = [
{
field: 'rule',
Expand Down Expand Up @@ -154,13 +154,13 @@ export const MisconfigurationFindingsDetailsTable = memo(
<EuiPanel hasShadow={false}>
<EuiLink
onClick={() => {
navToFindingsByHostName(queryName);
navToFindingsByName(queryName, fieldName);
}}
>
{i18n.translate(
'xpack.securitySolution.flyout.left.insights.misconfigurations.tableTitle',
{
defaultMessage: 'Misconfigurations',
defaultMessage: 'Misconfigurations ',
}
)}
<EuiIcon type={'popout'} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { useCspSetupStatusApi } from '@kbn/cloud-security-posture/src/hooks/use_csp_setup_status_api';
import { MisconfigurationsPreview } from './misconfiguration/misconfiguration_preview';

export const EntityInsight = <T,>({ hostName }: { hostName: string }) => {
export const EntityInsight = <T,>({
name,
fieldName,
isPreviewMode,
}: {
name: string;
fieldName: 'host.name' | 'user.name';
isPreviewMode?: boolean;
}) => {
const { euiTheme } = useEuiTheme();
const getSetupStatus = useCspSetupStatusApi();
const hasMisconfigurationFindings = getSetupStatus.data?.hasMisconfigurationsFindings;
Expand All @@ -22,7 +30,6 @@ export const EntityInsight = <T,>({ hostName }: { hostName: string }) => {
<>
{hasMisconfigurationFindings && (
<>
<EuiHorizontalRule />
<EuiAccordion
initialIsOpen={true}
id="entityInsight-accordion"
Expand All @@ -45,9 +52,14 @@ export const EntityInsight = <T,>({ hostName }: { hostName: string }) => {
}
>
<EuiSpacer size="m" />
<MisconfigurationsPreview hostName={hostName} />
<MisconfigurationsPreview
name={name}
fieldName={fieldName}
isPreviewMode={isPreviewMode}
/>
<EuiSpacer size="m" />
</EuiAccordion>
<EuiHorizontalRule />
</>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import { render } from '@testing-library/react';
import React from 'react';
import { MisconfigurationsPreview } from './misconfiguration_preview';

const mockProps = {
hostName: 'testContextID',
const mockProps: { name: string; fieldName: 'host.name' | 'user.name' } = {
name: 'testContextID',
fieldName: 'host.name',
};

describe('MisconfigurationsPreview', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import { i18n } from '@kbn/i18n';
import { ExpandablePanel } from '@kbn/security-solution-common';
import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { UserDetailsPanelKey } from '../../../flyout/entity_details/user_details_left';
import { HostDetailsPanelKey } from '../../../flyout/entity_details/host_details_left';
import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score';
import { RiskScoreEntity } from '../../../../common/entity_analytics/risk_engine';
import { buildHostNamesFilter } from '../../../../common/search_strategy';
import type { HostRiskScore, UserRiskScore } from '../../../../common/search_strategy';
import { buildHostNamesFilter, buildUserNamesFilter } from '../../../../common/search_strategy';

const FIRST_RECORD_PAGINATION = {
cursorStart: 0,
Expand Down Expand Up @@ -120,46 +122,63 @@ const MisconfigurationPreviewScore = ({
);
};

export const MisconfigurationsPreview = ({ hostName }: { hostName: string }) => {
export const MisconfigurationsPreview = ({
name,
fieldName,
isPreviewMode,
}: {
name: string;
fieldName: 'host.name' | 'user.name';
isPreviewMode?: boolean;
}) => {
const { data } = useMisconfigurationPreview({
query: buildEntityFlyoutPreviewQuery('host.name', hostName),
query: buildEntityFlyoutPreviewQuery(fieldName, name),
sort: [],
enabled: true,
pageSize: 1,
});

const isUsingHostName = fieldName === 'host.name';
const passedFindings = data?.count.passed || 0;
const failedFindings = data?.count.failed || 0;

const { euiTheme } = useEuiTheme();
const hasMisconfigurationFindings = passedFindings > 0 || failedFindings > 0;
const hostNameFilterQuery = useMemo(
() => (hostName ? buildHostNamesFilter([hostName]) : undefined),
[hostName]

const buildFilterQuery = useMemo(
() => (isUsingHostName ? buildHostNamesFilter([name]) : buildUserNamesFilter([name])),
[isUsingHostName, name]
);

const riskScoreState = useRiskScore({
riskEntity: RiskScoreEntity.host,
filterQuery: hostNameFilterQuery,
riskEntity: isUsingHostName ? RiskScoreEntity.host : RiskScoreEntity.user,
filterQuery: buildFilterQuery,
onlyLatest: false,
pagination: FIRST_RECORD_PAGINATION,
});
const { data: hostRisk } = riskScoreState;
const hostRiskData = hostRisk && hostRisk.length > 0 ? hostRisk[0] : undefined;
const isRiskScoreExist = !!hostRiskData?.host.risk;
const riskData = hostRisk?.[0];
const isRiskScoreExist = isUsingHostName
? !!(riskData as HostRiskScore)?.host.risk
: !!(riskData as UserRiskScore)?.user.risk;
const { openLeftPanel } = useExpandableFlyoutApi();
const isPreviewMode = false;
const goToEntityInsightTab = useCallback(() => {
openLeftPanel({
id: HostDetailsPanelKey,
params: {
name: hostName,
isRiskScoreExist,
hasMisconfigurationFindings,
path: { tab: 'csp_insights' },
},
id: isUsingHostName ? HostDetailsPanelKey : UserDetailsPanelKey,
params: isUsingHostName
? {
name,
isRiskScoreExist,
hasMisconfigurationFindings,
path: { tab: 'csp_insights' },
}
: {
user: { name },
isRiskScoreExist,
hasMisconfigurationFindings,
path: { tab: 'csp_insights' },
},
});
}, [hasMisconfigurationFindings, hostName, isRiskScoreExist, openLeftPanel]);
}, [hasMisconfigurationFindings, isRiskScoreExist, isUsingHostName, name, openLeftPanel]);
const link = useMemo(
() =>
!isPreviewMode
Expand All @@ -178,7 +197,7 @@ export const MisconfigurationsPreview = ({ hostName }: { hostName: string }) =>
return (
<ExpandablePanel
header={{
iconType: hasMisconfigurationFindings ? 'arrowStart' : '',
iconType: !isPreviewMode && hasMisconfigurationFindings ? 'arrowStart' : '',
title: (
<EuiText
size="xs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const HostPanelContent = ({
entity={{ name: hostName, type: 'host' }}
onChange={onAssetCriticalityChange}
/>
<EntityInsight name={hostName} fieldName={'host.name'} isPreviewMode={isPreviewMode} />
<ObservedEntity
observedData={observedHost}
contextID={contextID}
Expand All @@ -72,7 +73,6 @@ export const HostPanelContent = ({
observedFields={observedFields}
queryId={HOST_PANEL_OBSERVED_HOST_QUERY_ID}
/>
<EntityInsight hostName={hostName} />
</FlyoutBody>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,46 @@ describe('LeftPanel', () => {

expect(tabElement).not.toBeInTheDocument();
});

it("doesn't render insights panel when there no misconfiguration findings", () => {
const { queryByText } = render(
<UserDetailsPanel
path={{
tab: EntityDetailsLeftPanelTab.RISK_INPUTS,
}}
isRiskScoreExist
user={{ name: 'test user', email: [] }}
scopeId={'scopeId'}
hasMisconfigurationFindings={false}
/>,
{
wrapper: TestProviders,
}
);

const tabElement = queryByText('Insights');

expect(tabElement).not.toBeInTheDocument();
});

it('render insights panel when there are misconfiguration findings', () => {
const { queryByText } = render(
<UserDetailsPanel
path={{
tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS,
}}
isRiskScoreExist
user={{ name: 'test user', email: [] }}
scopeId={'scopeId'}
hasMisconfigurationFindings={true}
/>,
{
wrapper: TestProviders,
}
);

const tabElement = queryByText('Insights');

expect(tabElement).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface UserDetailsPanelProps extends Record<string, unknown> {
user: UserParam;
path?: PanelPath;
scopeId: string;
hasMisconfigurationFindings?: boolean;
}
export interface UserDetailsExpandableFlyoutProps extends FlyoutPanelProps {
key: 'user_details';
Expand All @@ -40,10 +41,24 @@ export const UserDetailsPanel = ({
user,
path,
scopeId,
hasMisconfigurationFindings,
}: UserDetailsPanelProps) => {
const managedUser = useManagedUser(user.name, user.email);
const tabs = useTabs(managedUser.data, user.name, isRiskScoreExist, scopeId);
const { selectedTabId, setSelectedTabId } = useSelectedTab(isRiskScoreExist, user, tabs, path);
const tabs = useTabs(
managedUser.data,
user.name,
isRiskScoreExist,
scopeId,
hasMisconfigurationFindings
);

const { selectedTabId, setSelectedTabId } = useSelectedTab(
isRiskScoreExist,
user,
tabs,
path,
hasMisconfigurationFindings
);

if (managedUser.isLoading) return <FlyoutLoading />;

Expand All @@ -67,7 +82,8 @@ const useSelectedTab = (
isRiskScoreExist: boolean,
user: UserParam,
tabs: LeftPanelTabsType,
path: PanelPath | undefined
path: PanelPath | undefined,
hasMisconfigurationFindings?: boolean
) => {
const { openLeftPanel } = useExpandableFlyoutApi();

Expand All @@ -81,12 +97,13 @@ const useSelectedTab = (
const setSelectedTabId = (tabId: EntityDetailsLeftPanelTab) => {
openLeftPanel({
id: UserDetailsPanelKey,
path: {
tab: tabId,
},
params: {
user,
isRiskScoreExist,
hasMisconfigurationFindings,
path: {
tab: tabId,
},
},
});
};
Expand Down
Loading

0 comments on commit d4ffb9b

Please sign in to comment.