mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Security Solution][Endpoint][Response Actions] Show an OS/platform icon on Responder for the running agent (#152821)
## Summary Adds a platform icon to the responder console header. In addition, it shows the applied policy name and agent platform in the `status` action result. <img width="282" alt="Screenshot 2023-03-07 at 11 59 52" src="https://user-images.githubusercontent.com/1849116/223464312-31890e22-a837-474c-955c-70a83cec9a68.png"> <img width="265" alt="Screenshot 2023-03-07 at 11 59 25" src="https://user-images.githubusercontent.com/1849116/223464316-ef22c4e8-59f6-4d52-bd4d-4795fabfc2ae.png"> <img width="283" alt="Screenshot 2023-03-07 at 11 58 09" src="https://user-images.githubusercontent.com/1849116/223464319-5f69e1f9-32e5-4ec0-b841-59acf7e152c1.png"> <img width="760" alt="Screenshot 2023-03-09 at 15 27 32" src="https://user-images.githubusercontent.com/1849116/224056980-90257b17-8e91-434a-a7fb-cb0dae789755.png"> **Last seen date Fix** Here's a clip with and without the additional style where you can see that there's additional spacing on the date item. This is an existing issue and has not been introduced with the new changes in the PR.  ### Checklist - [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) - [ ] [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 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] 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)
This commit is contained in:
parent
4c586a71d4
commit
c4ad98b685
9 changed files with 198 additions and 34 deletions
|
@ -165,6 +165,16 @@ export const EndpointStatusActionResult = memo<
|
|||
),
|
||||
description: <ConsoleCodeBlock>{agentStatus()}</ConsoleCodeBlock>,
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<ConsoleCodeBlock>
|
||||
{i18n.translate('xpack.securitySolution.endpointResponseActions.status.platform', {
|
||||
defaultMessage: 'Platform',
|
||||
})}
|
||||
</ConsoleCodeBlock>
|
||||
),
|
||||
description: <ConsoleCodeBlock>{endpointDetails.metadata.host.os.full}</ConsoleCodeBlock>,
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<ConsoleCodeBlock>
|
||||
|
@ -189,6 +199,37 @@ export const EndpointStatusActionResult = memo<
|
|||
</ConsoleCodeBlock>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<ConsoleCodeBlock>
|
||||
{i18n.translate(
|
||||
'xpack.securitySolution.endpointResponseActions.status.appliedPolicyVersion',
|
||||
{
|
||||
defaultMessage: 'Policy version',
|
||||
}
|
||||
)}
|
||||
</ConsoleCodeBlock>
|
||||
),
|
||||
description: (
|
||||
<ConsoleCodeBlock>
|
||||
{`v${endpointDetails.metadata.Endpoint.policy.applied.endpoint_policy_version}`}
|
||||
</ConsoleCodeBlock>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<ConsoleCodeBlock>
|
||||
{i18n.translate('xpack.securitySolution.endpointResponseActions.status.policyName', {
|
||||
defaultMessage: 'Policy name',
|
||||
})}
|
||||
</ConsoleCodeBlock>
|
||||
),
|
||||
description: (
|
||||
<ConsoleCodeBlock>
|
||||
{endpointDetails.metadata.Endpoint.policy.applied.name}
|
||||
</ConsoleCodeBlock>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<ConsoleCodeBlock>
|
||||
|
@ -205,7 +246,6 @@ export const EndpointStatusActionResult = memo<
|
|||
{ defaultMessage: 'Last active' }
|
||||
)}
|
||||
value={endpointDetails.metadata['@timestamp']}
|
||||
className="eui-textTruncate"
|
||||
/>
|
||||
</ConsoleCodeBlock>
|
||||
),
|
||||
|
|
|
@ -62,4 +62,8 @@ describe('Responder header endpoint info', () => {
|
|||
const lastUpdated = await renderResult.findByTestId('responderHeaderLastSeen');
|
||||
expect(lastUpdated).toBeTruthy();
|
||||
});
|
||||
it('should show platform icon', async () => {
|
||||
const platformIcon = await renderResult.findByTestId('responderHeaderEndpointPlatformIcon');
|
||||
expect(platformIcon).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,15 +10,25 @@ import {
|
|||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiLoadingContent,
|
||||
EuiSkeletonText,
|
||||
EuiToolTip,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react';
|
||||
import { useGetEndpointDetails } from '../../../hooks/endpoint/use_get_endpoint_details';
|
||||
import type { EndpointHostIsolationStatusProps } from '../../../../common/components/endpoint/host_isolation';
|
||||
import { EndpointAgentAndIsolationStatus } from '../../endpoint_agent_and_isolation_status';
|
||||
import { useGetEndpointPendingActionsSummary } from '../../../hooks/response_actions/use_get_endpoint_pending_actions_summary';
|
||||
import type { Platform } from './platforms';
|
||||
import { PlatformIcon } from './platforms';
|
||||
|
||||
const IconContainer = euiStyled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
interface HeaderEndpointInfoProps {
|
||||
endpointId: string;
|
||||
|
@ -48,7 +58,7 @@ export const HeaderEndpointInfo = memo<HeaderEndpointInfoProps>(({ endpointId })
|
|||
}, [endpointPendingActions?.data]);
|
||||
|
||||
if (isFetching && endpointPendingActions === undefined) {
|
||||
return <EuiLoadingContent lines={2} />;
|
||||
return <EuiSkeletonText lines={2} />;
|
||||
}
|
||||
|
||||
if (!endpointDetails) {
|
||||
|
@ -56,40 +66,52 @@ export const HeaderEndpointInfo = memo<HeaderEndpointInfoProps>(({ endpointId })
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs">
|
||||
<EuiFlexItem grow={false} className="eui-textTruncate">
|
||||
<EuiToolTip
|
||||
content={endpointDetails.metadata.host.name}
|
||||
anchorClassName="eui-textTruncate"
|
||||
>
|
||||
<EuiText size="s" data-test-subj="responderHeaderEndpointName">
|
||||
<h6 className="eui-textTruncate">{endpointDetails.metadata.host.name}</h6>
|
||||
</EuiText>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EndpointAgentAndIsolationStatus
|
||||
status={endpointDetails.host_status}
|
||||
isIsolated={endpointDetails.metadata.Endpoint.state?.isolation}
|
||||
{...pendingActionRequests}
|
||||
data-test-subj="responderHeaderEndpointAgentIsolationStatus"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<IconContainer>
|
||||
<PlatformIcon
|
||||
data-test-subj="responderHeaderEndpointPlatformIcon"
|
||||
platform={endpointDetails.metadata.host.os.name.toLowerCase() as Platform}
|
||||
/>
|
||||
</IconContainer>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiText color="subdued" size="s" data-test-subj="responderHeaderLastSeen">
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.responder.header.lastSeen"
|
||||
defaultMessage="Last seen {date}"
|
||||
values={{
|
||||
date: <FormattedRelative value={endpointDetails.metadata['@timestamp']} />,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs">
|
||||
<EuiFlexItem grow={false} className="eui-textTruncate">
|
||||
<EuiToolTip
|
||||
content={endpointDetails.metadata.host.name}
|
||||
anchorClassName="eui-textTruncate"
|
||||
>
|
||||
<EuiText size="s" data-test-subj="responderHeaderEndpointName">
|
||||
<h6 className="eui-textTruncate">{endpointDetails.metadata.host.name}</h6>
|
||||
</EuiText>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EndpointAgentAndIsolationStatus
|
||||
status={endpointDetails.host_status}
|
||||
isIsolated={endpointDetails.metadata.Endpoint.state?.isolation}
|
||||
{...pendingActionRequests}
|
||||
data-test-subj="responderHeaderEndpointAgentIsolationStatus"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiText color="subdued" size="s" data-test-subj="responderHeaderLastSeen">
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.responder.header.lastSeen"
|
||||
defaultMessage="Last seen {date}"
|
||||
values={{
|
||||
date: <FormattedRelative value={endpointDetails.metadata['@timestamp']} />,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { PlatformIcon, type Platform } from './platform_icon';
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 304.998 304.998"><path d="M274.659 244.888c-8.944-3.663-12.77-8.524-12.4-15.777.381-8.466-4.422-14.667-6.703-17.117 1.378-5.264 5.405-23.474.004-39.291-5.804-16.93-23.524-42.787-41.808-68.204-7.485-10.438-7.839-21.784-8.248-34.922-.392-12.531-.834-26.735-7.822-42.525C190.084 9.859 174.838 0 155.851 0c-11.295 0-22.889 3.53-31.811 9.684-18.27 12.609-15.855 40.1-14.257 58.291.219 2.491.425 4.844.545 6.853 1.064 17.816.096 27.206-1.17 30.06-.819 1.865-4.851 7.173-9.118 12.793-4.413 5.812-9.416 12.4-13.517 18.539-4.893 7.387-8.843 18.678-12.663 29.597-2.795 7.99-5.435 15.537-8.005 20.047a27.296 27.296 0 00-2.647 20.505c-1.844 1.281-4.508 3.803-6.757 8.557-2.718 5.8-8.233 8.917-19.701 11.122-5.27 1.078-8.904 3.294-10.804 6.586-2.765 4.791-1.259 10.811.115 14.925 2.03 6.048.765 9.876-1.535 16.826-.53 1.604-1.131 3.42-1.74 5.423-.959 3.161-.613 6.035 1.026 8.542 4.331 6.621 16.969 8.956 29.979 10.492 7.768.922 16.27 4.029 24.493 7.035 8.057 2.944 16.388 5.989 23.961 6.913 1.151.145 2.291.218 3.39.218 11.434 0 16.6-7.587 18.238-10.704 4.107-.838 18.272-3.522 32.871-3.882 14.576-.416 28.679 2.462 32.674 3.357 1.256 2.404 4.567 7.895 9.845 10.724 2.901 1.586 6.938 2.495 11.073 2.495h.001c4.416 0 12.817-1.044 19.466-8.039 6.632-7.028 23.202-16 35.302-22.551a717.87 717.87 0 007.441-4.065c6.797-3.768 10.506-9.152 10.175-14.771-.276-4.667-3.365-8.761-8.062-10.684zm-150.47-1.353c-.846-5.96-8.513-11.871-17.392-18.715-7.26-5.597-15.489-11.94-17.756-17.312-4.685-11.082-.992-30.568 5.447-40.602 3.182-5.024 5.781-12.643 8.295-20.011 2.714-7.956 5.521-16.182 8.66-19.783 4.971-5.622 9.565-16.561 10.379-25.182 4.655 4.444 11.876 10.083 18.547 10.083 1.027 0 2.024-.134 2.977-.403 4.564-1.318 11.277-5.197 17.769-8.947 5.597-3.234 12.499-7.222 15.096-7.585 4.453 6.394 30.328 63.655 32.972 82.044 2.092 14.55-.118 26.578-1.229 31.289a23.017 23.017 0 00-3.08-.221c-7.207 0-9.115 3.934-9.612 6.283-1.278 6.103-1.413 25.618-1.427 30.003-2.606 3.311-15.785 18.903-34.706 21.706-7.707 1.12-14.904 1.688-21.39 1.688-5.544 0-9.082-.428-10.551-.651l-9.508-10.879c3.749-1.851 7.497-5.757 6.509-12.805zm12.065-179.386c-.297.128-.589.265-.876.411a17.713 17.713 0 00-.199-1.952c-1.038-5.975-5-10.312-9.419-10.312-.327 0-.656.025-1.017.08-2.629.438-4.691 2.413-5.821 5.213.991-6.144 4.472-10.693 8.602-10.693 4.85 0 8.947 6.536 8.947 14.272 0 .975-.071 1.945-.217 2.981zm37.686 4.607c.444-1.414.684-2.944.684-4.532 0-7.014-4.45-12.509-10.131-12.509-5.552 0-10.069 5.611-10.069 12.509 0 .47.023.941.067 1.411l-.861-.329a19.125 19.125 0 01-.962-6.015c0-8.387 5.36-15.211 11.95-15.211 6.589 0 11.95 6.824 11.95 15.211 0 3.489-.963 6.819-2.628 9.465zm-4.859 16.324c-.095.424-.297.612-2.531 1.774-1.128.587-2.532 1.318-4.289 2.388l-1.174.711c-4.718 2.86-15.765 9.559-18.764 9.952-2.037.274-3.297-.516-6.13-2.441a88.441 88.441 0 00-2.044-1.362c-5.107-3.351-8.392-7.042-8.763-8.485 1.665-1.287 5.792-4.508 7.905-6.415 4.289-3.988 8.605-6.668 10.741-6.668.113 0 .215.008.321.028 2.51.443 8.701 2.914 13.223 4.718 2.09.834 3.895 1.554 5.165 2.01 4.001 1.374 6.087 3.132 6.34 3.79zm35.947 186.37c2.257-10.181 4.857-24.031 4.436-32.196-.097-1.855-.261-3.874-.42-5.826-.297-3.65-.738-9.075-.283-10.684.09-.042.19-.078.301-.109.019 4.668 1.033 13.979 8.479 17.226 2.219.968 4.755 1.458 7.537 1.458 7.459 0 15.735-3.659 19.125-7.049 1.996-1.996 3.675-4.438 4.851-6.372.257.753.415 1.737.332 3.005-.443 6.885 2.903 16.019 9.271 19.385l.927.487c2.268 1.19 8.292 4.353 8.389 5.853-.001.001-.051.177-.387.489-1.509 1.379-6.82 4.091-11.956 6.714-9.111 4.652-19.438 9.925-24.076 14.803-6.53 6.872-13.916 11.488-18.376 11.488a4.83 4.83 0 01-1.461-.206c-4.844-1.51-8.831-8.499-6.689-18.466zM39.917 245.477c-.494-2.312-.884-4.137-.465-5.905.304-1.31 6.771-2.714 9.533-3.313 3.883-.843 7.899-1.714 10.525-3.308 3.551-2.151 5.474-6.118 7.17-9.618 1.228-2.531 2.496-5.148 4.005-6.007.085-.05.215-.108.463-.108 2.827 0 8.759 5.943 12.177 11.262.867 1.341 2.473 4.028 4.331 7.139 5.557 9.298 13.166 22.033 17.14 26.301 3.581 3.837 9.378 11.214 7.952 17.541-1.044 4.909-6.602 8.901-7.913 9.784-.476.108-1.065.163-1.758.163-7.606 0-22.662-6.328-30.751-9.728l-1.197-.503c-4.517-1.894-11.891-3.087-19.022-4.241-5.674-.919-13.444-2.176-14.732-3.312-1.044-1.171.167-4.978 1.235-8.337.769-2.414 1.563-4.91 1.998-7.523.617-4.168-.109-7.561-.691-10.287z"/></svg>
|
After Width: | Height: | Size: 4.3 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 640 640"><path d="M494.782 340.02c-.803-81.025 66.084-119.907 69.072-121.832-37.595-54.993-96.167-62.552-117.037-63.402-49.843-5.032-97.242 29.362-122.565 29.362-25.253 0-64.277-28.607-105.604-27.85-54.32.803-104.4 31.594-132.403 80.245C29.81 334.457 71.81 479.58 126.816 558.976c26.87 38.882 58.914 82.56 100.997 81 40.512-1.594 55.843-26.244 104.848-26.244 48.993 0 62.753 26.245 105.64 25.406 43.606-.803 71.232-39.638 97.925-78.65 30.887-45.12 43.548-88.75 44.316-90.994-.969-.437-85.029-32.634-85.879-129.439l.118-.035zM414.23 102.178C436.553 75.095 451.636 37.5 447.514-.024c-32.162 1.311-71.163 21.437-94.253 48.485-20.729 24.012-38.836 62.28-33.993 99.036 35.918 2.8 72.591-18.248 94.926-45.272l.036-.047z"/></svg>
|
After Width: | Height: | Size: 946 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 640 640"><path d="M.2 298.669L0 90.615l256.007-34.76v242.814H.201zM298.658 49.654L639.905-.012v298.681H298.657V49.654zM640 341.331l-.071 298.681L298.669 592V341.332h341.33zM255.983 586.543L.189 551.463v-210.18h255.794v245.26z"/></svg>
|
After Width: | Height: | Size: 458 B |
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import type { AppContextTestRender } from '../../../../../common/mock/endpoint';
|
||||
import { createAppRootMockRenderer } from '../../../../../common/mock/endpoint';
|
||||
import { PlatformIcon, type PlatformIconProps } from './platform_icon';
|
||||
|
||||
describe('PlatformIcon', () => {
|
||||
let render: (props: PlatformIconProps) => ReturnType<AppContextTestRender['render']>;
|
||||
let renderResult: ReturnType<typeof render>;
|
||||
let mockedContext: AppContextTestRender;
|
||||
|
||||
beforeEach(() => {
|
||||
mockedContext = createAppRootMockRenderer();
|
||||
render = (props) =>
|
||||
(renderResult = mockedContext.render(
|
||||
<PlatformIcon {...{ 'data-test-subj': 'test', ...props }} />
|
||||
));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it.each(['linux', 'macos', 'windows', 'unknown'] as Array<PlatformIconProps['platform']>)(
|
||||
'should render icon for %s',
|
||||
(platform) => {
|
||||
render({ platform });
|
||||
const icon = renderResult.getByTestId('test');
|
||||
expect(icon).toBeTruthy();
|
||||
}
|
||||
);
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 { EuiIcon, type EuiIconProps } from '@elastic/eui';
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import linuxSvg from './logos/linux.svg';
|
||||
import windowsSvg from './logos/windows.svg';
|
||||
import macosSvg from './logos/macos.svg';
|
||||
|
||||
export type Platform = 'macos' | 'linux' | 'windows';
|
||||
const getPlatformIcon = (platform: Platform): string | null => {
|
||||
switch (platform) {
|
||||
case 'macos':
|
||||
return macosSvg;
|
||||
case 'linux':
|
||||
return linuxSvg;
|
||||
case 'windows':
|
||||
return windowsSvg;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export interface PlatformIconProps {
|
||||
platform: Platform;
|
||||
size?: EuiIconProps['size'];
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
|
||||
export const PlatformIcon = memo<PlatformIconProps>(
|
||||
({ platform, size = 'xl', 'data-test-subj': dataTestSubj }) => {
|
||||
const platformIcon = useMemo(() => getPlatformIcon(platform), [platform]);
|
||||
|
||||
return (
|
||||
<EuiIcon
|
||||
type={!platformIcon ? 'empty' : platformIcon}
|
||||
title={platform}
|
||||
size={size}
|
||||
data-test-subj={dataTestSubj}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
PlatformIcon.displayName = 'PlatformIcon';
|
Loading…
Add table
Add a link
Reference in a new issue