From 904295cb2027bacd82534f3af8d332453cb9f86d Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Wed, 17 Nov 2021 10:41:30 -0500 Subject: [PATCH 01/26] Move effected policies component to common management components --- .../effected_policy_select.test.tsx | 7 ++----- .../effected_policy_select/effected_policy_select.tsx | 10 +++++----- .../components/effected_policy_select/index.ts | 0 .../components/effected_policy_select/test_utils.ts | 0 .../view/components/create_trusted_app_form.test.tsx | 2 +- .../view/components/create_trusted_app_form.tsx | 6 +++--- .../pages/trusted_apps/view/trusted_apps_page.test.tsx | 2 +- 7 files changed, 12 insertions(+), 15 deletions(-) rename x-pack/plugins/security_solution/public/management/{pages/trusted_apps/view => }/components/effected_policy_select/effected_policy_select.test.tsx (95%) rename x-pack/plugins/security_solution/public/management/{pages/trusted_apps/view => }/components/effected_policy_select/effected_policy_select.tsx (94%) rename x-pack/plugins/security_solution/public/management/{pages/trusted_apps/view => }/components/effected_policy_select/index.ts (100%) rename x-pack/plugins/security_solution/public/management/{pages/trusted_apps/view => }/components/effected_policy_select/test_utils.ts (100%) diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.test.tsx b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.test.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.test.tsx rename to x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.test.tsx index 3e48ccc6d9b6d..5eebc2721857f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.test.tsx @@ -5,15 +5,12 @@ * 2.0. */ -import { EndpointDocGenerator } from '../../../../../../../common/endpoint/generate_data'; import { EffectedPolicySelect, EffectedPolicySelectProps } from './effected_policy_select'; -import { - AppContextTestRender, - createAppRootMockRenderer, -} from '../../../../../../common/mock/endpoint'; import React from 'react'; import { forceHTMLElementOffsetWidth } from './test_utils'; import { fireEvent, act } from '@testing-library/react'; +import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; +import { AppContextTestRender, createAppRootMockRenderer } from '../../../common/mock/endpoint'; describe('when using EffectedPolicySelect component', () => { const generator = new EndpointDocGenerator('effected-policy-select'); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx rename to x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx index 07de303c155aa..57044d2c59f29 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/effected_policy_select.tsx +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx @@ -23,11 +23,11 @@ import { i18n } from '@kbn/i18n'; import { EuiSelectableOption } from '@elastic/eui/src/components/selectable/selectable_option'; import { FormattedMessage } from '@kbn/i18n/react'; import styled from 'styled-components'; -import { PolicyData } from '../../../../../../../common/endpoint/types'; -import { getPolicyDetailPath } from '../../../../../common/routing'; -import { useAppUrl } from '../../../../../../common/lib/kibana/hooks'; -import { LinkToApp } from '../../../../../../common/components/endpoint/link_to_app'; -import { useTestIdGenerator } from '../../../../../components/hooks/use_test_id_generator'; +import { PolicyData } from '../../../../common/endpoint/types'; +import { LinkToApp } from '../../../common/components/endpoint/link_to_app'; +import { getPolicyDetailPath } from '../../common/routing'; +import { useTestIdGenerator } from '../hooks/use_test_id_generator'; +import { useAppUrl } from '../../../common/lib/kibana/hooks'; const NOOP = () => {}; const DEFAULT_LIST_PROPS: EuiSelectableProps['listProps'] = { bordered: true, showIcons: false }; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/index.ts b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/index.ts similarity index 100% rename from x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/index.ts rename to x-pack/plugins/security_solution/public/management/components/effected_policy_select/index.ts diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/test_utils.ts b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/test_utils.ts similarity index 100% rename from x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/effected_policy_select/test_utils.ts rename to x-pack/plugins/security_solution/public/management/components/effected_policy_select/test_utils.ts diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.test.tsx index f05d018fe8e9a..23589843c28c3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.test.tsx @@ -21,10 +21,10 @@ import { import { CreateTrustedAppForm, CreateTrustedAppFormProps } from './create_trusted_app_form'; import { defaultNewTrustedApp } from '../../store/builders'; -import { forceHTMLElementOffsetWidth } from './effected_policy_select/test_utils'; import { EndpointDocGenerator } from '../../../../../../common/endpoint/generate_data'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { licenseService } from '../../../../../common/hooks/use_license'; +import { forceHTMLElementOffsetWidth } from '../../../../components/effected_policy_select/test_utils'; jest.mock('../../../../../common/hooks/use_experimental_features'); const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx index da925ddd8a6c1..ca0d89ad8dee3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx @@ -42,13 +42,13 @@ import { import { defaultConditionEntry } from '../../store/builders'; import { OS_TITLES } from '../translations'; import { LogicalConditionBuilder, LogicalConditionBuilderProps } from './logical_condition'; +import { useTestIdGenerator } from '../../../../components/hooks/use_test_id_generator'; +import { useLicense } from '../../../../../common/hooks/use_license'; import { EffectedPolicySelect, EffectedPolicySelection, EffectedPolicySelectProps, -} from './effected_policy_select'; -import { useTestIdGenerator } from '../../../../components/hooks/use_test_id_generator'; -import { useLicense } from '../../../../../common/hooks/use_license'; +} from '../../../../components/effected_policy_select'; const OPERATING_SYSTEMS: readonly OperatingSystem[] = [ OperatingSystem.MAC, diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx index 39619379a1ee0..5d78de741e459 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx @@ -30,11 +30,11 @@ import { } from '../../../../../../fleet/common'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { isFailedResourceState, isLoadedResourceState } from '../state'; -import { forceHTMLElementOffsetWidth } from './components/effected_policy_select/test_utils'; import { toUpdateTrustedApp } from '../../../../../common/endpoint/service/trusted_apps/to_update_trusted_app'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; import { licenseService } from '../../../../common/hooks/use_license'; +import { forceHTMLElementOffsetWidth } from '../../../components/effected_policy_select/test_utils'; // TODO: remove this mock when feature flag is removed jest.mock('../../../../common/hooks/use_experimental_features'); From df52a5320eea7ce6745e5cf8c8f609f19f68cf40 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Wed, 17 Nov 2021 11:28:13 -0500 Subject: [PATCH 02/26] Allow description prop and use fallback generic copy --- .../effected_policy_select.tsx | 21 ++++++++++++------- .../components/create_trusted_app_form.tsx | 7 +++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx index 57044d2c59f29..01ca7ad9f735f 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx @@ -57,6 +57,7 @@ export type EffectedPolicySelectProps = Omit< options: PolicyData[]; isGlobal: boolean; isPlatinumPlus: boolean; + description?: string; onChange: (selection: EffectedPolicySelection) => void; selected?: PolicyData[]; }; @@ -64,6 +65,7 @@ export const EffectedPolicySelect = memo( ({ isGlobal, isPlatinumPlus, + description, onChange, listProps, options, @@ -79,7 +81,7 @@ export const EffectedPolicySelect = memo( () => [ { id: 'globalPolicy', - label: i18n.translate('xpack.securitySolution.endpoint.trustedAppsByPolicy.global', { + label: i18n.translate('xpack.securitySolution.endpoint.effectedPolicySelect.global', { defaultMessage: 'Global', }), iconType: isGlobal ? 'checkInCircleFilled' : '', @@ -87,7 +89,7 @@ export const EffectedPolicySelect = memo( }, { id: 'perPolicy', - label: i18n.translate('xpack.securitySolution.endpoint.trustedAppsByPolicy.perPolicy', { + label: i18n.translate('xpack.securitySolution.endpoint.effectedPolicySelect.perPolicy', { defaultMessage: 'Per Policy', }), iconType: !isGlobal ? 'checkInCircleFilled' : '', @@ -169,7 +171,7 @@ export const EffectedPolicySelect = memo(

@@ -179,10 +181,15 @@ export const EffectedPolicySelect = memo(

- {i18n.translate('xpack.securitySolution.trustedApps.assignmentSectionDescription', { - defaultMessage: - 'Assign this trusted application globally across all policies, or assign it to specific policies.', - })} + {description + ? description + : i18n.translate( + 'xpack.securitySolution.effectedPolicySelect.assignmentSectionDescription', + { + defaultMessage: + 'Assign globally across all policies, or assign it to specific policies.', + } + )}

diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx index ca0d89ad8dee3..147529b164ae1 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/create_trusted_app_form.tsx @@ -564,6 +564,13 @@ export const CreateTrustedAppForm = memo( options={policies.options} onChange={handlePolicySelectChange} isLoading={policies?.isLoading} + description={i18n.translate( + 'xpack.securitySolution.trustedApps.assignmentSectionDescription', + { + defaultMessage: + 'Assign this trusted application globally across all policies, or assign it to specific policies.', + } + )} data-test-subj={getTestId('effectedPolicies')} /> From 67be8ed74cdcb9da85e3c2999a9d46bb10a879ad Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Wed, 17 Nov 2021 12:08:09 -0500 Subject: [PATCH 03/26] Style borders removing radius --- .../effected_policy_select.tsx | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx index 01ca7ad9f735f..191593288722d 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx @@ -31,6 +31,19 @@ import { useAppUrl } from '../../../common/lib/kibana/hooks'; const NOOP = () => {}; const DEFAULT_LIST_PROPS: EuiSelectableProps['listProps'] = { bordered: true, showIcons: false }; +const EFFECTED_POLICIES_SEARCH_PROPS = { className: 'effected-policies-search' }; + +const StyledEuiSelectable = styled.div` + .effected-policies-search { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + .euiSelectableList { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top-width: 0; + } +`; const EffectivePolicyFormContainer = styled.div` .policy-name .euiSelectableListItem__text { @@ -209,16 +222,19 @@ export const EffectedPolicySelect = memo( {!isGlobal && ( - - {...otherSelectableProps} - options={selectableOptions} - listProps={listProps || DEFAULT_LIST_PROPS} - onChange={handleOnPolicySelectChange} - searchable={true} - data-test-subj={getTestId('policiesSelectable')} - > - {listBuilderCallback} - + + + {...otherSelectableProps} + options={selectableOptions} + listProps={listProps || DEFAULT_LIST_PROPS} + onChange={handleOnPolicySelectChange} + searchProps={EFFECTED_POLICIES_SEARCH_PROPS} + searchable={true} + data-test-subj={getTestId('policiesSelectable')} + > + {listBuilderCallback} + + )} From 3e4ac9fa7d8cd310caa7fb51b268c844a57dacce Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Wed, 17 Nov 2021 12:09:41 -0500 Subject: [PATCH 04/26] Rename variable --- .../effected_policy_select/effected_policy_select.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx index 191593288722d..2249fc89430d2 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.tsx @@ -31,7 +31,7 @@ import { useAppUrl } from '../../../common/lib/kibana/hooks'; const NOOP = () => {}; const DEFAULT_LIST_PROPS: EuiSelectableProps['listProps'] = { bordered: true, showIcons: false }; -const EFFECTED_POLICIES_SEARCH_PROPS = { className: 'effected-policies-search' }; +const SEARCH_PROPS = { className: 'effected-policies-search' }; const StyledEuiSelectable = styled.div` .effected-policies-search { @@ -228,7 +228,7 @@ export const EffectedPolicySelect = memo( options={selectableOptions} listProps={listProps || DEFAULT_LIST_PROPS} onChange={handleOnPolicySelectChange} - searchProps={EFFECTED_POLICIES_SEARCH_PROPS} + searchProps={SEARCH_PROPS} searchable={true} data-test-subj={getTestId('policiesSelectable')} > From 2e1801c32ba813cf0342418d98cef590a971db8a Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Wed, 17 Nov 2021 15:15:10 -0500 Subject: [PATCH 05/26] Move policy ingest service to a common service --- .../store/endpoint_pagination.test.ts | 2 +- .../endpoint_hosts/store/middleware.test.ts | 2 +- .../pages/endpoint_hosts/store/middleware.ts | 12 +++++----- .../store/mock_endpoint_result_list.ts | 12 +++++----- .../pages/endpoint_hosts/view/index.test.tsx | 6 ++--- .../middleware/policy_settings_middleware.ts | 10 ++++----- .../pages/policy/view/policy_details.test.tsx | 2 +- .../components/policy_form_layout.test.tsx | 2 +- .../policy_trusted_apps_layout.test.tsx | 2 +- .../pages/trusted_apps/service/index.ts | 2 +- .../policy}/ingest.test.ts | 18 +++++++-------- .../services => services/policy}/ingest.ts | 22 +++++++++++-------- .../policy}/test_mock_utils.ts | 8 +++---- 13 files changed, 52 insertions(+), 48 deletions(-) rename x-pack/plugins/security_solution/public/management/{pages/policy/store/services => services/policy}/ingest.test.ts (93%) rename x-pack/plugins/security_solution/public/management/{pages/policy/store/services => services/policy}/ingest.ts (95%) rename x-pack/plugins/security_solution/public/management/{pages/policy/store => services/policy}/test_mock_utils.ts (88%) diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts index dcfd5c86d11d8..e8fe81f0145d1 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts @@ -27,7 +27,7 @@ import { } from '../../../../common/store/test_utils'; import { getEndpointListPath } from '../../../common/routing'; -jest.mock('../../policy/store/services/ingest', () => ({ +jest.mock('../../../services/policy/ingest', () => ({ sendGetAgentPolicyList: () => Promise.resolve({ items: [] }), sendGetEndpointSecurityPackage: () => Promise.resolve({}), })); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts index 8405320198615..45f15ad5e3608 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts @@ -49,7 +49,7 @@ import { HOST_METADATA_LIST_ROUTE, } from '../../../../../common/endpoint/constants'; -jest.mock('../../policy/store/services/ingest', () => ({ +jest.mock('../../../services/policy/ingest', () => ({ sendGetAgentConfigList: () => Promise.resolve({ items: [] }), sendGetAgentPolicyList: () => Promise.resolve({ items: [] }), sendGetEndpointSecurityPackage: () => Promise.resolve({ version: '1.1.1' }), diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index 9f8c280fac30b..17dbae10c83b4 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -53,12 +53,6 @@ import { TransformStats, TransformStatsResponse, } from '../types'; -import { - sendGetEndpointSpecificPackagePolicies, - sendGetEndpointSecurityPackage, - sendGetAgentPolicyList, - sendGetFleetAgentsWithEndpoint, -} from '../../policy/store/services/ingest'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../fleet/common'; import { ENDPOINT_ACTION_LOG_ROUTE, @@ -81,6 +75,12 @@ import { EndpointPackageInfoStateChanged } from './action'; import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; import { getIsInvalidDateRange } from '../utils'; import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants'; +import { + sendGetAgentPolicyList, + sendGetEndpointSecurityPackage, + sendGetEndpointSpecificPackagePolicies, + sendGetFleetAgentsWithEndpoint, +} from '../../../services/policy/ingest'; type EndpointPageStore = ImmutableMiddlewareAPI; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts index 2e3de427e6960..6d3901f59c0b3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts @@ -15,12 +15,6 @@ import { PendingActionsResponse, } from '../../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; -import { - INGEST_API_AGENT_POLICIES, - INGEST_API_EPM_PACKAGES, - INGEST_API_PACKAGE_POLICIES, - INGEST_API_FLEET_AGENTS, -} from '../../policy/store/services/ingest'; import { GetAgentPoliciesResponse, GetAgentPoliciesResponseItem, @@ -32,6 +26,12 @@ import { pendingActionsResponseMock } from '../../../../common/lib/endpoint_pend import { ACTION_STATUS_ROUTE } from '../../../../../common/endpoint/constants'; import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants'; import { TransformStats, TransformStatsResponse } from '../types'; +import { + INGEST_API_AGENT_POLICIES, + INGEST_API_EPM_PACKAGES, + INGEST_API_FLEET_AGENTS, + INGEST_API_PACKAGE_POLICIES, +} from '../../../services/policy/ingest'; const generator = new EndpointDocGenerator('seed'); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx index a71acd66650dc..a685674ef0f47 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx @@ -29,7 +29,6 @@ import { } from '../../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { POLICY_STATUS_TO_HEALTH_COLOR, POLICY_STATUS_TO_TEXT } from './host_constants'; -import { mockPolicyResultList } from '../../policy/store/test_mock_utils'; import { getEndpointDetailsPath } from '../../../common/routing'; import { KibanaServices, useKibana, useToasts, useUiSetting$ } from '../../../../common/lib/kibana'; import { hostIsolationHttpMocks } from '../../../../common/lib/endpoint_isolation/mocks'; @@ -55,6 +54,7 @@ import { metadataTransformPrefix, METADATA_UNITED_TRANSFORM, } from '../../../../../common/endpoint/constants'; +import { mockPolicyResultList } from '../../../services/policy/test_mock_utils'; // not sure why this can't be imported from '../../../../common/mock/formatted_relative'; // but sure enough it needs to be inline in this one file @@ -68,8 +68,8 @@ jest.mock('@kbn/i18n/react', () => { }; }); jest.mock('../../../../common/components/link_to'); -jest.mock('../../policy/store/services/ingest', () => { - const originalModule = jest.requireActual('../../policy/store/services/ingest'); +jest.mock('../../../services/policy/ingest', () => { + const originalModule = jest.requireActual('../../../services/policy/ingest'); return { ...originalModule, sendGetEndpointSecurityPackage: () => Promise.resolve({}), diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts index 784565b5d8e1d..3b4897f524adf 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts @@ -6,6 +6,11 @@ */ import { IHttpFetchError } from 'kibana/public'; +import { + sendGetFleetAgentStatusForPolicy, + sendGetPackagePolicy, + sendPutPackagePolicy, +} from '../../../../../services/policy/ingest'; import { DefaultPolicyNotificationMessage, DefaultPolicyRuleNotificationMessage, @@ -18,11 +23,6 @@ import { policyDetailsForUpdate, needsToRefresh, } from '../selectors/policy_settings_selectors'; -import { - sendGetPackagePolicy, - sendGetFleetAgentStatusForPolicy, - sendPutPackagePolicy, -} from '../../services/ingest'; import { NewPolicyData, PolicyData } from '../../../../../../../common/endpoint/types'; import { getPolicyDataForUpdate } from '../../../../../../../common/endpoint/service/policy'; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx index 2e763f3f4eaf3..457623cfc6111 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx @@ -12,8 +12,8 @@ import { PolicyDetails } from './policy_details'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint'; import { getPolicyDetailPath, getEndpointListPath } from '../../../common/routing'; -import { policyListApiPathHandlers } from '../store/test_mock_utils'; import { PACKAGE_POLICY_API_ROOT, AGENT_API_ROUTES } from '../../../../../../fleet/common'; +import { policyListApiPathHandlers } from '../../../services/policy/test_mock_utils'; jest.mock('./policy_forms/components/policy_form_layout'); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx index 2702aec1cbabe..2b2d660f3c256 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx @@ -16,9 +16,9 @@ import { createAppRootMockRenderer, } from '../../../../../../common/mock/endpoint'; import { getPolicyDetailPath, getEndpointListPath } from '../../../../../common/routing'; -import { policyListApiPathHandlers } from '../../../store/test_mock_utils'; import { licenseService } from '../../../../../../common/hooks/use_license'; import { PACKAGE_POLICY_API_ROOT, AGENT_API_ROUTES } from '../../../../../../../../fleet/common'; +import { policyListApiPathHandlers } from '../../../../../services/policy/test_mock_utils'; jest.mock('../../../../../../common/hooks/use_license'); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx index 318b98712a7c0..403fdba08abb5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx @@ -18,10 +18,10 @@ import { getMockListResponse } from '../../../test_utils'; import { createLoadedResourceState, isLoadedResourceState } from '../../../../../state'; import { getPolicyDetailsArtifactsListPath } from '../../../../../common/routing'; import { EndpointDocGenerator } from '../../../../../../../common/endpoint/generate_data'; -import { policyListApiPathHandlers } from '../../../store/test_mock_utils'; import { useEndpointPrivileges } from '../../../../../../common/components/user_privileges/endpoint/use_endpoint_privileges'; import { getEndpointPrivilegesInitialStateMock } from '../../../../../../common/components/user_privileges/endpoint/mocks'; import { PACKAGE_POLICY_API_ROOT, AGENT_API_ROUTES } from '../../../../../../../../fleet/common'; +import { policyListApiPathHandlers } from '../../../../../services/policy/test_mock_utils'; jest.mock('../../../../trusted_apps/service'); jest.mock('../../../../../../common/components/user_privileges/endpoint/use_endpoint_privileges'); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts index b59fb6cfdd2f7..1f29ab72018e0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts @@ -35,9 +35,9 @@ import { } from '../../../../../common/endpoint/types'; import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; -import { sendGetEndpointSpecificPackagePolicies } from '../../policy/store/services/ingest'; import { toUpdateTrustedApp } from '../../../../../common/endpoint/service/trusted_apps/to_update_trusted_app'; import { isGlobalEffectScope } from '../state/type_guards'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policy/ingest'; export interface TrustedAppsService { getTrustedApp(params: GetOneTrustedAppRequestParams): Promise; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts b/x-pack/plugins/security_solution/public/management/services/policy/ingest.test.ts similarity index 93% rename from x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts rename to x-pack/plugins/security_solution/public/management/services/policy/ingest.test.ts index b5897d8fd3bc4..e3b87e086ada8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts +++ b/x-pack/plugins/security_solution/public/management/services/policy/ingest.test.ts @@ -5,20 +5,20 @@ * 2.0. */ +import { httpServiceMock } from 'src/core/public/mocks'; +import { + EPM_API_ROUTES, + PACKAGE_POLICY_API_ROOT, + PACKAGE_POLICY_API_ROUTES, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, +} from '../../../../../fleet/common'; import { INGEST_API_EPM_PACKAGES, - sendGetPackagePolicy, sendGetEndpointSecurityPackage, sendGetEndpointSpecificPackagePolicies, + sendGetPackagePolicy, } from './ingest'; -import { httpServiceMock } from '../../../../../../../../../src/core/public/mocks'; -import { - EPM_API_ROUTES, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, - PACKAGE_POLICY_API_ROOT, - PACKAGE_POLICY_API_ROUTES, -} from '../../../../../../../fleet/common'; -import { policyListApiPathHandlers } from '../test_mock_utils'; +import { policyListApiPathHandlers } from './test_mock_utils'; describe('ingest service', () => { let http: ReturnType; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts b/x-pack/plugins/security_solution/public/management/services/policy/ingest.ts similarity index 95% rename from x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts rename to x-pack/plugins/security_solution/public/management/services/policy/ingest.ts index 0375b0c434f18..f847f66f3fd87 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts +++ b/x-pack/plugins/security_solution/public/management/services/policy/ingest.ts @@ -6,19 +6,23 @@ */ import { HttpFetchOptions, HttpStart } from 'kibana/public'; +import { NewPolicyData } from '../../../../common/endpoint/types'; import { - GetPackagePoliciesRequest, - GetAgentStatusResponse, - GetAgentsResponse, - DeletePackagePoliciesResponse, DeletePackagePoliciesRequest, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, - GetPackagesResponse, + DeletePackagePoliciesResponse, GetAgentPoliciesRequest, GetAgentPoliciesResponse, -} from '../../../../../../../fleet/common'; -import { GetPolicyListResponse, GetPolicyResponse, UpdatePolicyResponse } from '../../types'; -import { NewPolicyData } from '../../../../../../common/endpoint/types'; + GetAgentsResponse, + GetAgentStatusResponse, + GetPackagePoliciesRequest, + GetPackagesResponse, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, +} from '../../../../../fleet/common'; +import { + GetPolicyListResponse, + GetPolicyResponse, + UpdatePolicyResponse, +} from '../../pages/policy/types'; const INGEST_API_ROOT = `/api/fleet`; export const INGEST_API_PACKAGE_POLICIES = `${INGEST_API_ROOT}/package_policies`; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/test_mock_utils.ts b/x-pack/plugins/security_solution/public/management/services/policy/test_mock_utils.ts similarity index 88% rename from x-pack/plugins/security_solution/public/management/pages/policy/store/test_mock_utils.ts rename to x-pack/plugins/security_solution/public/management/services/policy/test_mock_utils.ts index 7ab46617dae3e..cd15dd060144e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/test_mock_utils.ts +++ b/x-pack/plugins/security_solution/public/management/services/policy/test_mock_utils.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { INGEST_API_EPM_PACKAGES, INGEST_API_PACKAGE_POLICIES } from './services/ingest'; -import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; -import { GetPolicyListResponse } from '../types'; -import { GetPackagesResponse } from '../../../../../../fleet/common'; +import { GetPackagesResponse } from '../../../../../fleet/common'; +import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; +import { GetPolicyListResponse } from '../../pages/policy/types'; +import { INGEST_API_EPM_PACKAGES, INGEST_API_PACKAGE_POLICIES } from './ingest'; const generator = new EndpointDocGenerator('policy-list'); From 4e57894cba84a7e5682b8563bab4c14b59ebd388 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 18 Nov 2021 07:02:39 -0500 Subject: [PATCH 06/26] Revert "Move policy ingest service to a common service" This reverts commit 2e1801c32ba813cf0342418d98cef590a971db8a. --- .../store/endpoint_pagination.test.ts | 2 +- .../endpoint_hosts/store/middleware.test.ts | 2 +- .../pages/endpoint_hosts/store/middleware.ts | 12 +++++----- .../store/mock_endpoint_result_list.ts | 12 +++++----- .../pages/endpoint_hosts/view/index.test.tsx | 6 ++--- .../middleware/policy_settings_middleware.ts | 10 ++++----- .../policy/store/services}/ingest.test.ts | 18 +++++++-------- .../policy/store/services}/ingest.ts | 22 ++++++++----------- .../policy/store}/test_mock_utils.ts | 8 +++---- .../pages/policy/view/policy_details.test.tsx | 2 +- .../components/policy_form_layout.test.tsx | 2 +- .../policy_trusted_apps_layout.test.tsx | 2 +- .../pages/trusted_apps/service/index.ts | 2 +- 13 files changed, 48 insertions(+), 52 deletions(-) rename x-pack/plugins/security_solution/public/management/{services/policy => pages/policy/store/services}/ingest.test.ts (93%) rename x-pack/plugins/security_solution/public/management/{services/policy => pages/policy/store/services}/ingest.ts (95%) rename x-pack/plugins/security_solution/public/management/{services/policy => pages/policy/store}/test_mock_utils.ts (88%) diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts index e8fe81f0145d1..dcfd5c86d11d8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts @@ -27,7 +27,7 @@ import { } from '../../../../common/store/test_utils'; import { getEndpointListPath } from '../../../common/routing'; -jest.mock('../../../services/policy/ingest', () => ({ +jest.mock('../../policy/store/services/ingest', () => ({ sendGetAgentPolicyList: () => Promise.resolve({ items: [] }), sendGetEndpointSecurityPackage: () => Promise.resolve({}), })); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts index 45f15ad5e3608..8405320198615 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts @@ -49,7 +49,7 @@ import { HOST_METADATA_LIST_ROUTE, } from '../../../../../common/endpoint/constants'; -jest.mock('../../../services/policy/ingest', () => ({ +jest.mock('../../policy/store/services/ingest', () => ({ sendGetAgentConfigList: () => Promise.resolve({ items: [] }), sendGetAgentPolicyList: () => Promise.resolve({ items: [] }), sendGetEndpointSecurityPackage: () => Promise.resolve({ version: '1.1.1' }), diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index 17dbae10c83b4..9f8c280fac30b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -53,6 +53,12 @@ import { TransformStats, TransformStatsResponse, } from '../types'; +import { + sendGetEndpointSpecificPackagePolicies, + sendGetEndpointSecurityPackage, + sendGetAgentPolicyList, + sendGetFleetAgentsWithEndpoint, +} from '../../policy/store/services/ingest'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../fleet/common'; import { ENDPOINT_ACTION_LOG_ROUTE, @@ -75,12 +81,6 @@ import { EndpointPackageInfoStateChanged } from './action'; import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; import { getIsInvalidDateRange } from '../utils'; import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants'; -import { - sendGetAgentPolicyList, - sendGetEndpointSecurityPackage, - sendGetEndpointSpecificPackagePolicies, - sendGetFleetAgentsWithEndpoint, -} from '../../../services/policy/ingest'; type EndpointPageStore = ImmutableMiddlewareAPI; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts index 6d3901f59c0b3..2e3de427e6960 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts @@ -15,6 +15,12 @@ import { PendingActionsResponse, } from '../../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; +import { + INGEST_API_AGENT_POLICIES, + INGEST_API_EPM_PACKAGES, + INGEST_API_PACKAGE_POLICIES, + INGEST_API_FLEET_AGENTS, +} from '../../policy/store/services/ingest'; import { GetAgentPoliciesResponse, GetAgentPoliciesResponseItem, @@ -26,12 +32,6 @@ import { pendingActionsResponseMock } from '../../../../common/lib/endpoint_pend import { ACTION_STATUS_ROUTE } from '../../../../../common/endpoint/constants'; import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants'; import { TransformStats, TransformStatsResponse } from '../types'; -import { - INGEST_API_AGENT_POLICIES, - INGEST_API_EPM_PACKAGES, - INGEST_API_FLEET_AGENTS, - INGEST_API_PACKAGE_POLICIES, -} from '../../../services/policy/ingest'; const generator = new EndpointDocGenerator('seed'); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx index a685674ef0f47..a71acd66650dc 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx @@ -29,6 +29,7 @@ import { } from '../../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { POLICY_STATUS_TO_HEALTH_COLOR, POLICY_STATUS_TO_TEXT } from './host_constants'; +import { mockPolicyResultList } from '../../policy/store/test_mock_utils'; import { getEndpointDetailsPath } from '../../../common/routing'; import { KibanaServices, useKibana, useToasts, useUiSetting$ } from '../../../../common/lib/kibana'; import { hostIsolationHttpMocks } from '../../../../common/lib/endpoint_isolation/mocks'; @@ -54,7 +55,6 @@ import { metadataTransformPrefix, METADATA_UNITED_TRANSFORM, } from '../../../../../common/endpoint/constants'; -import { mockPolicyResultList } from '../../../services/policy/test_mock_utils'; // not sure why this can't be imported from '../../../../common/mock/formatted_relative'; // but sure enough it needs to be inline in this one file @@ -68,8 +68,8 @@ jest.mock('@kbn/i18n/react', () => { }; }); jest.mock('../../../../common/components/link_to'); -jest.mock('../../../services/policy/ingest', () => { - const originalModule = jest.requireActual('../../../services/policy/ingest'); +jest.mock('../../policy/store/services/ingest', () => { + const originalModule = jest.requireActual('../../policy/store/services/ingest'); return { ...originalModule, sendGetEndpointSecurityPackage: () => Promise.resolve({}), diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts index 3b4897f524adf..784565b5d8e1d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/middleware/policy_settings_middleware.ts @@ -6,11 +6,6 @@ */ import { IHttpFetchError } from 'kibana/public'; -import { - sendGetFleetAgentStatusForPolicy, - sendGetPackagePolicy, - sendPutPackagePolicy, -} from '../../../../../services/policy/ingest'; import { DefaultPolicyNotificationMessage, DefaultPolicyRuleNotificationMessage, @@ -23,6 +18,11 @@ import { policyDetailsForUpdate, needsToRefresh, } from '../selectors/policy_settings_selectors'; +import { + sendGetPackagePolicy, + sendGetFleetAgentStatusForPolicy, + sendPutPackagePolicy, +} from '../../services/ingest'; import { NewPolicyData, PolicyData } from '../../../../../../../common/endpoint/types'; import { getPolicyDataForUpdate } from '../../../../../../../common/endpoint/service/policy'; diff --git a/x-pack/plugins/security_solution/public/management/services/policy/ingest.test.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts similarity index 93% rename from x-pack/plugins/security_solution/public/management/services/policy/ingest.test.ts rename to x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts index e3b87e086ada8..b5897d8fd3bc4 100644 --- a/x-pack/plugins/security_solution/public/management/services/policy/ingest.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts @@ -5,20 +5,20 @@ * 2.0. */ -import { httpServiceMock } from 'src/core/public/mocks'; -import { - EPM_API_ROUTES, - PACKAGE_POLICY_API_ROOT, - PACKAGE_POLICY_API_ROUTES, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, -} from '../../../../../fleet/common'; import { INGEST_API_EPM_PACKAGES, + sendGetPackagePolicy, sendGetEndpointSecurityPackage, sendGetEndpointSpecificPackagePolicies, - sendGetPackagePolicy, } from './ingest'; -import { policyListApiPathHandlers } from './test_mock_utils'; +import { httpServiceMock } from '../../../../../../../../../src/core/public/mocks'; +import { + EPM_API_ROUTES, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, + PACKAGE_POLICY_API_ROOT, + PACKAGE_POLICY_API_ROUTES, +} from '../../../../../../../fleet/common'; +import { policyListApiPathHandlers } from '../test_mock_utils'; describe('ingest service', () => { let http: ReturnType; diff --git a/x-pack/plugins/security_solution/public/management/services/policy/ingest.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts similarity index 95% rename from x-pack/plugins/security_solution/public/management/services/policy/ingest.ts rename to x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts index f847f66f3fd87..0375b0c434f18 100644 --- a/x-pack/plugins/security_solution/public/management/services/policy/ingest.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts @@ -6,23 +6,19 @@ */ import { HttpFetchOptions, HttpStart } from 'kibana/public'; -import { NewPolicyData } from '../../../../common/endpoint/types'; import { - DeletePackagePoliciesRequest, + GetPackagePoliciesRequest, + GetAgentStatusResponse, + GetAgentsResponse, DeletePackagePoliciesResponse, + DeletePackagePoliciesRequest, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, + GetPackagesResponse, GetAgentPoliciesRequest, GetAgentPoliciesResponse, - GetAgentsResponse, - GetAgentStatusResponse, - GetPackagePoliciesRequest, - GetPackagesResponse, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, -} from '../../../../../fleet/common'; -import { - GetPolicyListResponse, - GetPolicyResponse, - UpdatePolicyResponse, -} from '../../pages/policy/types'; +} from '../../../../../../../fleet/common'; +import { GetPolicyListResponse, GetPolicyResponse, UpdatePolicyResponse } from '../../types'; +import { NewPolicyData } from '../../../../../../common/endpoint/types'; const INGEST_API_ROOT = `/api/fleet`; export const INGEST_API_PACKAGE_POLICIES = `${INGEST_API_ROOT}/package_policies`; diff --git a/x-pack/plugins/security_solution/public/management/services/policy/test_mock_utils.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/test_mock_utils.ts similarity index 88% rename from x-pack/plugins/security_solution/public/management/services/policy/test_mock_utils.ts rename to x-pack/plugins/security_solution/public/management/pages/policy/store/test_mock_utils.ts index cd15dd060144e..7ab46617dae3e 100644 --- a/x-pack/plugins/security_solution/public/management/services/policy/test_mock_utils.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/test_mock_utils.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { GetPackagesResponse } from '../../../../../fleet/common'; -import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; -import { GetPolicyListResponse } from '../../pages/policy/types'; -import { INGEST_API_EPM_PACKAGES, INGEST_API_PACKAGE_POLICIES } from './ingest'; +import { INGEST_API_EPM_PACKAGES, INGEST_API_PACKAGE_POLICIES } from './services/ingest'; +import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; +import { GetPolicyListResponse } from '../types'; +import { GetPackagesResponse } from '../../../../../../fleet/common'; const generator = new EndpointDocGenerator('policy-list'); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx index 457623cfc6111..2e763f3f4eaf3 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx @@ -12,8 +12,8 @@ import { PolicyDetails } from './policy_details'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint'; import { getPolicyDetailPath, getEndpointListPath } from '../../../common/routing'; +import { policyListApiPathHandlers } from '../store/test_mock_utils'; import { PACKAGE_POLICY_API_ROOT, AGENT_API_ROUTES } from '../../../../../../fleet/common'; -import { policyListApiPathHandlers } from '../../../services/policy/test_mock_utils'; jest.mock('./policy_forms/components/policy_form_layout'); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx index 2b2d660f3c256..2702aec1cbabe 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx @@ -16,9 +16,9 @@ import { createAppRootMockRenderer, } from '../../../../../../common/mock/endpoint'; import { getPolicyDetailPath, getEndpointListPath } from '../../../../../common/routing'; +import { policyListApiPathHandlers } from '../../../store/test_mock_utils'; import { licenseService } from '../../../../../../common/hooks/use_license'; import { PACKAGE_POLICY_API_ROOT, AGENT_API_ROUTES } from '../../../../../../../../fleet/common'; -import { policyListApiPathHandlers } from '../../../../../services/policy/test_mock_utils'; jest.mock('../../../../../../common/hooks/use_license'); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx index 403fdba08abb5..318b98712a7c0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/trusted_apps/layout/policy_trusted_apps_layout.test.tsx @@ -18,10 +18,10 @@ import { getMockListResponse } from '../../../test_utils'; import { createLoadedResourceState, isLoadedResourceState } from '../../../../../state'; import { getPolicyDetailsArtifactsListPath } from '../../../../../common/routing'; import { EndpointDocGenerator } from '../../../../../../../common/endpoint/generate_data'; +import { policyListApiPathHandlers } from '../../../store/test_mock_utils'; import { useEndpointPrivileges } from '../../../../../../common/components/user_privileges/endpoint/use_endpoint_privileges'; import { getEndpointPrivilegesInitialStateMock } from '../../../../../../common/components/user_privileges/endpoint/mocks'; import { PACKAGE_POLICY_API_ROOT, AGENT_API_ROUTES } from '../../../../../../../../fleet/common'; -import { policyListApiPathHandlers } from '../../../../../services/policy/test_mock_utils'; jest.mock('../../../../trusted_apps/service'); jest.mock('../../../../../../common/components/user_privileges/endpoint/use_endpoint_privileges'); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts index 1f29ab72018e0..b59fb6cfdd2f7 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts @@ -35,9 +35,9 @@ import { } from '../../../../../common/endpoint/types'; import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; +import { sendGetEndpointSpecificPackagePolicies } from '../../policy/store/services/ingest'; import { toUpdateTrustedApp } from '../../../../../common/endpoint/service/trusted_apps/to_update_trusted_app'; import { isGlobalEffectScope } from '../state/type_guards'; -import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policy/ingest'; export interface TrustedAppsService { getTrustedApp(params: GetOneTrustedAppRequestParams): Promise; From e914304df79268553ca7eb47747883cacfd2fed0 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 18 Nov 2021 07:19:48 -0500 Subject: [PATCH 07/26] Revert "Move policy ingest service to a common service" This reverts commit 2e1801c32ba813cf0342418d98cef590a971db8a. --- .../pages/endpoint_hosts/store/middleware.ts | 2 +- .../policy/store/services/ingest.test.ts | 31 +------------- .../pages/policy/store/services/ingest.ts | 25 +---------- .../pages/trusted_apps/service/index.ts | 2 +- .../management/services/policies.test.ts | 42 +++++++++++++++++++ .../public/management/services/policies.ts | 35 ++++++++++++++++ 6 files changed, 81 insertions(+), 56 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/services/policies.test.ts create mode 100644 x-pack/plugins/security_solution/public/management/services/policies.ts diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index 9f8c280fac30b..3e448d932dd89 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -54,7 +54,6 @@ import { TransformStatsResponse, } from '../types'; import { - sendGetEndpointSpecificPackagePolicies, sendGetEndpointSecurityPackage, sendGetAgentPolicyList, sendGetFleetAgentsWithEndpoint, @@ -81,6 +80,7 @@ import { EndpointPackageInfoStateChanged } from './action'; import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; import { getIsInvalidDateRange } from '../utils'; import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; type EndpointPageStore = ImmutableMiddlewareAPI; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts index b5897d8fd3bc4..ef66c948e1127 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.test.ts @@ -9,15 +9,9 @@ import { INGEST_API_EPM_PACKAGES, sendGetPackagePolicy, sendGetEndpointSecurityPackage, - sendGetEndpointSpecificPackagePolicies, } from './ingest'; import { httpServiceMock } from '../../../../../../../../../src/core/public/mocks'; -import { - EPM_API_ROUTES, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, - PACKAGE_POLICY_API_ROOT, - PACKAGE_POLICY_API_ROUTES, -} from '../../../../../../../fleet/common'; +import { EPM_API_ROUTES, PACKAGE_POLICY_API_ROOT } from '../../../../../../../fleet/common'; import { policyListApiPathHandlers } from '../test_mock_utils'; describe('ingest service', () => { @@ -27,29 +21,6 @@ describe('ingest service', () => { http = httpServiceMock.createStartContract(); }); - describe('sendGetEndpointSpecificPackagePolicies()', () => { - it('auto adds kuery to api request', async () => { - await sendGetEndpointSpecificPackagePolicies(http); - expect(http.get).toHaveBeenCalledWith(`${PACKAGE_POLICY_API_ROUTES.LIST_PATTERN}`, { - query: { - kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, - }, - }); - }); - it('supports additional KQL to be defined on input for query params', async () => { - await sendGetEndpointSpecificPackagePolicies(http, { - query: { kuery: 'someValueHere', page: 1, perPage: 10 }, - }); - expect(http.get).toHaveBeenCalledWith(`${PACKAGE_POLICY_API_ROUTES.LIST_PATTERN}`, { - query: { - kuery: `someValueHere and ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, - perPage: 10, - page: 1, - }, - }); - }); - }); - describe('sendGetPackagePolicy()', () => { it('builds correct API path', async () => { await sendGetPackagePolicy(http, '123'); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts index 0375b0c434f18..27b567c3bb38c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/services/ingest.ts @@ -7,17 +7,15 @@ import { HttpFetchOptions, HttpStart } from 'kibana/public'; import { - GetPackagePoliciesRequest, GetAgentStatusResponse, GetAgentsResponse, DeletePackagePoliciesResponse, DeletePackagePoliciesRequest, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, GetPackagesResponse, GetAgentPoliciesRequest, GetAgentPoliciesResponse, } from '../../../../../../../fleet/common'; -import { GetPolicyListResponse, GetPolicyResponse, UpdatePolicyResponse } from '../../types'; +import { GetPolicyResponse, UpdatePolicyResponse } from '../../types'; import { NewPolicyData } from '../../../../../../common/endpoint/types'; const INGEST_API_ROOT = `/api/fleet`; @@ -28,27 +26,6 @@ export const INGEST_API_FLEET_AGENTS = `${INGEST_API_ROOT}/agents`; export const INGEST_API_EPM_PACKAGES = `${INGEST_API_ROOT}/epm/packages`; const INGEST_API_DELETE_PACKAGE_POLICY = `${INGEST_API_PACKAGE_POLICIES}/delete`; -/** - * Retrieves a list of endpoint specific package policies (those created with a `package.name` of - * `endpoint`) from Ingest - * @param http - * @param options - */ -export const sendGetEndpointSpecificPackagePolicies = ( - http: HttpStart, - options: HttpFetchOptions & Partial = {} -): Promise => { - return http.get(INGEST_API_PACKAGE_POLICIES, { - ...options, - query: { - ...options.query, - kuery: `${ - options?.query?.kuery ? `${options.query.kuery} and ` : '' - }${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, - }, - }); -}; - /** * Retrieves a single package policy based on ID from ingest * @param http diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts index b59fb6cfdd2f7..2549dd5a2a4dc 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts @@ -35,9 +35,9 @@ import { } from '../../../../../common/endpoint/types'; import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; -import { sendGetEndpointSpecificPackagePolicies } from '../../policy/store/services/ingest'; import { toUpdateTrustedApp } from '../../../../../common/endpoint/service/trusted_apps/to_update_trusted_app'; import { isGlobalEffectScope } from '../state/type_guards'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; export interface TrustedAppsService { getTrustedApp(params: GetOneTrustedAppRequestParams): Promise; diff --git a/x-pack/plugins/security_solution/public/management/services/policies.test.ts b/x-pack/plugins/security_solution/public/management/services/policies.test.ts new file mode 100644 index 0000000000000..0b93dffb71d3c --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/services/policies.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { httpServiceMock } from '../../../../../../src/core/public/mocks'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../fleet/common'; +import { PACKAGE_POLICY_API_ROUTES } from '../../../../fleet/common/constants/routes'; +import { sendGetEndpointSpecificPackagePolicies } from './policies'; + +describe('ingest service', () => { + let http: ReturnType; + + beforeEach(() => { + http = httpServiceMock.createStartContract(); + }); + + describe('sendGetEndpointSpecificPackagePolicies()', () => { + it('auto adds kuery to api request', async () => { + await sendGetEndpointSpecificPackagePolicies(http); + expect(http.get).toHaveBeenCalledWith(`${PACKAGE_POLICY_API_ROUTES.LIST_PATTERN}`, { + query: { + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, + }, + }); + }); + it('supports additional KQL to be defined on input for query params', async () => { + await sendGetEndpointSpecificPackagePolicies(http, { + query: { kuery: 'someValueHere', page: 1, perPage: 10 }, + }); + expect(http.get).toHaveBeenCalledWith(`${PACKAGE_POLICY_API_ROUTES.LIST_PATTERN}`, { + query: { + kuery: `someValueHere and ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, + perPage: 10, + page: 1, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/services/policies.ts b/x-pack/plugins/security_solution/public/management/services/policies.ts new file mode 100644 index 0000000000000..63810ad499c09 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/services/policies.ts @@ -0,0 +1,35 @@ +/* + * 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 { HttpFetchOptions, HttpStart } from 'kibana/public'; +import { + GetPackagePoliciesRequest, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, +} from '../../../../fleet/common'; +import { INGEST_API_PACKAGE_POLICIES } from '../pages/policy/store/services/ingest'; +import { GetPolicyListResponse } from '../pages/policy/types'; + +/** + * Retrieves a list of endpoint specific package policies (those created with a `package.name` of + * `endpoint`) from Ingest + * @param http + * @param options + */ +export const sendGetEndpointSpecificPackagePolicies = ( + http: HttpStart, + options: HttpFetchOptions & Partial = {} +): Promise => { + return http.get(INGEST_API_PACKAGE_POLICIES, { + ...options, + query: { + ...options.query, + kuery: `${ + options?.query?.kuery ? `${options.query.kuery} and ` : '' + }${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, + }, + }); +}; From 0dd114edd296e682790901f977e43e95d80789bd Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 18 Nov 2021 14:21:43 -0500 Subject: [PATCH 08/26] Move query to custom hook --- .../view/components/form_flyout.tsx | 48 +++++++----------- .../host_isolation_exceptions/view/hooks.ts | 50 ++++++++++++++++--- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index 35d834afa1756..3b931a27963ab 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -22,10 +22,16 @@ import { UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import React, { memo, useCallback, useMemo, useState } from 'react'; -import { useMutation, useQuery, useQueryClient } from 'react-query'; -import { ServerApiError } from '../../../../../common/types'; +import { useMutation, useQueryClient } from 'react-query'; import { Loader } from '../../../../../common/components/loader'; import { useHttp, useToasts } from '../../../../../common/lib/kibana'; +import { ServerApiError } from '../../../../../common/types'; +import { + createHostIsolationExceptionItem, + updateOneHostIsolationExceptionItem, +} from '../../service'; +import { useGetHostIsolationExceptionFormEntry } from '../hooks'; +import { HostIsolationExceptionsForm } from './form'; import { getCreateErrorMessage, getCreationSuccessMessage, @@ -33,13 +39,6 @@ import { getUpdateErrorMessage, getUpdateSuccessMessage, } from './translations'; -import { createEmptyHostIsolationException } from '../../utils'; -import { HostIsolationExceptionsForm } from './form'; -import { - createHostIsolationExceptionItem, - getOneHostIsolationExceptionItem, - updateOneHostIsolationExceptionItem, -} from '../../service'; export const HostIsolationExceptionsFormFlyout = memo( ({ onCancel, id }: { onCancel: () => void; id?: string }) => { @@ -52,28 +51,17 @@ export const HostIsolationExceptionsFormFlyout = memo( CreateExceptionListItemSchema | UpdateExceptionListItemSchema | undefined >(undefined); - useQuery( - ['hostIsolationExceptions', 'form', id], - async () => { - // for editing, fetch from the API - if (id !== undefined) { - return getOneHostIsolationExceptionItem(http, id); - } - // for adding, return a new empty object - return createEmptyHostIsolationException(); + // Load the entry to create or edit + // NOTE: This form doesn't use the hook data directly + // because that data object will be mutated + useGetHostIsolationExceptionFormEntry({ + id, + onSuccess: (data) => setException(data), + onError: (error) => { + toasts.addWarning(getLoadErrorMessage(error)); + onCancel(); }, - { - refetchIntervalInBackground: false, - refetchOnWindowFocus: false, - onSuccess: (data) => { - setException(data); - }, - onError: (error) => { - toasts.addWarning(getLoadErrorMessage(error)); - onCancel(); - }, - } - ); + }); const mutation = useMutation( () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts index 0b18a5b61bd01..efdc481b2fe42 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts @@ -4,24 +4,33 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { + CreateExceptionListItemSchema, + FoundExceptionListItemSchema, + UpdateExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; import { useCallback, useEffect, useState } from 'react'; +import { QueryObserverResult, useQuery } from 'react-query'; import { useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import { FoundExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { QueryObserverResult, useQuery } from 'react-query'; -import { ServerApiError } from '../../../../common/types'; -import { useHttp } from '../../../../common/lib/kibana/hooks'; import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; +import { useHttp } from '../../../../common/lib/kibana/hooks'; import { State } from '../../../../common/store'; +import { ServerApiError } from '../../../../common/types'; import { MANAGEMENT_STORE_GLOBAL_NAMESPACE, MANAGEMENT_STORE_HOST_ISOLATION_EXCEPTIONS_NAMESPACE, } from '../../../common/constants'; import { getHostIsolationExceptionsListPath } from '../../../common/routing'; -import { getHostIsolationExceptionItems, getHostIsolationExceptionSummary } from '../service'; +import { parseQueryFilterToKQL } from '../../../common/utils'; +import { + getHostIsolationExceptionItems, + getHostIsolationExceptionSummary, + getOneHostIsolationExceptionItem, +} from '../service'; import { getCurrentLocation } from '../store/selector'; import { HostIsolationExceptionsPageLocation, HostIsolationExceptionsPageState } from '../types'; -import { parseQueryFilterToKQL } from '../../../common/utils'; +import { createEmptyHostIsolationException } from '../utils'; export function useHostIsolationExceptionsSelector( selector: (state: HostIsolationExceptionsPageState) => R @@ -95,3 +104,32 @@ export function useFetchHostIsolationExceptionsList(): QueryObserverResult< } ); } + +export function useGetHostIsolationExceptionFormEntry({ + id, + onSuccess, + onError, +}: { + id?: string; + onSuccess: (data: CreateExceptionListItemSchema | UpdateExceptionListItemSchema) => void; + onError: (error: ServerApiError) => void; +}): QueryObserverResult { + const http = useHttp(); + return useQuery( + ['hostIsolationExceptions', 'form', id], + async () => { + // for editing, fetch from the API + if (id !== undefined) { + return getOneHostIsolationExceptionItem(http, id); + } + // for adding, return a new empty object + return createEmptyHostIsolationException(); + }, + { + refetchIntervalInBackground: false, + refetchOnWindowFocus: false, + onSuccess, + onError, + } + ); +} From 51e98f0220592c32aa9bfa8d5347fe6852fce906 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Fri, 19 Nov 2021 11:01:10 -0500 Subject: [PATCH 09/26] WIP: Add policies to host isolation exceptions --- .../effected_policy_select/utils.ts | 53 ++++++++++++++ .../view/components/form.tsx | 70 +++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts new file mode 100644 index 0000000000000..21614e1fea07f --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts @@ -0,0 +1,53 @@ +/* + * 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 { PolicyData } from '../../../../common/endpoint/types'; +import { EffectedPolicySelection } from './effected_policy_select'; + +export const GLOBAL_POLICY_TAG = 'policy:all'; + +export function getArtifactTagsByEffectedPolicySelection( + selection: EffectedPolicySelection +): string[] { + if (selection.isGlobal) { + return [GLOBAL_POLICY_TAG]; + } + return selection.selected.map((policy) => { + return `policy:${policy.id}`; + }); +} + +export function getEffectedPolicySelectionByTags( + tags: string[], + policies: PolicyData[] +): EffectedPolicySelection { + if (tags.find((tag) => tag === GLOBAL_POLICY_TAG)) { + return { + isGlobal: true, + selected: [], + }; + } + const selected: PolicyData[] = tags.reduce((acc, tag) => { + // edge case: a left over tag with a non-existed policy + // will be removed by veryfing the policy exists + const id = tag.split(':')[1]; + const foundPolicy = policies.find((policy) => policy.id === id); + if (foundPolicy !== undefined) { + acc.push(foundPolicy); + } + return acc; + }, [] as PolicyData[]); + + return { + isGlobal: false, + selected, + }; +} + +export function isGlobalPolicyEffected(tags?: string[]): boolean { + return tags !== undefined && tags.find((tag) => tag === GLOBAL_POLICY_TAG) !== undefined; +} diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index 4e853f0e6fa6f..3a49ca2e87929 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -21,6 +21,20 @@ import { UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { useQuery } from 'react-query'; +import { useHttp } from '../../../../../common/lib/kibana'; +import { + EffectedPolicySelect, + EffectedPolicySelection, + EffectedPolicySelectProps, +} from '../../../../components/effected_policy_select'; +import { + getArtifactTagsByEffectedPolicySelection, + getEffectedPolicySelectionByTags, + isGlobalPolicyEffected, +} from '../../../../components/effected_policy_select/utils'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../../services/policies'; +import { GetPolicyListResponse } from '../../../policy/types'; import { isValidIPv4OrCIDR } from '../../utils'; import { DESCRIPTION_LABEL, @@ -50,6 +64,31 @@ export const HostIsolationExceptionsForm: React.FC<{ const [hasBeenInputIpVisited, setHasBeenInputIpVisited] = useState(false); const [hasNameError, setHasNameError] = useState(!exception.name); const [hasIpError, setHasIpError] = useState(!ipEntry.value); + const http = useHttp(); + + const policiesRequest = useQuery( + ['hostIsolationExceptions', 'policies'], + () => { + return sendGetEndpointSpecificPackagePolicies(http, { + query: { + page: 1, + perPage: 1000, + }, + }); + }, + { + refetchIntervalInBackground: false, + refetchOnWindowFocus: false, + onSuccess: (data) => { + if (isGlobalPolicyEffected(exception.tags)) { + setIsGlobal(true); + } else { + setIsGlobal(false); + setSelectedPolicies(getEffectedPolicySelectionByTags(exception.tags || [], data.items)); + } + }, + } + ); useEffect(() => { onError(hasNameError || hasIpError); @@ -91,6 +130,25 @@ export const HostIsolationExceptionsForm: React.FC<{ [exception, onChange] ); + const [isGlobal, setIsGlobal] = useState(true); + + const [selectedPolicies, setSelectedPolicies] = useState({ + isGlobal, + selected: [], + }); + + const handlePolicySelectChange: EffectedPolicySelectProps['onChange'] = useCallback( + (selection) => { + setIsGlobal(selection.isGlobal); + setSelectedPolicies(() => selection); + onChange({ + ...exception, + tags: getArtifactTagsByEffectedPolicySelection(selection), + }); + }, + [exception, onChange] + ); + const handleOnDescriptionChange = useCallback( (event: React.ChangeEvent) => { onChange({ ...exception, description: event.target.value }); @@ -203,6 +261,18 @@ export const HostIsolationExceptionsForm: React.FC<{
{ipInput} + + + + ); }); From 7aa40e70ab0ecb1cb99c55d8ed7614a152b7cc83 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Fri, 19 Nov 2021 11:32:59 -0500 Subject: [PATCH 10/26] Apply policies and submit --- .../effected_policy_select/utils.ts | 2 +- .../view/components/form.tsx | 50 ++++++------------- .../host_isolation_exceptions/view/hooks.ts | 26 ++++++++++ 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts index 21614e1fea07f..811fca77cdc78 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts @@ -25,7 +25,7 @@ export function getEffectedPolicySelectionByTags( tags: string[], policies: PolicyData[] ): EffectedPolicySelection { - if (tags.find((tag) => tag === GLOBAL_POLICY_TAG)) { + if (tags.length === 0 || tags.find((tag) => tag === GLOBAL_POLICY_TAG)) { return { isGlobal: true, selected: [], diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index 3a49ca2e87929..8b11dcbddb4fc 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -21,8 +21,6 @@ import { UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; -import { useQuery } from 'react-query'; -import { useHttp } from '../../../../../common/lib/kibana'; import { EffectedPolicySelect, EffectedPolicySelection, @@ -33,9 +31,8 @@ import { getEffectedPolicySelectionByTags, isGlobalPolicyEffected, } from '../../../../components/effected_policy_select/utils'; -import { sendGetEndpointSpecificPackagePolicies } from '../../../../services/policies'; -import { GetPolicyListResponse } from '../../../policy/types'; import { isValidIPv4OrCIDR } from '../../utils'; +import { useGetEndpointSpecificPolicies } from '../hooks'; import { DESCRIPTION_LABEL, DESCRIPTION_PLACEHOLDER, @@ -64,31 +61,23 @@ export const HostIsolationExceptionsForm: React.FC<{ const [hasBeenInputIpVisited, setHasBeenInputIpVisited] = useState(false); const [hasNameError, setHasNameError] = useState(!exception.name); const [hasIpError, setHasIpError] = useState(!ipEntry.value); - const http = useHttp(); - const policiesRequest = useQuery( - ['hostIsolationExceptions', 'policies'], - () => { - return sendGetEndpointSpecificPackagePolicies(http, { - query: { - page: 1, - perPage: 1000, - }, - }); + const [isGlobal, setIsGlobal] = useState(isGlobalPolicyEffected(exception.tags)); + const [selectedPolicies, setSelectedPolicies] = useState({ + isGlobal, + selected: [], + }); + + const policiesRequest = useGetEndpointSpecificPolicies({ + onSuccess: (data) => { + if (isGlobalPolicyEffected(exception.tags)) { + setIsGlobal(true); + } else { + setIsGlobal(false); + setSelectedPolicies(getEffectedPolicySelectionByTags(exception.tags || [], data.items)); + } }, - { - refetchIntervalInBackground: false, - refetchOnWindowFocus: false, - onSuccess: (data) => { - if (isGlobalPolicyEffected(exception.tags)) { - setIsGlobal(true); - } else { - setIsGlobal(false); - setSelectedPolicies(getEffectedPolicySelectionByTags(exception.tags || [], data.items)); - } - }, - } - ); + }); useEffect(() => { onError(hasNameError || hasIpError); @@ -130,13 +119,6 @@ export const HostIsolationExceptionsForm: React.FC<{ [exception, onChange] ); - const [isGlobal, setIsGlobal] = useState(true); - - const [selectedPolicies, setSelectedPolicies] = useState({ - isGlobal, - selected: [], - }); - const handlePolicySelectChange: EffectedPolicySelectProps['onChange'] = useCallback( (selection) => { setIsGlobal(selection.isGlobal); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts index efdc481b2fe42..1eab38c07598f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts @@ -23,6 +23,8 @@ import { } from '../../../common/constants'; import { getHostIsolationExceptionsListPath } from '../../../common/routing'; import { parseQueryFilterToKQL } from '../../../common/utils'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; +import { GetPolicyListResponse } from '../../policy/types'; import { getHostIsolationExceptionItems, getHostIsolationExceptionSummary, @@ -133,3 +135,27 @@ export function useGetHostIsolationExceptionFormEntry({ } ); } + +export function useGetEndpointSpecificPolicies({ + onSuccess, +}: { + onSuccess: (data: GetPolicyListResponse) => void; +}): QueryObserverResult { + const http = useHttp(); + return useQuery( + ['hostIsolationExceptions', 'policies'], + () => { + return sendGetEndpointSpecificPackagePolicies(http, { + query: { + page: 1, + perPage: 1000, + }, + }); + }, + { + refetchIntervalInBackground: false, + refetchOnWindowFocus: false, + onSuccess, + } + ); +} From 96922e0e3d13e8a72bf7e561f2b4ad0dca26114f Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Fri, 19 Nov 2021 13:20:59 -0500 Subject: [PATCH 11/26] Fetch policies inside the form flyout --- .../view/components/form.tsx | 133 ++++++++---------- .../view/components/form_flyout.tsx | 7 +- .../host_isolation_exceptions/view/hooks.ts | 7 +- 3 files changed, 62 insertions(+), 85 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index 8b11dcbddb4fc..6df76476e238d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -20,7 +20,8 @@ import { CreateExceptionListItemSchema, UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { memo, useCallback, useEffect, useState } from 'react'; +import { PolicyData } from '../../../../../../common/endpoint/types'; import { EffectedPolicySelect, EffectedPolicySelection, @@ -28,11 +29,9 @@ import { } from '../../../../components/effected_policy_select'; import { getArtifactTagsByEffectedPolicySelection, - getEffectedPolicySelectionByTags, isGlobalPolicyEffected, } from '../../../../components/effected_policy_select/utils'; import { isValidIPv4OrCIDR } from '../../utils'; -import { useGetEndpointSpecificPolicies } from '../hooks'; import { DESCRIPTION_LABEL, DESCRIPTION_PLACEHOLDER, @@ -53,9 +52,10 @@ interface ExceptionIpEntry { export const HostIsolationExceptionsForm: React.FC<{ exception: CreateExceptionListItemSchema | UpdateExceptionListItemSchema; + policies: PolicyData[]; onError: (error: boolean) => void; onChange: (exception: CreateExceptionListItemSchema | UpdateExceptionListItemSchema) => void; -}> = memo(({ exception, onError, onChange }) => { +}> = memo(({ exception, onError, policies, onChange }) => { const ipEntry = exception.entries[0] as ExceptionIpEntry; const [hasBeenInputNameVisited, setHasBeenInputNameVisited] = useState(false); const [hasBeenInputIpVisited, setHasBeenInputIpVisited] = useState(false); @@ -68,17 +68,6 @@ export const HostIsolationExceptionsForm: React.FC<{ selected: [], }); - const policiesRequest = useGetEndpointSpecificPolicies({ - onSuccess: (data) => { - if (isGlobalPolicyEffected(exception.tags)) { - setIsGlobal(true); - } else { - setIsGlobal(false); - setSelectedPolicies(getEffectedPolicySelectionByTags(exception.tags || [], data.items)); - } - }, - }); - useEffect(() => { onError(hasNameError || hasIpError); }, [hasNameError, hasIpError, onError]); @@ -138,72 +127,63 @@ export const HostIsolationExceptionsForm: React.FC<{ [exception, onChange] ); - const nameInput = useMemo( - () => ( - + - !hasBeenInputNameVisited && setHasBeenInputNameVisited(true)} - /> - - ), - [hasNameError, hasBeenInputNameVisited, exception.name, handleOnChangeName] + aria-label={NAME_PLACEHOLDER} + required={hasBeenInputNameVisited} + maxLength={256} + data-test-subj="hostIsolationExceptions-form-name-input" + onBlur={() => !hasBeenInputNameVisited && setHasBeenInputNameVisited(true)} + /> + ); - const ipInput = useMemo( - () => ( - + - !hasBeenInputIpVisited && setHasBeenInputIpVisited(true)} - /> - - ), - [hasIpError, hasBeenInputIpVisited, exception.entries, handleOnIpChange] + aria-label={IP_PLACEHOLDER} + required={hasBeenInputIpVisited} + maxLength={256} + data-test-subj="hostIsolationExceptions-form-ip-input" + onBlur={() => !hasBeenInputIpVisited && setHasBeenInputIpVisited(true)} + /> + ); - const descriptionInput = useMemo( - () => ( - - - - ), - [exception.description, handleOnDescriptionChange] + const descriptionInput = ( + + + ); return ( @@ -249,9 +229,8 @@ export const HostIsolationExceptionsForm: React.FC<{ isGlobal={isGlobal} isPlatinumPlus={true} selected={selectedPolicies.selected} - options={policiesRequest.data?.items || []} + options={policies} onChange={handlePolicySelectChange} - isLoading={policiesRequest.isLoading} data-test-subj={'effectedPolicies-select'} /> diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index 3b931a27963ab..ccdcd8a29dd17 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -30,7 +30,7 @@ import { createHostIsolationExceptionItem, updateOneHostIsolationExceptionItem, } from '../../service'; -import { useGetHostIsolationExceptionFormEntry } from '../hooks'; +import { useGetEndpointSpecificPolicies, useGetHostIsolationExceptionFormEntry } from '../hooks'; import { HostIsolationExceptionsForm } from './form'; import { getCreateErrorMessage, @@ -63,6 +63,8 @@ export const HostIsolationExceptionsFormFlyout = memo( }, }); + const policiesRequest = useGetEndpointSpecificPolicies(); + const mutation = useMutation( () => { if (isEditing) { @@ -132,7 +134,7 @@ export const HostIsolationExceptionsFormFlyout = memo( [formHasError, handleOnSubmit, isEditing, mutation.isLoading] ); - return exception ? ( + return exception && policiesRequest.data?.items ? ( void; -}): QueryObserverResult { +export function useGetEndpointSpecificPolicies(): QueryObserverResult { const http = useHttp(); return useQuery( ['hostIsolationExceptions', 'policies'], @@ -155,7 +151,6 @@ export function useGetEndpointSpecificPolicies({ { refetchIntervalInBackground: false, refetchOnWindowFocus: false, - onSuccess, } ); } From 0582054626f5ebe4c65be45b07c91b4ac5cc44e4 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Fri, 19 Nov 2021 13:53:12 -0500 Subject: [PATCH 12/26] Preserve previous policy selection --- .../view/components/form.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index 6df76476e238d..e91c99143caec 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -29,6 +29,7 @@ import { } from '../../../../components/effected_policy_select'; import { getArtifactTagsByEffectedPolicySelection, + getEffectedPolicySelectionByTags, isGlobalPolicyEffected, } from '../../../../components/effected_policy_select/utils'; import { isValidIPv4OrCIDR } from '../../utils'; @@ -68,6 +69,13 @@ export const HostIsolationExceptionsForm: React.FC<{ selected: [], }); + // set current policies if not previously selected + useEffect(() => { + if (selectedPolicies.selected.length === 0) { + setSelectedPolicies(getEffectedPolicySelectionByTags(exception.tags || [], policies)); + } + }, [exception.tags, policies, selectedPolicies.selected.length]); + useEffect(() => { onError(hasNameError || hasIpError); }, [hasNameError, hasIpError, onError]); @@ -111,7 +119,11 @@ export const HostIsolationExceptionsForm: React.FC<{ const handlePolicySelectChange: EffectedPolicySelectProps['onChange'] = useCallback( (selection) => { setIsGlobal(selection.isGlobal); - setSelectedPolicies(() => selection); + + // preseve the previous selection between global and not global toggle + if (!selection.isGlobal) { + setSelectedPolicies(() => selection); + } onChange({ ...exception, tags: getArtifactTagsByEffectedPolicySelection(selection), From 1d41e48f7c387049acc3419db110f29f8bf7cd47 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Fri, 19 Nov 2021 14:04:53 -0500 Subject: [PATCH 13/26] Show error for fetching policies --- .../view/components/form_flyout.tsx | 10 +++++++--- .../pages/host_isolation_exceptions/view/hooks.ts | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index ccdcd8a29dd17..d81c071cfd93d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -52,8 +52,6 @@ export const HostIsolationExceptionsFormFlyout = memo( >(undefined); // Load the entry to create or edit - // NOTE: This form doesn't use the hook data directly - // because that data object will be mutated useGetHostIsolationExceptionFormEntry({ id, onSuccess: (data) => setException(data), @@ -63,7 +61,13 @@ export const HostIsolationExceptionsFormFlyout = memo( }, }); - const policiesRequest = useGetEndpointSpecificPolicies(); + // load the list of policies + const policiesRequest = useGetEndpointSpecificPolicies({ + onError: (error) => { + toasts.addWarning(getLoadErrorMessage(error)); + onCancel(); + }, + }); const mutation = useMutation( () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts index a6d5efaa8de98..a2ea458bae42a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts @@ -136,9 +136,13 @@ export function useGetHostIsolationExceptionFormEntry({ ); } -export function useGetEndpointSpecificPolicies(): QueryObserverResult { +export function useGetEndpointSpecificPolicies({ + onError, +}: { + onError: (error: ServerApiError) => void; +}): QueryObserverResult { const http = useHttp(); - return useQuery( + return useQuery( ['hostIsolationExceptions', 'policies'], () => { return sendGetEndpointSpecificPackagePolicies(http, { @@ -151,6 +155,7 @@ export function useGetEndpointSpecificPolicies(): QueryObserverResult Date: Fri, 19 Nov 2021 14:25:01 -0500 Subject: [PATCH 14/26] Improve form render performance --- .../view/components/form.tsx | 131 ++++++++++-------- .../view/components/form_flyout.tsx | 9 +- 2 files changed, 77 insertions(+), 63 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index e91c99143caec..5eab22dbdf86e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -20,7 +20,7 @@ import { CreateExceptionListItemSchema, UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import React, { memo, useCallback, useEffect, useState } from 'react'; +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { PolicyData } from '../../../../../../common/endpoint/types'; import { EffectedPolicySelect, @@ -55,7 +55,9 @@ export const HostIsolationExceptionsForm: React.FC<{ exception: CreateExceptionListItemSchema | UpdateExceptionListItemSchema; policies: PolicyData[]; onError: (error: boolean) => void; - onChange: (exception: CreateExceptionListItemSchema | UpdateExceptionListItemSchema) => void; + onChange: ( + exception: Partial | Partial + ) => void; }> = memo(({ exception, onError, policies, onChange }) => { const ipEntry = exception.entries[0] as ExceptionIpEntry; const [hasBeenInputNameVisited, setHasBeenInputNameVisited] = useState(false); @@ -88,9 +90,9 @@ export const HostIsolationExceptionsForm: React.FC<{ return; } setHasNameError(false); - onChange({ ...exception, name }); + onChange({ name }); }, - [exception, onChange] + [onChange] ); const handleOnIpChange = useCallback( @@ -102,7 +104,6 @@ export const HostIsolationExceptionsForm: React.FC<{ } setHasIpError(false); onChange({ - ...exception, entries: [ { field: 'destination.ip', @@ -113,7 +114,7 @@ export const HostIsolationExceptionsForm: React.FC<{ ], }); }, - [exception, onChange] + [onChange] ); const handlePolicySelectChange: EffectedPolicySelectProps['onChange'] = useCallback( @@ -125,77 +126,85 @@ export const HostIsolationExceptionsForm: React.FC<{ setSelectedPolicies(() => selection); } onChange({ - ...exception, tags: getArtifactTagsByEffectedPolicySelection(selection), }); }, - [exception, onChange] + [onChange] ); const handleOnDescriptionChange = useCallback( (event: React.ChangeEvent) => { - onChange({ ...exception, description: event.target.value }); + onChange({ description: event.target.value }); }, - [exception, onChange] + [onChange] ); - const nameInput = ( - - ( + !hasBeenInputNameVisited && setHasBeenInputNameVisited(true)} - /> - + isInvalid={hasNameError && hasBeenInputNameVisited} + error={NAME_ERROR} + > + !hasBeenInputNameVisited && setHasBeenInputNameVisited(true)} + /> + + ), + [exception.name, handleOnChangeName, hasBeenInputNameVisited, hasNameError] ); - const ipInput = ( - - ( + !hasBeenInputIpVisited && setHasBeenInputIpVisited(true)} - /> - + isInvalid={hasIpError && hasBeenInputIpVisited} + error={IP_ERROR} + > + !hasBeenInputIpVisited && setHasBeenInputIpVisited(true)} + /> + + ), + [exception.entries, handleOnIpChange, hasBeenInputIpVisited, hasIpError] ); - const descriptionInput = ( - - - + const descriptionInput = useMemo( + () => ( + + + + ), + [exception.description, handleOnDescriptionChange] ); return ( diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index d81c071cfd93d..ef11b6f13fe5f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -61,7 +61,7 @@ export const HostIsolationExceptionsFormFlyout = memo( }, }); - // load the list of policies + // load the list of policies> const policiesRequest = useGetEndpointSpecificPolicies({ onError: (error) => { toasts.addWarning(getLoadErrorMessage(error)); @@ -138,6 +138,11 @@ export const HostIsolationExceptionsFormFlyout = memo( [formHasError, handleOnSubmit, isEditing, mutation.isLoading] ); + const handleFormChange = ( + change: Partial | Partial + ) => { + setException(Object.assign(exception, change)); + }; return exception && policiesRequest.data?.items ? ( From 1cc62cbb34b7e220091aa22dec52f5ccbab1ca89 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 29 Nov 2021 07:51:47 -0500 Subject: [PATCH 15/26] Move policies specific hook to its own folder --- .../view/components/form.tsx | 4 +-- .../view/components/form_flyout.tsx | 3 ++- .../host_isolation_exceptions/view/hooks.ts | 26 ------------------ .../public/management/services/policies.ts | 27 +++++++++++++++++++ 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index cb9051f59ef36..44d8517b51270 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -73,8 +73,8 @@ export const HostIsolationExceptionsForm: React.FC<{ // set current policies if not previously selected useEffect(() => { - if (selectedPolicies.selected.length === 0) { - setSelectedPolicies(getEffectedPolicySelectionByTags(exception.tags || [], policies)); + if (selectedPolicies.selected.length === 0 && exception.tags) { + setSelectedPolicies(getEffectedPolicySelectionByTags(exception.tags, policies)); } }, [exception.tags, policies, selectedPolicies.selected.length]); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index ce5f9179a8b34..4f1ca50f3f82f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -26,11 +26,12 @@ import { useMutation, useQueryClient } from 'react-query'; import { Loader } from '../../../../../common/components/loader'; import { useHttp, useToasts } from '../../../../../common/lib/kibana'; import { ServerApiError } from '../../../../../common/types'; +import { useGetEndpointSpecificPolicies } from '../../../../services/policies'; import { createHostIsolationExceptionItem, updateOneHostIsolationExceptionItem, } from '../../service'; -import { useGetEndpointSpecificPolicies, useGetHostIsolationExceptionFormEntry } from '../hooks'; +import { useGetHostIsolationExceptionFormEntry } from '../hooks'; import { HostIsolationExceptionsForm } from './form'; import { getCreateErrorMessage, diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts index a2ea458bae42a..efdc481b2fe42 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/hooks.ts @@ -23,8 +23,6 @@ import { } from '../../../common/constants'; import { getHostIsolationExceptionsListPath } from '../../../common/routing'; import { parseQueryFilterToKQL } from '../../../common/utils'; -import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; -import { GetPolicyListResponse } from '../../policy/types'; import { getHostIsolationExceptionItems, getHostIsolationExceptionSummary, @@ -135,27 +133,3 @@ export function useGetHostIsolationExceptionFormEntry({ } ); } - -export function useGetEndpointSpecificPolicies({ - onError, -}: { - onError: (error: ServerApiError) => void; -}): QueryObserverResult { - const http = useHttp(); - return useQuery( - ['hostIsolationExceptions', 'policies'], - () => { - return sendGetEndpointSpecificPackagePolicies(http, { - query: { - page: 1, - perPage: 1000, - }, - }); - }, - { - refetchIntervalInBackground: false, - refetchOnWindowFocus: false, - onError, - } - ); -} diff --git a/x-pack/plugins/security_solution/public/management/services/policies.ts b/x-pack/plugins/security_solution/public/management/services/policies.ts index 63810ad499c09..7a2a94308a32a 100644 --- a/x-pack/plugins/security_solution/public/management/services/policies.ts +++ b/x-pack/plugins/security_solution/public/management/services/policies.ts @@ -6,10 +6,13 @@ */ import { HttpFetchOptions, HttpStart } from 'kibana/public'; +import { QueryObserverResult, useQuery } from 'react-query'; import { GetPackagePoliciesRequest, PACKAGE_POLICY_SAVED_OBJECT_TYPE, } from '../../../../fleet/common'; +import { useHttp } from '../../common/lib/kibana/hooks'; +import { ServerApiError } from '../../common/types'; import { INGEST_API_PACKAGE_POLICIES } from '../pages/policy/store/services/ingest'; import { GetPolicyListResponse } from '../pages/policy/types'; @@ -33,3 +36,27 @@ export const sendGetEndpointSpecificPackagePolicies = ( }, }); }; + +export function useGetEndpointSpecificPolicies({ + onError, +}: { + onError: (error: ServerApiError) => void; +}): QueryObserverResult { + const http = useHttp(); + return useQuery( + ['endpointSpecificPolicies'], + () => { + return sendGetEndpointSpecificPackagePolicies(http, { + query: { + page: 1, + perPage: 1000, + }, + }); + }, + { + refetchIntervalInBackground: false, + refetchOnWindowFocus: false, + onError, + } + ); +} From de4db404161f8a66dda947b1c2e0ec482684f31e Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 29 Nov 2021 08:39:20 -0500 Subject: [PATCH 16/26] Fix existing form tests --- .../view/components/form.test.tsx | 17 ++++++++----- .../view/components/form_flyout.tsx | 1 + .../management/services/test_mock_utilts.ts | 24 +++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx index eb8294a1f4658..a9663983a44db 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx @@ -18,8 +18,9 @@ import { } from '@kbn/securitysolution-io-ts-list-types'; import userEvent from '@testing-library/user-event'; import uuid from 'uuid'; +import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../../services/test_mock_utilts'; -describe('When on the host isolation exceptions add entry form', () => { +describe('When on the host isolation exceptions entry form', () => { let render: ( exception: CreateExceptionListItemSchema | UpdateExceptionListItemSchema ) => ReturnType; @@ -31,9 +32,15 @@ describe('When on the host isolation exceptions add entry form', () => { onChange.mockReset(); onError.mockReset(); const mockedContext = createAppRootMockRenderer(); + const policiesRequest = sendGetEndpointSpecificPackagePoliciesMock(); render = (exception) => { return mockedContext.render( - + ); }; }); @@ -77,11 +84,10 @@ describe('When on the host isolation exceptions add entry form', () => { } ); - it('should call onChange when a value is introduced in a field', () => { + it('should call onChange with the partial change when a value is introduced in a field', () => { const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); userEvent.type(ipInput, '10.0.0.1'); expect(onChange).toHaveBeenLastCalledWith({ - ...newException, entries: [ { field: 'destination.ip', operator: 'included', type: 'match', value: '10.0.0.1' }, ], @@ -122,12 +128,11 @@ describe('When on the host isolation exceptions add entry form', () => { ).toHaveValue('initial description'); }); - it('should call onChange when a value is introduced in a field', () => { + it('should call onChange with the partial change when a value is introduced in a field', () => { const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); userEvent.clear(ipInput); userEvent.type(ipInput, '10.0.100.1'); expect(onChange).toHaveBeenCalledWith({ - ...existingException, entries: [ { field: 'destination.ip', operator: 'included', type: 'match', value: '10.0.100.1' }, ], diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index 4f1ca50f3f82f..419d84e554b3b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -144,6 +144,7 @@ export const HostIsolationExceptionsFormFlyout = memo( ) => { setException(Object.assign(exception, change)); }; + return exception && policiesRequest.data?.items ? ( { + const generator = new FleetPackagePolicyGenerator(); + const items = Array(5).map((_, index) => { + const policy = generator.generateEndpointPackagePolicy(); + policy.name += ` ${index}`; + return policy; + }); + + return { + items, + total: 5, + page: 1, + perPage: 10, + }; +}; From 9ee5593a27959e42435028d747871b350fd8988f Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 29 Nov 2021 09:33:50 -0500 Subject: [PATCH 17/26] Update tests for host isolation exceptions form --- .../view/components/form.test.tsx | 115 ++++++++++++++++-- .../management/services/test_mock_utilts.ts | 2 +- 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx index a9663983a44db..c061597d19b3e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx @@ -5,20 +5,21 @@ * 2.0. */ -import { createEmptyHostIsolationException } from '../../utils'; -import { HostIsolationExceptionsForm } from './form'; -import React from 'react'; -import { - AppContextTestRender, - createAppRootMockRenderer, -} from '../../../../../common/mock/endpoint'; import { CreateExceptionListItemSchema, UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import userEvent from '@testing-library/user-event'; +import React from 'react'; import uuid from 'uuid'; +import { + AppContextTestRender, + createAppRootMockRenderer, +} from '../../../../../common/mock/endpoint'; import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../../services/test_mock_utilts'; +import { GetPolicyListResponse } from '../../../policy/types'; +import { createEmptyHostIsolationException } from '../../utils'; +import { HostIsolationExceptionsForm } from './form'; describe('When on the host isolation exceptions entry form', () => { let render: ( @@ -27,12 +28,13 @@ describe('When on the host isolation exceptions entry form', () => { let renderResult: ReturnType; const onChange = jest.fn(); const onError = jest.fn(); + let policiesRequest: GetPolicyListResponse; beforeEach(() => { onChange.mockReset(); onError.mockReset(); const mockedContext = createAppRootMockRenderer(); - const policiesRequest = sendGetEndpointSpecificPackagePoliciesMock(); + policiesRequest = sendGetEndpointSpecificPackagePoliciesMock(); render = (exception) => { return mockedContext.render( { ], }); }); + + it('should select the "global" policy by default', () => { + expect( + renderResult + .getByTestId('effectedPolicies-select-global') + .classList.contains('euiButtonGroupButton-isSelected') + ).toBe(true); + // policy selector should be hidden + expect(renderResult.queryByTestId('effectedPolicies-select-policiesSelectable')).toBeFalsy(); + }); + + it('should display the policy list when "per policy" is selected', () => { + userEvent.click(renderResult.getByTestId('perPolicy')); + + // policy selector should show up + expect(renderResult.getByTestId('effectedPolicies-select-policiesSelectable')).toBeTruthy(); + }); + + it('should call onChange when a policy is selected from the policy selectiion', () => { + const policyId = policiesRequest.items[0].id; + userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click(renderResult.getByTestId(`policy-${policyId}`)); + expect(onChange).toHaveBeenLastCalledWith({ + tags: [`policy:${policyId}`], + }); + }); + + it('should retain the previous policy selection when switching from per-policy to global', () => { + const policyId = policiesRequest.items[0].id; + + // move to per-policy and select the first + userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click(renderResult.getByTestId(`policy-${policyId}`)); + expect(renderResult.queryByTestId('effectedPolicies-select-policiesSelectable')).toBeTruthy(); + expect(onChange).toHaveBeenLastCalledWith({ + tags: [`policy:${policyId}`], + }); + + // move back to global + userEvent.click(renderResult.getByTestId('globalPolicy')); + expect(renderResult.queryByTestId('effectedPolicies-select-policiesSelectable')).toBeFalsy(); + expect(onChange).toHaveBeenLastCalledWith({ + tags: [`policy:all`], + }); + + // move back to per-policy + userEvent.click(renderResult.getByTestId('perPolicy')); + // the previous selected policy should be selected + expect(renderResult.getByTestId(`policy-${policyId}`)).toHaveAttribute( + 'aria-selected', + 'true' + ); + // on change called with the previous policy + expect(onChange).toHaveBeenLastCalledWith({ + tags: [`policy:${policyId}`], + }); + }); }); - describe('When editing an existing exception', () => { + /** + * NOTE: fewer tests exists for update as the form component + * behaves the same for edit and add with the only + * difference of having pre-filled fields + */ + describe('When editing an existing exception with global policy', () => { let existingException: UpdateExceptionListItemSchema; beforeEach(() => { existingException = { @@ -104,6 +168,7 @@ describe('When on the host isolation exceptions entry form', () => { description: 'initial description', id: uuid.v4(), item_id: uuid.v4(), + tags: ['policy:all'], entries: [ { field: 'destination.ip', @@ -113,10 +178,10 @@ describe('When on the host isolation exceptions entry form', () => { }, ], }; - renderResult = render(existingException); }); it('should render the form with pre-filled inputs', () => { + renderResult = render(existingException); expect(renderResult.getByTestId('hostIsolationExceptions-form-name-input')).toHaveValue( 'name edit me' ); @@ -129,6 +194,7 @@ describe('When on the host isolation exceptions entry form', () => { }); it('should call onChange with the partial change when a value is introduced in a field', () => { + renderResult = render(existingException); const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); userEvent.clear(ipInput); userEvent.type(ipInput, '10.0.100.1'); @@ -138,5 +204,34 @@ describe('When on the host isolation exceptions entry form', () => { ], }); }); + + it('should show global pre-selected', () => { + renderResult = render(existingException); + expect( + renderResult + .getByTestId('effectedPolicies-select-global') + .classList.contains('euiButtonGroupButton-isSelected') + ).toBe(true); + // policy selector should be hidden + expect(renderResult.queryByTestId('effectedPolicies-select-policiesSelectable')).toBeFalsy(); + }); + + it('should show pre-selected policies', () => { + const policyId1 = policiesRequest.items[0].id; + const policyId2 = policiesRequest.items[3].id; + existingException.tags = [`policy:${policyId1}`, `policy:${policyId2}`]; + + renderResult = render(existingException); + + expect(renderResult.queryByTestId('effectedPolicies-select-policiesSelectable')).toBeTruthy(); + expect(renderResult.getByTestId(`policy-${policyId1}`)).toHaveAttribute( + 'aria-selected', + 'true' + ); + expect(renderResult.getByTestId(`policy-${policyId2}`)).toHaveAttribute( + 'aria-selected', + 'true' + ); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts b/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts index 40b7166ca5849..500fe15d759da 100644 --- a/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts +++ b/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts @@ -9,7 +9,7 @@ import { GetPolicyListResponse } from '../pages/policy/types'; export const sendGetEndpointSpecificPackagePoliciesMock = (): GetPolicyListResponse => { const generator = new FleetPackagePolicyGenerator(); - const items = Array(5).map((_, index) => { + const items = Array.from({ length: 5 }, (_, index) => { const policy = generator.generateEndpointPackagePolicy(); policy.name += ` ${index}`; return policy; From f399c1aa78e6b0422018dd5a56f4c0355514827f Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 29 Nov 2021 10:00:45 -0500 Subject: [PATCH 18/26] Fix form tests --- .../view/components/form.test.tsx | 6 ++-- .../view/components/form_flyout.test.tsx | 20 +++++++---- .../view/components/form_flyout.tsx | 2 +- .../host_isolation_exceptions_list.test.tsx | 18 ++++++++-- .../public/management/services/hooks.ts | 35 +++++++++++++++++++ .../public/management/services/policies.ts | 27 -------------- .../management/services/test_mock_utilts.ts | 27 +++++++------- 7 files changed, 82 insertions(+), 53 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/services/hooks.ts diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx index c061597d19b3e..7e3034c3c074d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx @@ -30,11 +30,11 @@ describe('When on the host isolation exceptions entry form', () => { const onError = jest.fn(); let policiesRequest: GetPolicyListResponse; - beforeEach(() => { + beforeEach(async () => { onChange.mockReset(); onError.mockReset(); const mockedContext = createAppRootMockRenderer(); - policiesRequest = sendGetEndpointSpecificPackagePoliciesMock(); + policiesRequest = await sendGetEndpointSpecificPackagePoliciesMock(); render = (exception) => { return mockedContext.render( { expect(renderResult.queryByTestId('effectedPolicies-select-policiesSelectable')).toBeFalsy(); }); - it('should show pre-selected policies', () => { + it('should show pre-selected policies', () => { const policyId1 = policiesRequest.items[0].id; const policyId2 = policiesRequest.items[3].id; existingException.tags = [`policy:${policyId1}`, `policy:${policyId2}`]; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx index 4ed79cabdb32b..a39669d2046e5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx @@ -5,29 +5,35 @@ * 2.0. */ +import { waitFor, waitForElementToBeRemoved } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import React from 'react'; +import uuid from 'uuid'; import { AppContextTestRender, createAppRootMockRenderer, } from '../../../../../common/mock/endpoint'; -import userEvent from '@testing-library/user-event'; -import { HostIsolationExceptionsFormFlyout } from './form_flyout'; -import uuid from 'uuid'; -import { createEmptyHostIsolationException } from '../../utils'; -import { waitFor, waitForElementToBeRemoved } from '@testing-library/react'; +import { getHostIsolationExceptionsListPath } from '../../../../common/routing'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../../services/policies'; +import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../../services/test_mock_utilts'; import { createHostIsolationExceptionItem, - updateOneHostIsolationExceptionItem, getOneHostIsolationExceptionItem, + updateOneHostIsolationExceptionItem, } from '../../service'; -import { getHostIsolationExceptionsListPath } from '../../../../common/routing'; +import { createEmptyHostIsolationException } from '../../utils'; +import { HostIsolationExceptionsFormFlyout } from './form_flyout'; jest.mock('../../service.ts'); jest.mock('../../../../../common/hooks/use_license'); +jest.mock('../../../../services/policies'); const createHostIsolationExceptionItemMock = createHostIsolationExceptionItem as jest.Mock; const updateOneHostIsolationExceptionItemMock = updateOneHostIsolationExceptionItem as jest.Mock; const getOneHostIsolationExceptionItemMock = getOneHostIsolationExceptionItem as jest.Mock; +(sendGetEndpointSpecificPackagePolicies as jest.Mock).mockImplementation( + sendGetEndpointSpecificPackagePoliciesMock +); describe('When on the host isolation exceptions flyout form', () => { let mockedContext: AppContextTestRender; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index 419d84e554b3b..20ed19a07c741 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -26,7 +26,7 @@ import { useMutation, useQueryClient } from 'react-query'; import { Loader } from '../../../../../common/components/loader'; import { useHttp, useToasts } from '../../../../../common/lib/kibana'; import { ServerApiError } from '../../../../../common/types'; -import { useGetEndpointSpecificPolicies } from '../../../../services/policies'; +import { useGetEndpointSpecificPolicies } from '../../../../services/hooks'; import { createHostIsolationExceptionItem, updateOneHostIsolationExceptionItem, diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx index f6f68f1f6e970..846546a6a3f9f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx @@ -10,16 +10,22 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { getFoundExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/found_exception_list_item_schema.mock'; import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../common/constants'; +import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; +import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../services/test_mock_utilts'; import { getHostIsolationExceptionItems } from '../service'; import { HostIsolationExceptionsList } from './host_isolation_exceptions_list'; -import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; jest.mock('../service'); jest.mock('../../../../common/hooks/use_license'); jest.mock('../../../../common/components/user_privileges/endpoint/use_endpoint_privileges'); +jest.mock('../../../services/policies'); const getHostIsolationExceptionItemsMock = getHostIsolationExceptionItems as jest.Mock; +(sendGetEndpointSpecificPackagePolicies as jest.Mock).mockImplementation( + sendGetEndpointSpecificPackagePoliciesMock +); describe('When on the host isolation exceptions page', () => { let render: () => ReturnType; @@ -29,7 +35,9 @@ describe('When on the host isolation exceptions page', () => { const useEndpointPrivilegesMock = useEndpointPrivileges as jest.Mock; const waitForApiCall = () => { - return waitFor(() => expect(getHostIsolationExceptionItemsMock).toHaveBeenCalled()); + return waitFor(() => { + expect(getHostIsolationExceptionItemsMock).toHaveBeenCalled(); + }); }; beforeEach(() => { @@ -163,6 +171,9 @@ describe('When on the host isolation exceptions page', () => { await waitForApiCall(); userEvent.click(renderResult.getByTestId('hostIsolationExceptionsListAddButton')); await waitForApiCall(); + await waitFor(() => { + expect(sendGetEndpointSpecificPackagePolicies).toHaveBeenCalled(); + }); expect(renderResult.getByTestId('hostIsolationExceptionsCreateEditFlyout')).toBeTruthy(); }); @@ -170,6 +181,9 @@ describe('When on the host isolation exceptions page', () => { history.push(`${HOST_ISOLATION_EXCEPTIONS_PATH}?show=create`); render(); await waitForApiCall(); + await waitFor(() => { + expect(sendGetEndpointSpecificPackagePolicies).toHaveBeenCalled(); + }); expect(renderResult.getByTestId('hostIsolationExceptionsCreateEditFlyout')).toBeTruthy(); expect(renderResult.queryByTestId('hostIsolationExceptionsCreateEditFlyout')).toBeTruthy(); }); diff --git a/x-pack/plugins/security_solution/public/management/services/hooks.ts b/x-pack/plugins/security_solution/public/management/services/hooks.ts new file mode 100644 index 0000000000000..c2481b0f22878 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/services/hooks.ts @@ -0,0 +1,35 @@ +/* + * 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 { QueryObserverResult, useQuery } from 'react-query'; +import { useHttp } from '../../common/lib/kibana/hooks'; +import { ServerApiError } from '../../common/types'; +import { GetPolicyListResponse } from '../pages/policy/types'; +import { sendGetEndpointSpecificPackagePolicies } from './policies'; + +export function useGetEndpointSpecificPolicies({ + onError, +}: { + onError: (error: ServerApiError) => void; +}): QueryObserverResult { + const http = useHttp(); + return useQuery( + ['endpointSpecificPolicies'], + () => { + return sendGetEndpointSpecificPackagePolicies(http, { + query: { + page: 1, + perPage: 1000, + }, + }); + }, + { + refetchIntervalInBackground: false, + refetchOnWindowFocus: false, + onError, + } + ); +} diff --git a/x-pack/plugins/security_solution/public/management/services/policies.ts b/x-pack/plugins/security_solution/public/management/services/policies.ts index 7a2a94308a32a..63810ad499c09 100644 --- a/x-pack/plugins/security_solution/public/management/services/policies.ts +++ b/x-pack/plugins/security_solution/public/management/services/policies.ts @@ -6,13 +6,10 @@ */ import { HttpFetchOptions, HttpStart } from 'kibana/public'; -import { QueryObserverResult, useQuery } from 'react-query'; import { GetPackagePoliciesRequest, PACKAGE_POLICY_SAVED_OBJECT_TYPE, } from '../../../../fleet/common'; -import { useHttp } from '../../common/lib/kibana/hooks'; -import { ServerApiError } from '../../common/types'; import { INGEST_API_PACKAGE_POLICIES } from '../pages/policy/store/services/ingest'; import { GetPolicyListResponse } from '../pages/policy/types'; @@ -36,27 +33,3 @@ export const sendGetEndpointSpecificPackagePolicies = ( }, }); }; - -export function useGetEndpointSpecificPolicies({ - onError, -}: { - onError: (error: ServerApiError) => void; -}): QueryObserverResult { - const http = useHttp(); - return useQuery( - ['endpointSpecificPolicies'], - () => { - return sendGetEndpointSpecificPackagePolicies(http, { - query: { - page: 1, - perPage: 1000, - }, - }); - }, - { - refetchIntervalInBackground: false, - refetchOnWindowFocus: false, - onError, - } - ); -} diff --git a/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts b/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts index 500fe15d759da..b0b61fc3c74b9 100644 --- a/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts +++ b/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts @@ -7,18 +7,19 @@ import { FleetPackagePolicyGenerator } from '../../../common/endpoint/data_generators/fleet_package_policy_generator'; import { GetPolicyListResponse } from '../pages/policy/types'; -export const sendGetEndpointSpecificPackagePoliciesMock = (): GetPolicyListResponse => { - const generator = new FleetPackagePolicyGenerator(); - const items = Array.from({ length: 5 }, (_, index) => { - const policy = generator.generateEndpointPackagePolicy(); - policy.name += ` ${index}`; - return policy; - }); +export const sendGetEndpointSpecificPackagePoliciesMock = + async (): Promise => { + const generator = new FleetPackagePolicyGenerator(); + const items = Array.from({ length: 5 }, (_, index) => { + const policy = generator.generateEndpointPackagePolicy(); + policy.name += ` ${index}`; + return policy; + }); - return { - items, - total: 5, - page: 1, - perPage: 10, + return { + items, + total: 5, + page: 1, + perPage: 10, + }; }; -}; From 985a84f7aacef1a8133927746c636a0ec05b9308 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 29 Nov 2021 10:23:14 -0500 Subject: [PATCH 19/26] Move policies service to its own folder --- .../pages/endpoint_hosts/store/middleware.ts | 105 +++++++++--------- .../view/components/form.test.tsx | 2 +- .../view/components/form_flyout.test.tsx | 6 +- .../view/components/form_flyout.tsx | 2 +- .../host_isolation_exceptions_list.test.tsx | 6 +- .../service/trusted_apps_http_service.ts | 22 ++-- .../services/{ => policies}/hooks.ts | 6 +- .../services/{ => policies}/policies.test.ts | 6 +- .../services/{ => policies}/policies.ts | 6 +- .../{ => policies}/test_mock_utilts.ts | 4 +- 10 files changed, 82 insertions(+), 83 deletions(-) rename x-pack/plugins/security_solution/public/management/services/{ => policies}/hooks.ts (83%) rename x-pack/plugins/security_solution/public/management/services/{ => policies}/policies.test.ts (85%) rename x-pack/plugins/security_solution/public/management/services/{ => policies}/policies.ts (84%) rename x-pack/plugins/security_solution/public/management/services/{ => policies}/test_mock_utilts.ts (78%) diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index d82518c303c6e..2759a35841524 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -5,11 +5,20 @@ * 2.0. */ +import type { DataViewBase, Query } from '@kbn/es-query'; +import { CoreStart, HttpStart } from 'kibana/public'; import { Dispatch } from 'redux'; import semverGte from 'semver/functions/gte'; - -import { CoreStart, HttpStart } from 'kibana/public'; -import type { DataViewBase, Query } from '@kbn/es-query'; +import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../fleet/common'; +import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants'; +import { + BASE_POLICY_RESPONSE_ROUTE, + ENDPOINT_ACTION_LOG_ROUTE, + HOST_METADATA_GET_ROUTE, + HOST_METADATA_LIST_ROUTE, + metadataCurrentIndexPattern, + METADATA_UNITED_INDEX, +} from '../../../../../common/endpoint/constants'; import { ActivityLog, GetHostPolicyResponse, @@ -21,67 +30,57 @@ import { ImmutableObject, MetadataListResponse, } from '../../../../../common/endpoint/types'; -import { GetPolicyListResponse } from '../../policy/types'; +import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint_isolation'; +import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; import { ImmutableMiddlewareAPI, ImmutableMiddlewareFactory } from '../../../../common/store'; +import { AppAction } from '../../../../common/store/actions'; +import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies/policies'; import { - isOnEndpointPage, - hasSelectedEndpoint, - selectedAgent, - uiQueryParams, - listData, + asStaleResourceState, + createFailedResourceState, + createLoadedResourceState, + createLoadingResourceState, +} from '../../../state'; +import { + sendGetAgentPolicyList, + sendGetEndpointSecurityPackage, + sendGetFleetAgentsWithEndpoint, +} from '../../policy/store/services/ingest'; +import { GetPolicyListResponse } from '../../policy/types'; +import { + AgentIdsPendingActions, + EndpointState, + PolicyIds, + TransformStats, + TransformStatsResponse, +} from '../types'; +import { getIsInvalidDateRange } from '../utils'; +import { EndpointPackageInfoStateChanged } from './action'; +import { + detailsData, endpointPackageInfo, - nonExistingPolicies, - patterns, - searchBarQuery, - getIsIsolationRequestPending, - getCurrentIsolationRequestState, + endpointPackageVersion, getActivityLogData, getActivityLogDataPaging, - getLastLoadedActivityLogData, getActivityLogError, - detailsData, + getActivityLogIsUninitializedOrHasSubsequentAPIError, + getCurrentIsolationRequestState, getIsEndpointPackageInfoUninitialized, + getIsIsolationRequestPending, getIsOnEndpointDetailsActivityLog, + getLastLoadedActivityLogData, getMetadataTransformStats, + hasSelectedEndpoint, isMetadataTransformStatsLoading, - getActivityLogIsUninitializedOrHasSubsequentAPIError, - endpointPackageVersion, + isOnEndpointPage, + listData, + nonExistingPolicies, + patterns, + searchBarQuery, + selectedAgent, + uiQueryParams, } from './selectors'; -import { - AgentIdsPendingActions, - EndpointState, - PolicyIds, - TransformStats, - TransformStatsResponse, -} from '../types'; -import { - sendGetEndpointSecurityPackage, - sendGetAgentPolicyList, - sendGetFleetAgentsWithEndpoint, -} from '../../policy/store/services/ingest'; -import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../fleet/common'; -import { - ENDPOINT_ACTION_LOG_ROUTE, - HOST_METADATA_GET_ROUTE, - HOST_METADATA_LIST_ROUTE, - BASE_POLICY_RESPONSE_ROUTE, - metadataCurrentIndexPattern, - METADATA_UNITED_INDEX, -} from '../../../../../common/endpoint/constants'; -import { - asStaleResourceState, - createFailedResourceState, - createLoadedResourceState, - createLoadingResourceState, -} from '../../../state'; -import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint_isolation'; -import { AppAction } from '../../../../common/store/actions'; -import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; -import { EndpointPackageInfoStateChanged } from './action'; -import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; -import { getIsInvalidDateRange } from '../utils'; -import { METADATA_TRANSFORM_STATS_URL } from '../../../../../common/constants'; -import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; type EndpointPageStore = ImmutableMiddlewareAPI; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx index 7e3034c3c074d..10180d378457a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx @@ -16,7 +16,7 @@ import { AppContextTestRender, createAppRootMockRenderer, } from '../../../../../common/mock/endpoint'; -import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../../services/test_mock_utilts'; +import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../../services/policies/test_mock_utilts'; import { GetPolicyListResponse } from '../../../policy/types'; import { createEmptyHostIsolationException } from '../../utils'; import { HostIsolationExceptionsForm } from './form'; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx index a39669d2046e5..e9735c6bad5ef 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.test.tsx @@ -14,8 +14,8 @@ import { createAppRootMockRenderer, } from '../../../../../common/mock/endpoint'; import { getHostIsolationExceptionsListPath } from '../../../../common/routing'; -import { sendGetEndpointSpecificPackagePolicies } from '../../../../services/policies'; -import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../../services/test_mock_utilts'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../../services/policies/policies'; +import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../../services/policies/test_mock_utilts'; import { createHostIsolationExceptionItem, getOneHostIsolationExceptionItem, @@ -26,7 +26,7 @@ import { HostIsolationExceptionsFormFlyout } from './form_flyout'; jest.mock('../../service.ts'); jest.mock('../../../../../common/hooks/use_license'); -jest.mock('../../../../services/policies'); +jest.mock('../../../../services/policies/policies'); const createHostIsolationExceptionItemMock = createHostIsolationExceptionItem as jest.Mock; const updateOneHostIsolationExceptionItemMock = updateOneHostIsolationExceptionItem as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx index 20ed19a07c741..d48343f0f4b1c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form_flyout.tsx @@ -26,7 +26,7 @@ import { useMutation, useQueryClient } from 'react-query'; import { Loader } from '../../../../../common/components/loader'; import { useHttp, useToasts } from '../../../../../common/lib/kibana'; import { ServerApiError } from '../../../../../common/types'; -import { useGetEndpointSpecificPolicies } from '../../../../services/hooks'; +import { useGetEndpointSpecificPolicies } from '../../../../services/policies/hooks'; import { createHostIsolationExceptionItem, updateOneHostIsolationExceptionItem, diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx index 846546a6a3f9f..f3a4a35144f93 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx @@ -12,15 +12,15 @@ import { getFoundExceptionListItemSchemaMock } from '../../../../../../lists/com import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../common/constants'; import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint'; -import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; -import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../services/test_mock_utilts'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies/policies'; +import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../services/policies/test_mock_utilts'; import { getHostIsolationExceptionItems } from '../service'; import { HostIsolationExceptionsList } from './host_isolation_exceptions_list'; jest.mock('../service'); jest.mock('../../../../common/hooks/use_license'); jest.mock('../../../../common/components/user_privileges/endpoint/use_endpoint_privileges'); -jest.mock('../../../services/policies'); +jest.mock('../../../services/policies/policies'); const getHostIsolationExceptionItemsMock = getHostIsolationExceptionItems as jest.Mock; (sendGetEndpointSpecificPackagePolicies as jest.Mock).mockImplementation( diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/trusted_apps_http_service.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/trusted_apps_http_service.ts index b12d5e9c65cd1..add5f73b49b91 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/trusted_apps_http_service.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/trusted_apps_http_service.ts @@ -5,19 +5,20 @@ * 2.0. */ -import pMap from 'p-map'; -import { HttpStart } from 'kibana/public'; -import { - ENDPOINT_TRUSTED_APPS_LIST_ID, - EXCEPTION_LIST_ITEM_URL, - EXCEPTION_LIST_URL, -} from '@kbn/securitysolution-list-constants'; import { ExceptionListItemSchema, ExceptionListSchema, ExceptionListSummarySchema, FoundExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { + ENDPOINT_TRUSTED_APPS_LIST_ID, + EXCEPTION_LIST_ITEM_URL, + EXCEPTION_LIST_URL, +} from '@kbn/securitysolution-list-constants'; +import { HttpStart } from 'kibana/public'; +import pMap from 'p-map'; +import { toUpdateTrustedApp } from '../../../../../common/endpoint/service/trusted_apps/to_update_trusted_app'; import { DeleteTrustedAppsRequestParams, GetOneTrustedAppRequestParams, @@ -33,16 +34,15 @@ import { PutTrustedAppUpdateResponse, TrustedApp, } from '../../../../../common/endpoint/types'; -import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies'; +import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies/policies'; +import { TRUSTED_APPS_EXCEPTION_LIST_DEFINITION } from '../constants'; import { isGlobalEffectScope } from '../state/type_guards'; -import { toUpdateTrustedApp } from '../../../../../common/endpoint/service/trusted_apps/to_update_trusted_app'; -import { validateTrustedAppHttpRequestBody } from './validate_trusted_app_http_request_body'; import { exceptionListItemToTrustedApp, newTrustedAppToCreateExceptionListItem, updatedTrustedAppToUpdateExceptionListItem, } from './mappers'; -import { TRUSTED_APPS_EXCEPTION_LIST_DEFINITION } from '../constants'; +import { validateTrustedAppHttpRequestBody } from './validate_trusted_app_http_request_body'; export interface TrustedAppsService { getTrustedApp(params: GetOneTrustedAppRequestParams): Promise; diff --git a/x-pack/plugins/security_solution/public/management/services/hooks.ts b/x-pack/plugins/security_solution/public/management/services/policies/hooks.ts similarity index 83% rename from x-pack/plugins/security_solution/public/management/services/hooks.ts rename to x-pack/plugins/security_solution/public/management/services/policies/hooks.ts index c2481b0f22878..d59b2ca984131 100644 --- a/x-pack/plugins/security_solution/public/management/services/hooks.ts +++ b/x-pack/plugins/security_solution/public/management/services/policies/hooks.ts @@ -5,9 +5,9 @@ * 2.0. */ import { QueryObserverResult, useQuery } from 'react-query'; -import { useHttp } from '../../common/lib/kibana/hooks'; -import { ServerApiError } from '../../common/types'; -import { GetPolicyListResponse } from '../pages/policy/types'; +import { useHttp } from '../../../common/lib/kibana/hooks'; +import { ServerApiError } from '../../../common/types'; +import { GetPolicyListResponse } from '../../pages/policy/types'; import { sendGetEndpointSpecificPackagePolicies } from './policies'; export function useGetEndpointSpecificPolicies({ diff --git a/x-pack/plugins/security_solution/public/management/services/policies.test.ts b/x-pack/plugins/security_solution/public/management/services/policies/policies.test.ts similarity index 85% rename from x-pack/plugins/security_solution/public/management/services/policies.test.ts rename to x-pack/plugins/security_solution/public/management/services/policies/policies.test.ts index 0b93dffb71d3c..acdecd7072366 100644 --- a/x-pack/plugins/security_solution/public/management/services/policies.test.ts +++ b/x-pack/plugins/security_solution/public/management/services/policies/policies.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { httpServiceMock } from '../../../../../../src/core/public/mocks'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../fleet/common'; -import { PACKAGE_POLICY_API_ROUTES } from '../../../../fleet/common/constants/routes'; +import { httpServiceMock } from '../../../../../../../src/core/public/mocks'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../../fleet/common'; +import { PACKAGE_POLICY_API_ROUTES } from '../../../../../fleet/common/constants/routes'; import { sendGetEndpointSpecificPackagePolicies } from './policies'; describe('ingest service', () => { diff --git a/x-pack/plugins/security_solution/public/management/services/policies.ts b/x-pack/plugins/security_solution/public/management/services/policies/policies.ts similarity index 84% rename from x-pack/plugins/security_solution/public/management/services/policies.ts rename to x-pack/plugins/security_solution/public/management/services/policies/policies.ts index 63810ad499c09..2cd71fb26655a 100644 --- a/x-pack/plugins/security_solution/public/management/services/policies.ts +++ b/x-pack/plugins/security_solution/public/management/services/policies/policies.ts @@ -9,9 +9,9 @@ import { HttpFetchOptions, HttpStart } from 'kibana/public'; import { GetPackagePoliciesRequest, PACKAGE_POLICY_SAVED_OBJECT_TYPE, -} from '../../../../fleet/common'; -import { INGEST_API_PACKAGE_POLICIES } from '../pages/policy/store/services/ingest'; -import { GetPolicyListResponse } from '../pages/policy/types'; +} from '../../../../../fleet/common'; +import { INGEST_API_PACKAGE_POLICIES } from '../../pages/policy/store/services/ingest'; +import { GetPolicyListResponse } from '../../pages/policy/types'; /** * Retrieves a list of endpoint specific package policies (those created with a `package.name` of diff --git a/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts b/x-pack/plugins/security_solution/public/management/services/policies/test_mock_utilts.ts similarity index 78% rename from x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts rename to x-pack/plugins/security_solution/public/management/services/policies/test_mock_utilts.ts index b0b61fc3c74b9..026fb8e243b0b 100644 --- a/x-pack/plugins/security_solution/public/management/services/test_mock_utilts.ts +++ b/x-pack/plugins/security_solution/public/management/services/policies/test_mock_utilts.ts @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { FleetPackagePolicyGenerator } from '../../../common/endpoint/data_generators/fleet_package_policy_generator'; -import { GetPolicyListResponse } from '../pages/policy/types'; +import { FleetPackagePolicyGenerator } from '../../../../common/endpoint/data_generators/fleet_package_policy_generator'; +import { GetPolicyListResponse } from '../../pages/policy/types'; export const sendGetEndpointSpecificPackagePoliciesMock = async (): Promise => { From 270f54cf79173a91deb4b220b6cfe0c210b10315 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Mon, 29 Nov 2021 12:20:10 -0500 Subject: [PATCH 20/26] Display the name of policies on the artifact card --- ..._endpoint_policies_to_artifact_policies.ts | 38 ++++++++++++++++ .../view/host_isolation_exceptions_list.tsx | 44 ++++++++++++------- 2 files changed, 65 insertions(+), 17 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/components/artifact_entry_card/hooks/use_endpoint_policies_to_artifact_policies.ts diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/hooks/use_endpoint_policies_to_artifact_policies.ts b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/hooks/use_endpoint_policies_to_artifact_policies.ts new file mode 100644 index 0000000000000..d28c6cbe3b107 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/hooks/use_endpoint_policies_to_artifact_policies.ts @@ -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 { useMemo } from 'react'; +import { MenuItemPropsByPolicyId } from '..'; +import { PolicyData } from '../../../../../common/endpoint/types'; +import { useAppUrl } from '../../../../common/lib/kibana'; +import { getPolicyDetailPath } from '../../../common/routing'; + +/** + * Takes a list of EndpointPolicies (PolicyData) and turn them + * into MenuItemPropsByPolicyId required by the artifact card. + * + * The resulting menu will open the policies in a new tab + * + */ +export const useEndpointPoliciesToArtifactPolicies = ( + policies: PolicyData[] = [] +): MenuItemPropsByPolicyId => { + const { getAppUrl } = useAppUrl(); + return useMemo(() => { + const data = policies.reduce((policiesMap, policy) => { + const policyId = policy.id; + const policyDetailsPath = getPolicyDetailPath(policyId); + policiesMap[policyId] = { + href: getAppUrl({ path: policyDetailsPath }), + children: policy.name ?? policyId, + target: '_blank', + }; + return policiesMap; + }, {}); + return data; + }, [getAppUrl, policies]); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx index a9da5c6d135a3..875e5d1819471 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx @@ -5,37 +5,39 @@ * 2.0. */ -import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EuiButton, EuiSpacer, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useCallback, useEffect, useState } from 'react'; -import { EuiButton, EuiText, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import React, { useCallback, useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; +import { Immutable } from '../../../../../common/endpoint/types'; import { ExceptionItem } from '../../../../common/components/exceptions/viewer/exception_item'; -import { getCurrentLocation } from '../store/selector'; +import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; import { - useFetchHostIsolationExceptionsList, - useHostIsolationExceptionsNavigateCallback, - useHostIsolationExceptionsSelector, -} from './hooks'; -import { PaginatedContent, PaginatedContentProps } from '../../../components/paginated_content'; -import { Immutable } from '../../../../../common/endpoint/types'; + MANAGEMENT_DEFAULT_PAGE_SIZE, + MANAGEMENT_PAGE_SIZE_OPTIONS, +} from '../../../common/constants'; +import { getEndpointListPath } from '../../../common/routing'; import { AdministrationListPage } from '../../../components/administration_list_page'; -import { SearchExceptions } from '../../../components/search_exceptions'; import { ArtifactEntryCard, ArtifactEntryCardProps } from '../../../components/artifact_entry_card'; -import { HostIsolationExceptionsEmptyState } from './components/empty'; +import { useEndpointPoliciesToArtifactPolicies } from '../../../components/artifact_entry_card/hooks/use_endpoint_policies_to_artifact_policies'; +import { PaginatedContent, PaginatedContentProps } from '../../../components/paginated_content'; +import { SearchExceptions } from '../../../components/search_exceptions'; +import { useGetEndpointSpecificPolicies } from '../../../services/policies/hooks'; +import { getCurrentLocation } from '../store/selector'; import { HostIsolationExceptionDeleteModal } from './components/delete_modal'; +import { HostIsolationExceptionsEmptyState } from './components/empty'; import { HostIsolationExceptionsFormFlyout } from './components/form_flyout'; import { DELETE_HOST_ISOLATION_EXCEPTION_LABEL, EDIT_HOST_ISOLATION_EXCEPTION_LABEL, } from './components/translations'; -import { getEndpointListPath } from '../../../common/routing'; -import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; import { - MANAGEMENT_DEFAULT_PAGE_SIZE, - MANAGEMENT_PAGE_SIZE_OPTIONS, -} from '../../../common/constants'; + useFetchHostIsolationExceptionsList, + useHostIsolationExceptionsNavigateCallback, + useHostIsolationExceptionsSelector, +} from './hooks'; type HostIsolationExceptionPaginatedContent = PaginatedContentProps< Immutable, @@ -53,6 +55,11 @@ export const HostIsolationExceptionsList = () => { const { isLoading, data, error, refetch } = useFetchHostIsolationExceptionsList(); + // load the list of policies> + const policiesRequest = useGetEndpointSpecificPolicies({ + onError: () => {}, + }); + const pagination = { totalItemCount: data?.total ?? 0, pageSize: data?.per_page ?? MANAGEMENT_DEFAULT_PAGE_SIZE, @@ -79,6 +86,8 @@ export const HostIsolationExceptionsList = () => { [navigateCallback] ); + const artifactCardPolicies = useEndpointPoliciesToArtifactPolicies(policiesRequest.data?.items); + function handleItemComponentProps(element: ExceptionListItemSchema): ArtifactEntryCardProps { const editAction = { icon: 'controlsHorizontal', @@ -103,6 +112,7 @@ export const HostIsolationExceptionsList = () => { item: element, 'data-test-subj': `hostIsolationExceptionsCard`, actions: privileges.canIsolateHost ? [editAction, deleteAction] : [deleteAction], + policies: artifactCardPolicies, }; } From 3aa2ef0707b9392f97d47f6073e5328a58d55a52 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Tue, 30 Nov 2021 07:56:11 -0500 Subject: [PATCH 21/26] Show error if policies can't be loaded --- .../view/components/translations.ts | 7 +++++++ .../view/host_isolation_exceptions_list.tsx | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts index 9504aa0673e54..de8f8bb9f0d23 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/translations.ts @@ -127,3 +127,10 @@ export const getCreationSuccessMessage = (name: string) => { } ); }; + +export const getLoadPoliciesError = (error: ServerApiError) => { + return i18n.translate('xpack.securitySolution.hostIsolationExceptions.failedLoadPolicies', { + defaultMessage: 'There was an error loading policies: "{error}"', + values: { error: error.message }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx index 875e5d1819471..a2bd3c73d8e5b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.tsx @@ -14,6 +14,7 @@ import { useHistory } from 'react-router-dom'; import { Immutable } from '../../../../../common/endpoint/types'; import { ExceptionItem } from '../../../../common/components/exceptions/viewer/exception_item'; import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; +import { useToasts } from '../../../../common/lib/kibana'; import { MANAGEMENT_DEFAULT_PAGE_SIZE, MANAGEMENT_PAGE_SIZE_OPTIONS, @@ -32,6 +33,7 @@ import { HostIsolationExceptionsFormFlyout } from './components/form_flyout'; import { DELETE_HOST_ISOLATION_EXCEPTION_LABEL, EDIT_HOST_ISOLATION_EXCEPTION_LABEL, + getLoadPoliciesError, } from './components/translations'; import { useFetchHostIsolationExceptionsList, @@ -54,10 +56,13 @@ export const HostIsolationExceptionsList = () => { const [itemToDelete, setItemToDelete] = useState(null); const { isLoading, data, error, refetch } = useFetchHostIsolationExceptionsList(); + const toasts = useToasts(); // load the list of policies> const policiesRequest = useGetEndpointSpecificPolicies({ - onError: () => {}, + onError: (err) => { + toasts.addDanger(getLoadPoliciesError(err)); + }, }); const pagination = { From 87aefd3e044e30de011fc714af2e55f3d837bb31 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Wed, 1 Dec 2021 07:35:03 -0500 Subject: [PATCH 22/26] Use full width for effected policies selector --- .../pages/host_isolation_exceptions/view/components/form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index 44d8517b51270..3a6ff771324f5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -245,7 +245,7 @@ export const HostIsolationExceptionsForm: React.FC<{ {ipInput} - + Date: Thu, 2 Dec 2021 07:47:48 -0500 Subject: [PATCH 23/26] Add documentation --- .../management/components/effected_policy_select/utils.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts index 811fca77cdc78..8144719751e5a 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts @@ -21,6 +21,13 @@ export function getArtifactTagsByEffectedPolicySelection( }); } +/** + * Given a list of an Exception item tags it will return + * the parsed policies from it. + * + * Policy tags follow the pattern `policy:id` + * non policy tags will be ignored. + */ export function getEffectedPolicySelectionByTags( tags: string[], policies: PolicyData[] From a24a200075d01d7316e85904f3758cfd86edf8ce Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 2 Dec 2021 08:02:35 -0500 Subject: [PATCH 24/26] Preserve previous tags --- .../effected_policy_select/utils.ts | 21 ++++++++++++++++--- .../view/components/form.tsx | 8 +++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts index 8144719751e5a..f273ecaa96c56 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts @@ -10,15 +10,30 @@ import { EffectedPolicySelection } from './effected_policy_select'; export const GLOBAL_POLICY_TAG = 'policy:all'; +/** + * Given a list of artifact tags, returns the tags that are not policy tags + * policy tags follow the format: `policy:id` + */ +export function getArtifactTagsWithoutPolicies(tags?: string[]): string[] { + return tags?.filter((tag) => !tag.startsWith('policy:')) || []; +} + +/** + * Return a list of artifact policy tags based on a current + * selection by the EffectedPolicySelection component. + */ export function getArtifactTagsByEffectedPolicySelection( - selection: EffectedPolicySelection + selection: EffectedPolicySelection, + otherTags: string[] = [] ): string[] { if (selection.isGlobal) { - return [GLOBAL_POLICY_TAG]; + return [GLOBAL_POLICY_TAG, ...otherTags]; } - return selection.selected.map((policy) => { + const newTags = selection.selected.map((policy) => { return `policy:${policy.id}`; }); + + return newTags.concat(otherTags); } /** diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index 3a6ff771324f5..ec2a3ffe0936d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -29,6 +29,7 @@ import { } from '../../../../components/effected_policy_select'; import { getArtifactTagsByEffectedPolicySelection, + getArtifactTagsWithoutPolicies, getEffectedPolicySelectionByTags, isGlobalPolicyEffected, } from '../../../../components/effected_policy_select/utils'; @@ -126,10 +127,13 @@ export const HostIsolationExceptionsForm: React.FC<{ setSelectedPolicies(() => selection); } onChange({ - tags: getArtifactTagsByEffectedPolicySelection(selection), + tags: getArtifactTagsByEffectedPolicySelection( + selection, + getArtifactTagsWithoutPolicies(exception.tags) + ), }); }, - [onChange] + [exception.tags, onChange] ); const handleOnDescriptionChange = useCallback( From d1f505adeb0d61b43d251a660be78eeb398b2249 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 2 Dec 2021 09:20:34 -0500 Subject: [PATCH 25/26] Remove duplicated logic for isGlobal --- .../view/components/form.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx index ec2a3ffe0936d..a9d1572ba5cba 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.tsx @@ -66,9 +66,8 @@ export const HostIsolationExceptionsForm: React.FC<{ const [hasNameError, setHasNameError] = useState(!exception.name); const [hasIpError, setHasIpError] = useState(!ipEntry.value); - const [isGlobal, setIsGlobal] = useState(isGlobalPolicyEffected(exception.tags)); const [selectedPolicies, setSelectedPolicies] = useState({ - isGlobal, + isGlobal: isGlobalPolicyEffected(exception.tags), selected: [], }); @@ -120,12 +119,13 @@ export const HostIsolationExceptionsForm: React.FC<{ const handlePolicySelectChange: EffectedPolicySelectProps['onChange'] = useCallback( (selection) => { - setIsGlobal(selection.isGlobal); - // preseve the previous selection between global and not global toggle - if (!selection.isGlobal) { - setSelectedPolicies(() => selection); + if (selection.isGlobal) { + setSelectedPolicies({ isGlobal: true, selected: selection.selected }); + } else { + setSelectedPolicies(selection); } + onChange({ tags: getArtifactTagsByEffectedPolicySelection( selection, @@ -251,7 +251,7 @@ export const HostIsolationExceptionsForm: React.FC<{ Date: Sat, 4 Dec 2021 12:46:40 -0500 Subject: [PATCH 26/26] Remove unused dependency --- .../view/host_isolation_exceptions_list.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx index b9a5aebeeb054..94bd6ea73d7fa 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx @@ -10,7 +10,6 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { getFoundExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/found_exception_list_item_schema.mock'; import { HOST_ISOLATION_EXCEPTIONS_PATH } from '../../../../../common/constants'; -import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint'; import { AppContextTestRender, createAppRootMockRenderer } from '../../../../common/mock/endpoint'; import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies/policies'; import { sendGetEndpointSpecificPackagePoliciesMock } from '../../../services/policies/test_mock_utilts';