[8.x] [Security Solution][Bidirectional Integrations Banner][Crowdstrike][SentinelOne] Banner for bidirectional integrations (#200625) (#200768)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Solution][Bidirectional Integrations
Banner][Crowdstrike][SentinelOne] Banner for bidirectional integrations
(#200625)](https://github.com/elastic/kibana/pull/200625)

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

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

<!--BACKPORT [{"author":{"name":"Candace
Park","email":"56409205+parkiino@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-11-19T04:46:25Z","message":"[Security
Solution][Bidirectional Integrations Banner][Crowdstrike][SentinelOne]
Banner for bidirectional integrations (#200625)\n\n## Summary\r\n\r\n-
[x] Callouts for bidirectional integrations capabilities on
Sentinel\r\nOne and Crowdstrike integrations.\r\n- [x] Unit
tests\r\n\r\n# Screenshots\r\n<img width=\"1685\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/f360c391-6046-49a8-b9d4-56a598dc2b99\">\r\n<img
width=\"1132\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/9a15dc52-172a-4ee9-8e39-831a524e5d0b\">\r\n\r\nDARK
MODE\r\n<img width=\"1127\"
alt=\"image\"\r\nsrc=\"7f3730f8-7eed-4ca0-a67d-7658fe98d308)","sha":"3c3274829bdcb950ab4aff9abf1d106482de6267","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Fleet","v9.0.0","Team:Defend
Workflows","backport:prev-minor","v8.17.0"],"title":"[Security
Solution][Bidirectional Integrations Banner][Crowdstrike][SentinelOne]
Banner for bidirectional
integrations","number":200625,"url":"https://github.com/elastic/kibana/pull/200625","mergeCommit":{"message":"[Security
Solution][Bidirectional Integrations Banner][Crowdstrike][SentinelOne]
Banner for bidirectional integrations (#200625)\n\n## Summary\r\n\r\n-
[x] Callouts for bidirectional integrations capabilities on
Sentinel\r\nOne and Crowdstrike integrations.\r\n- [x] Unit
tests\r\n\r\n# Screenshots\r\n<img width=\"1685\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/f360c391-6046-49a8-b9d4-56a598dc2b99\">\r\n<img
width=\"1132\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/9a15dc52-172a-4ee9-8e39-831a524e5d0b\">\r\n\r\nDARK
MODE\r\n<img width=\"1127\"
alt=\"image\"\r\nsrc=\"7f3730f8-7eed-4ca0-a67d-7658fe98d308)","sha":"3c3274829bdcb950ab4aff9abf1d106482de6267"}},"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/200625","number":200625,"mergeCommit":{"message":"[Security
Solution][Bidirectional Integrations Banner][Crowdstrike][SentinelOne]
Banner for bidirectional integrations (#200625)\n\n## Summary\r\n\r\n-
[x] Callouts for bidirectional integrations capabilities on
Sentinel\r\nOne and Crowdstrike integrations.\r\n- [x] Unit
tests\r\n\r\n# Screenshots\r\n<img width=\"1685\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/f360c391-6046-49a8-b9d4-56a598dc2b99\">\r\n<img
width=\"1132\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/9a15dc52-172a-4ee9-8e39-831a524e5d0b\">\r\n\r\nDARK
MODE\r\n<img width=\"1127\"
alt=\"image\"\r\nsrc=\"7f3730f8-7eed-4ca0-a67d-7658fe98d308)","sha":"3c3274829bdcb950ab4aff9abf1d106482de6267"}},{"branch":"8.x","label":"v8.17.0","branchLabelMappingKey":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Candace Park <56409205+parkiino@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2024-11-20 04:47:14 +11:00 committed by GitHub
parent 106dfd6c59
commit e942bb0047
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 156 additions and 3 deletions

View file

@ -472,6 +472,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
securitySolution: {
artifactControl: `${SECURITY_SOLUTION_DOCS}artifact-control.html`,
avcResults: `${ELASTIC_WEBSITE_URL}blog/elastic-av-comparatives-business-security-test`,
bidirectionalIntegrations: `${SECURITY_SOLUTION_DOCS}third-party-actions.html`,
trustedApps: `${SECURITY_SOLUTION_DOCS}trusted-apps-ov.html`,
eventFilters: `${SECURITY_SOLUTION_DOCS}event-filters.html`,
blocklist: `${SECURITY_SOLUTION_DOCS}blocklist.html`,

View file

@ -342,6 +342,7 @@ export interface DocLinks {
readonly aiAssistant: string;
readonly artifactControl: string;
readonly avcResults: string;
readonly bidirectionalIntegrations: string;
readonly trustedApps: string;
readonly eventFilters: string;
readonly eventMerging: string;

View file

@ -0,0 +1,50 @@
/*
* 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 RenderResult } from '@testing-library/react';
import { createFleetTestRendererMock } from '../../../../../../../mock';
import {
BidirectionalIntegrationsBanner,
type BidirectionalIntegrationsBannerProps,
} from './bidirectional_integrations_callout';
jest.mock('react-use/lib/useLocalStorage');
describe('BidirectionalIntegrationsBanner', () => {
let formProps: BidirectionalIntegrationsBannerProps;
let renderResult: RenderResult;
beforeEach(() => {
formProps = {
onDismiss: jest.fn(),
};
const renderer = createFleetTestRendererMock();
renderResult = renderer.render(<BidirectionalIntegrationsBanner {...formProps} />);
});
it('should render bidirectional integrations banner', () => {
expect(renderResult.getByTestId('bidirectionalIntegrationsCallout')).toBeInTheDocument();
});
it('should contain a link to documentation', () => {
const docLink = renderResult.getByTestId('bidirectionalIntegrationDocLink');
expect(docLink).toBeInTheDocument();
expect(docLink.getAttribute('href')).toContain('third-party-actions.html');
});
it('should call `onDismiss` callback when user clicks dismiss', () => {
renderResult.getByTestId('euiDismissCalloutButton').click();
expect(formProps.onDismiss).toBeCalled();
});
});

View file

@ -0,0 +1,66 @@
/*
* 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, { memo } from 'react';
import styled from 'styled-components';
import { EuiCallOut, EuiLink, EuiTextColor } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
const AccentCallout = styled(EuiCallOut)`
.euiCallOutHeader__title {
color: ${(props) => props.theme.eui.euiColorAccent};
}
background-color: ${(props) => props.theme.eui.euiPanelBackgroundColorModifiers.accent};
`;
export interface BidirectionalIntegrationsBannerProps {
onDismiss: () => void;
}
export const BidirectionalIntegrationsBanner = memo<BidirectionalIntegrationsBannerProps>(
({ onDismiss }) => {
const { docLinks } = useKibana().services;
const bannerTitle = (
<EuiTextColor color="accent">
<FormattedMessage
id="xpack.fleet.bidirectionalIntegrationsBanner.title"
defaultMessage={'NEW: Response enabled integration'}
/>
</EuiTextColor>
);
return (
<AccentCallout
title={bannerTitle}
iconType="cheer"
onDismiss={onDismiss}
data-test-subj={'bidirectionalIntegrationsCallout'}
>
<FormattedMessage
id="xpack.fleet.bidirectionalIntegrationsBanner.body"
defaultMessage="Orchestrate response actions across endpoint vendors with bidirectional integrations. {learnmore}."
values={{
learnmore: (
<EuiLink
href={docLinks?.links.securitySolution.bidirectionalIntegrations}
target="_blank"
data-test-subj="bidirectionalIntegrationDocLink"
>
<FormattedMessage
id="xpack.fleet.bidirectionalIntegrations.doc.link"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
</AccentCallout>
);
}
);
BidirectionalIntegrationsBanner.displayName = 'BidirectionalIntegrationsBanner';

View file

@ -6,7 +6,9 @@
*/
export { BackLink } from './back_link';
export { AddIntegrationButton } from './add_integration_button';
export { CloudPostureThirdPartySupportCallout } from './cloud_posture_third_party_support_callout';
export { UpdateIcon } from './update_icon';
export { IntegrationAgentPolicyCount } from './integration_agent_policy_count';
export { IconPanel, LoadingIconPanel } from './icon_panel';
export { KeepPoliciesUpToDateSwitch } from './keep_policies_up_to_date_switch';
export { BidirectionalIntegrationsBanner } from './bidirectional_integrations_callout';

View file

@ -42,7 +42,10 @@ import { SideBarColumn } from '../../../components/side_bar_column';
import type { FleetStartServices } from '../../../../../../../plugin';
import { CloudPostureThirdPartySupportCallout } from '../components/cloud_posture_third_party_support_callout';
import {
CloudPostureThirdPartySupportCallout,
BidirectionalIntegrationsBanner,
} from '../components';
import { Screenshots } from './screenshots';
import { Readme } from './readme';
@ -172,6 +175,8 @@ export const OverviewPage: React.FC<Props> = memo(
const isUnverified = isPackageUnverified(packageInfo, packageVerificationKeyId);
const isPrerelease = isPackagePrerelease(packageInfo.version);
const isElasticDefend = packageInfo.name === 'endpoint';
const isSentinelOne = packageInfo.name === 'sentinel_one';
const isCrowdStrike = packageInfo.name === 'crowdstrike';
const [markdown, setMarkdown] = useState<string | undefined>(undefined);
const [selectedItemId, setSelectedItem] = useState<string | undefined>(undefined);
const [isSideNavOpenOnMobile, setIsSideNavOpenOnMobile] = useState(false);
@ -296,11 +301,27 @@ export const OverviewPage: React.FC<Props> = memo(
const [showAVCBanner, setShowAVCBanner] = useState(
storage.get('securitySolution.showAvcBanner') ?? true
);
const onBannerDismiss = useCallback(() => {
const [showCSResponseSupportBanner, setShowCSResponseSupportBanner] = useState(
storage.get('fleet.showCSResponseSupportBanner') ?? true
);
const [showSOReponseSupportBanner, setShowSOResponseSupportBanner] = useState(
storage.get('fleet.showSOReponseSupportBanner') ?? true
);
const onAVCBannerDismiss = useCallback(() => {
setShowAVCBanner(false);
storage.set('securitySolution.showAvcBanner', false);
}, [storage]);
const onCSResponseSupportBannerDismiss = useCallback(() => {
setShowCSResponseSupportBanner(false);
storage.set('fleet.showCSResponseSupportBanner', false);
}, [storage]);
const onSOResponseSupportBannerDismiss = useCallback(() => {
setShowSOResponseSupportBanner(false);
storage.set('fleet.showSOReponseSupportBanner', false);
}, [storage]);
return (
<EuiFlexGroup alignItems="flexStart" data-test-subj="epm.OverviewPage">
<SideBar grow={2}>
@ -317,7 +338,19 @@ export const OverviewPage: React.FC<Props> = memo(
{isUnverified && <UnverifiedCallout />}
{useIsStillYear2024() && isElasticDefend && showAVCBanner && (
<>
<AVCResultsBanner2024 onDismiss={onBannerDismiss} />
<AVCResultsBanner2024 onDismiss={onAVCBannerDismiss} />
<EuiSpacer size="s" />
</>
)}
{isCrowdStrike && showCSResponseSupportBanner && (
<>
<BidirectionalIntegrationsBanner onDismiss={onCSResponseSupportBannerDismiss} />
<EuiSpacer size="s" />
</>
)}
{isSentinelOne && showSOReponseSupportBanner && (
<>
<BidirectionalIntegrationsBanner onDismiss={onSOResponseSupportBannerDismiss} />
<EuiSpacer size="s" />
</>
)}