From d1a4e7937142b92ee270434150731f692224a211 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Mon, 20 Nov 2023 18:27:06 +0100 Subject: [PATCH 01/33] agentless/agent-based selector --- .../fleet_extensions/policy_template_form.tsx | 104 +++++++++++++++++- .../plugins/fleet/common/constants/index.ts | 1 + .../fleet/common/constants/setup_type.ts | 10 ++ x-pack/plugins/fleet/common/index.ts | 2 + .../fleet/common/types/models/index.ts | 1 + .../fleet/common/types/models/setup_type.ts | 11 ++ .../single_page_layout/index.tsx | 98 ++++++++++++++--- x-pack/plugins/fleet/public/index.ts | 1 + x-pack/plugins/fleet/public/types/index.ts | 1 + .../fleet/public/types/ui_extensions.ts | 2 + 10 files changed, 207 insertions(+), 24 deletions(-) create mode 100644 x-pack/plugins/fleet/common/constants/setup_type.ts create mode 100644 x-pack/plugins/fleet/common/types/models/setup_type.ts diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 92ee1f34a59b2..35664639752b5 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -10,17 +10,22 @@ import semverValid from 'semver/functions/valid'; import semverCoerce from 'semver/functions/coerce'; import semverLt from 'semver/functions/lt'; import { + EuiAccordion, EuiCallOut, EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, + EuiLink, EuiLoadingSpinner, EuiSpacer, + EuiSuperSelect, EuiText, EuiTitle, + useGeneratedHtmlId, } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; +import { SetupType } from '@kbn/fleet-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import type { NewPackagePolicyInput, @@ -32,7 +37,7 @@ import { i18n } from '@kbn/i18n'; import { AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE } from './azure_credentials_form/azure_credentials_form'; import { CspRadioGroupProps, RadioGroup } from './csp_boxed_radio_group'; import { assert } from '../../../common/utils/helpers'; -import type { PostureInput, CloudSecurityPolicyTemplate } from '../../../common/types'; +import type { CloudSecurityPolicyTemplate, PostureInput } from '../../../common/types'; import { CLOUDBEAT_AWS, CLOUDBEAT_VANILLA, @@ -41,13 +46,13 @@ import { SUPPORTED_POLICY_TEMPLATES, } from '../../../common/constants'; import { - getPosturePolicy, + getMaxPackageName, getPostureInputHiddenVars, + getPosturePolicy, getVulnMgmtCloudFormationDefaultValue, - POSTURE_NAMESPACE, - type NewPackagePolicyPostureInput, isPostureInput, - getMaxPackageName, + type NewPackagePolicyPostureInput, + POSTURE_NAMESPACE, } from './utils'; import { PolicyTemplateInfo, @@ -506,15 +511,98 @@ const IntegrationSettings = ({ onChange, fields }: IntegrationInfoFieldsProps) = ); +const SetupTypeSelector = ({ + setupType, + onSetupTypeChange, +}: { + setupType: SetupType; + onSetupTypeChange: (value: SetupType) => void; +}) => { + const options = [ + { + value: SetupType.AGENTLESS, + inputDisplay: 'Agentless', + dropdownDisplay: ( + <> + Agentless + +

Set up the integration without an agent

+
+ + ), + }, + { + value: SetupType.AGENT_BASED, + inputDisplay: 'Agent-based', + dropdownDisplay: ( + <> + Agent-based + +

Set up the integration with an agent

+
+ + ), + }, + ]; + + return ( + <> + + Advanced options} + > + + + + + + + ); +}; + export const CspPolicyTemplateForm = memo( - ({ newPolicy, onChange, validationResults, isEditPage, packageInfo }) => { + ({ + newPolicy, + onChange, + validationResults, + isEditPage, + packageInfo, + handleSetupTypeChange, + agentlessPolicy, + }) => { const integrationParam = useParams<{ integration: CloudSecurityPolicyTemplate }>().integration; const integration = SUPPORTED_POLICY_TEMPLATES.includes(integrationParam) ? integrationParam : undefined; // Handling validation state const [isValid, setIsValid] = useState(true); + const [setupType, setSetupType] = useState(SetupType.AGENT_BASED); const input = getSelectedOption(newPolicy.inputs, integration); + const isCspmAws = input.type === CLOUDBEAT_AWS; + const isAgentlessAvailable = isCspmAws && agentlessPolicy; + + useEffect(() => { + if (isAgentlessAvailable) { + setSetupType(SetupType.AGENTLESS); + } else { + setSetupType(SetupType.AGENT_BASED); + } + }, [isAgentlessAvailable]); + + useEffect(() => { + if (handleSetupTypeChange) { + handleSetupTypeChange(setupType); + } + }, [handleSetupTypeChange, setupType]); const updatePolicy = useCallback( (updatedPolicy: NewPackagePolicy) => { @@ -708,6 +796,10 @@ export const CspPolicyTemplateForm = memo updatePolicy({ ...newPolicy, [field]: value })} /> + {isAgentlessAvailable && ( + + )} + {/* Defines the vars of the enabled input of the active policy template */} { const { agents: { enabled: isFleetEnabled }, + enableExperimental, } = useConfig(); const { params } = useRouteMatch(); @@ -293,6 +303,53 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ ); } + const isAgentlessEnabled = enableExperimental?.includes(AGENTLESS_FEATURE_FLAG) ?? false; + const [selectedSetupType, setSelectedSetupType] = useState(SetupType.AGENT_BASED); + const [agentlessPolicy, setAgentlessPolicy] = useState(); + + useEffect(() => { + const fetchAgentlessPolicy = async () => { + const { data, error } = await sendGetOneAgentPolicy(AGENTLESS_POLICY_ID); + const isAgentlessAvailable = !error && data && data.item; + + if (isAgentlessAvailable) { + setAgentlessPolicy(data.item); + } + }; + + if (isAgentlessEnabled) { + fetchAgentlessPolicy(); + } + }, [isAgentlessEnabled]); + + const handleSetupTypeChange = useCallback( + (setupType) => { + if (!isAgentlessEnabled || setupType === selectedSetupType) { + return; + } + + if (setupType === SetupType.AGENTLESS) { + if (agentlessPolicy) { + updateAgentPolicy(agentlessPolicy); + setSelectedPolicyTab(SelectedPolicyTab.EXISTING); + } + } else if (setupType === SetupType.AGENT_BASED) { + updateNewAgentPolicy(newAgentPolicy); + setSelectedPolicyTab(SelectedPolicyTab.NEW); + } + + setSelectedSetupType(setupType); + }, + [ + isAgentlessEnabled, + selectedSetupType, + agentlessPolicy, + updateAgentPolicy, + updateNewAgentPolicy, + newAgentPolicy, + ] + ); + const replaceStepConfigurePackagePolicy = replaceDefineStepView && packageInfo?.name ? ( !isInitialized ? ( @@ -306,6 +363,8 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ onChange={handleExtensionViewOnChange} validationResults={validationResults} isEditPage={false} + handleSetupTypeChange={handleSetupTypeChange} + agentlessPolicy={agentlessPolicy} /> ) @@ -374,13 +433,16 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ 'data-test-subj': 'dataCollectionSetupStep', children: replaceStepConfigurePackagePolicy || stepConfigurePackagePolicy, }, - { + ]; + + if (selectedSetupType !== 'agentless') { + steps.push({ title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { defaultMessage: 'Where to add this integration?', }), children: stepSelectAgentPolicy, - }, - ]; + }); + } // Display package error if there is one if (packageInfoError) { diff --git a/x-pack/plugins/fleet/public/index.ts b/x-pack/plugins/fleet/public/index.ts index 30ccf9c9c657d..d439b0b8e3134 100644 --- a/x-pack/plugins/fleet/public/index.ts +++ b/x-pack/plugins/fleet/public/index.ts @@ -16,6 +16,7 @@ export const plugin = (initializerContext: PluginInitializerContext) => { }; export type { NewPackagePolicy, KibanaSavedObjectType } from './types'; +export { SetupType } from './types'; export type { AgentDetailsReassignPolicyAction, AgentPolicyDetailsDeployAgentAction, diff --git a/x-pack/plugins/fleet/public/types/index.ts b/x-pack/plugins/fleet/public/types/index.ts index 63837dc809559..f4fc1110fd8fd 100644 --- a/x-pack/plugins/fleet/public/types/index.ts +++ b/x-pack/plugins/fleet/public/types/index.ts @@ -144,6 +144,7 @@ export { ElasticsearchAssetType, KibanaAssetType, InstallStatus, + SetupType, } from '../../common/types'; export * from './intra_app_route_state'; diff --git a/x-pack/plugins/fleet/public/types/ui_extensions.ts b/x-pack/plugins/fleet/public/types/ui_extensions.ts index 53ae5322f0d9d..6b7e71827937f 100644 --- a/x-pack/plugins/fleet/public/types/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/types/ui_extensions.ts @@ -36,6 +36,8 @@ export type PackagePolicyReplaceDefineStepExtensionComponentProps = ( validationResults?: PackagePolicyValidationResults; agentPolicy?: AgentPolicy; packageInfo: PackageInfo; + agentlessPolicy?: AgentPolicy; + handleSetupTypeChange?: (setupType: string) => void; }; /** From da03bc89259812822c3d321947b300a36e41ec25 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Tue, 21 Nov 2023 18:04:20 +0100 Subject: [PATCH 02/33] i18n for the SetupType selector --- .../fleet_extensions/policy_template_form.tsx | 68 ++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 35664639752b5..6f0ab800863af 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -521,24 +521,54 @@ const SetupTypeSelector = ({ const options = [ { value: SetupType.AGENTLESS, - inputDisplay: 'Agentless', + inputDisplay: ( + + ), dropdownDisplay: ( <> - Agentless + + + -

Set up the integration without an agent

+

+ +

), }, { value: SetupType.AGENT_BASED, - inputDisplay: 'Agent-based', + inputDisplay: ( + + ), dropdownDisplay: ( <> - Agent-based + + + -

Set up the integration with an agent

+

+ +

), @@ -550,14 +580,34 @@ const SetupTypeSelector = ({ Advanced options} + buttonContent={ + + + + } > - + + } + > + } onChange={onSetupTypeChange} itemLayoutAlign="top" hasDividers From b7327f8cc3b127366c36d18c5ff5ef90a84b9947 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Tue, 21 Nov 2023 18:15:01 +0100 Subject: [PATCH 03/33] use enum in the check to add hosts step --- .../single_page_layout/index.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index 189e7d1a68715..139ca6bb3b60b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -32,11 +32,7 @@ import { useCancelAddPackagePolicy } from '../hooks'; import { isRootPrivilegesRequired, splitPkgKey } from '../../../../../../../common/services'; import { AGENTLESS_FEATURE_FLAG, AGENTLESS_POLICY_ID } from '../../../../../../../common/constants'; -import type { - AgentPolicy, - NewAgentPolicy, - PackagePolicyEditExtensionComponentProps, -} from '../../../../types'; +import type { AgentPolicy, NewAgentPolicy, PackagePolicyEditExtensionComponentProps } from '../../../../types'; import { SetupType } from '../../../../types'; import { sendGetAgentStatus, @@ -435,7 +431,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ }, ]; - if (selectedSetupType !== 'agentless') { + if (selectedSetupType !== SetupType.AGENTLESS) { steps.push({ title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { defaultMessage: 'Where to add this integration?', From ba16765262ce5ffa7bdc390049668f72a4aa76b8 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:56:27 +0000 Subject: [PATCH 04/33] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../create_package_policy_page/single_page_layout/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index 139ca6bb3b60b..b1fde5c95577d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -32,7 +32,11 @@ import { useCancelAddPackagePolicy } from '../hooks'; import { isRootPrivilegesRequired, splitPkgKey } from '../../../../../../../common/services'; import { AGENTLESS_FEATURE_FLAG, AGENTLESS_POLICY_ID } from '../../../../../../../common/constants'; -import type { AgentPolicy, NewAgentPolicy, PackagePolicyEditExtensionComponentProps } from '../../../../types'; +import type { + AgentPolicy, + NewAgentPolicy, + PackagePolicyEditExtensionComponentProps, +} from '../../../../types'; import { SetupType } from '../../../../types'; import { sendGetAgentStatus, From 8239c60c77f596cd612f1f1fd50b4d22f5e5c100 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Wed, 22 Nov 2023 15:25:31 +0100 Subject: [PATCH 05/33] move setup type logic in a hook --- .../fleet/common/constants/setup_type.ts | 2 - .../fleet/common/experimental_features.ts | 1 + .../single_page_layout/hooks/index.tsx | 1 + .../single_page_layout/hooks/setup_type.ts | 81 +++++++++++++++++++ .../single_page_layout/index.tsx | 63 ++------------- 5 files changed, 91 insertions(+), 57 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_type.ts diff --git a/x-pack/plugins/fleet/common/constants/setup_type.ts b/x-pack/plugins/fleet/common/constants/setup_type.ts index df913f9f29861..063c0a0d01301 100644 --- a/x-pack/plugins/fleet/common/constants/setup_type.ts +++ b/x-pack/plugins/fleet/common/constants/setup_type.ts @@ -6,5 +6,3 @@ */ export const AGENTLESS_POLICY_ID = 'agentless_cspm'; - -export const AGENTLESS_FEATURE_FLAG = 'agentless'; diff --git a/x-pack/plugins/fleet/common/experimental_features.ts b/x-pack/plugins/fleet/common/experimental_features.ts index 233173263c129..c8f12d394b6b4 100644 --- a/x-pack/plugins/fleet/common/experimental_features.ts +++ b/x-pack/plugins/fleet/common/experimental_features.ts @@ -25,6 +25,7 @@ export const allowedExperimentalValues = Object.freeze>( kafkaOutput: true, outputSecretsStorage: false, remoteESOutput: false, + agentless: false, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx index 33d1cee841590..ab498174d0d1b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx @@ -7,3 +7,4 @@ export { useDevToolsRequest } from './devtools_request'; export { useOnSubmit } from './form'; +export { useSetupType } from './setup_type'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_type.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_type.ts new file mode 100644 index 0000000000000..ddda53435b75b --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_type.ts @@ -0,0 +1,81 @@ +/* + * 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 { useCallback, useEffect, useState } from 'react'; + +import { AGENTLESS_POLICY_ID } from '../../../../../../../../common/constants'; +import { ExperimentalFeaturesService } from '../../../../../services'; +import type { AgentPolicy, NewAgentPolicy } from '../../../../../types'; +import { SetupType } from '../../../../../types'; +import { sendGetOneAgentPolicy } from '../../../../../hooks'; +import { SelectedPolicyTab } from '../../components'; + +export function useSetupType({ + updateNewAgentPolicy, + newAgentPolicy, + updateAgentPolicy, + setSelectedPolicyTab, +}: { + updateNewAgentPolicy: (policy: NewAgentPolicy) => void; + newAgentPolicy: NewAgentPolicy; + updateAgentPolicy: (policy: AgentPolicy) => void; + setSelectedPolicyTab: (tab: SelectedPolicyTab) => void; +}) { + const { agentless: isAgentlessEnabled } = ExperimentalFeaturesService.get(); + const [selectedSetupType, setSelectedSetupType] = useState(SetupType.AGENT_BASED); + const [agentlessPolicy, setAgentlessPolicy] = useState(); + + useEffect(() => { + const fetchAgentlessPolicy = async () => { + const { data, error } = await sendGetOneAgentPolicy(AGENTLESS_POLICY_ID); + const isAgentlessAvailable = !error && data && data.item; + + if (isAgentlessAvailable) { + setAgentlessPolicy(data.item); + } + }; + + if (isAgentlessEnabled) { + fetchAgentlessPolicy(); + } + }, [isAgentlessEnabled]); + + const handleSetupTypeChange = useCallback( + (setupType) => { + if (!isAgentlessEnabled || setupType === selectedSetupType) { + return; + } + + if (setupType === SetupType.AGENTLESS) { + if (agentlessPolicy) { + updateAgentPolicy(agentlessPolicy); + setSelectedPolicyTab(SelectedPolicyTab.EXISTING); + } + } else if (setupType === SetupType.AGENT_BASED) { + updateNewAgentPolicy(newAgentPolicy); + setSelectedPolicyTab(SelectedPolicyTab.NEW); + } + + setSelectedSetupType(setupType); + }, + [ + isAgentlessEnabled, + selectedSetupType, + agentlessPolicy, + updateAgentPolicy, + setSelectedPolicyTab, + updateNewAgentPolicy, + newAgentPolicy, + ] + ); + + return { + handleSetupTypeChange, + agentlessPolicy, + selectedSetupType, + }; +} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index b1fde5c95577d..c47b73674e880 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -31,16 +31,10 @@ import { import { useCancelAddPackagePolicy } from '../hooks'; import { isRootPrivilegesRequired, splitPkgKey } from '../../../../../../../common/services'; -import { AGENTLESS_FEATURE_FLAG, AGENTLESS_POLICY_ID } from '../../../../../../../common/constants'; -import type { - AgentPolicy, - NewAgentPolicy, - PackagePolicyEditExtensionComponentProps, -} from '../../../../types'; +import type { NewAgentPolicy, PackagePolicyEditExtensionComponentProps } from '../../../../types'; import { SetupType } from '../../../../types'; import { sendGetAgentStatus, - sendGetOneAgentPolicy, useConfig, useGetPackageInfoByKeyQuery, useUIExtension, @@ -68,7 +62,7 @@ import { import { generateNewAgentPolicyWithDefaults } from '../../../../../../../common/services/generate_new_agent_policy'; import { CreatePackagePolicySinglePageLayout, PostInstallAddAgentModal } from './components'; -import { useDevToolsRequest, useOnSubmit } from './hooks'; +import { useDevToolsRequest, useOnSubmit, useSetupType } from './hooks'; import { PostInstallCloudFormationModal } from './components/post_install_cloud_formation_modal'; import { PostInstallGoogleCloudShellModal } from './components/post_install_google_cloud_shell_modal'; import { PostInstallAzureArmTemplateModal } from './components/post_install_azure_arm_template_modal'; @@ -96,7 +90,6 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ }) => { const { agents: { enabled: isFleetEnabled }, - enableExperimental, } = useConfig(); const { params } = useRouteMatch(); @@ -303,52 +296,12 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ ); } - const isAgentlessEnabled = enableExperimental?.includes(AGENTLESS_FEATURE_FLAG) ?? false; - const [selectedSetupType, setSelectedSetupType] = useState(SetupType.AGENT_BASED); - const [agentlessPolicy, setAgentlessPolicy] = useState(); - - useEffect(() => { - const fetchAgentlessPolicy = async () => { - const { data, error } = await sendGetOneAgentPolicy(AGENTLESS_POLICY_ID); - const isAgentlessAvailable = !error && data && data.item; - - if (isAgentlessAvailable) { - setAgentlessPolicy(data.item); - } - }; - - if (isAgentlessEnabled) { - fetchAgentlessPolicy(); - } - }, [isAgentlessEnabled]); - - const handleSetupTypeChange = useCallback( - (setupType) => { - if (!isAgentlessEnabled || setupType === selectedSetupType) { - return; - } - - if (setupType === SetupType.AGENTLESS) { - if (agentlessPolicy) { - updateAgentPolicy(agentlessPolicy); - setSelectedPolicyTab(SelectedPolicyTab.EXISTING); - } - } else if (setupType === SetupType.AGENT_BASED) { - updateNewAgentPolicy(newAgentPolicy); - setSelectedPolicyTab(SelectedPolicyTab.NEW); - } - - setSelectedSetupType(setupType); - }, - [ - isAgentlessEnabled, - selectedSetupType, - agentlessPolicy, - updateAgentPolicy, - updateNewAgentPolicy, - newAgentPolicy, - ] - ); + const { agentlessPolicy, handleSetupTypeChange, selectedSetupType } = useSetupType({ + newAgentPolicy, + updateNewAgentPolicy, + updateAgentPolicy, + setSelectedPolicyTab, + }); const replaceStepConfigurePackagePolicy = replaceDefineStepView && packageInfo?.name ? ( From 102e93ae08a8b975d6c23c29283a5e9eab13f816 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Wed, 22 Nov 2023 15:56:56 +0100 Subject: [PATCH 06/33] rename 'setup type' to 'setup technology' --- .../fleet_extensions/policy_template_form.tsx | 54 +++++++++---------- .../plugins/fleet/common/constants/index.ts | 1 - .../fleet/common/constants/setup_type.ts | 8 --- x-pack/plugins/fleet/common/index.ts | 2 - .../fleet/common/types/models/index.ts | 2 +- .../{setup_type.ts => setup_technology.ts} | 2 +- .../single_page_layout/hooks/index.tsx | 2 +- .../{setup_type.ts => setup_technology.ts} | 29 +++++----- .../single_page_layout/index.tsx | 21 ++++---- x-pack/plugins/fleet/public/index.ts | 2 +- x-pack/plugins/fleet/public/types/index.ts | 2 +- .../fleet/public/types/ui_extensions.ts | 2 +- 12 files changed, 60 insertions(+), 67 deletions(-) delete mode 100644 x-pack/plugins/fleet/common/constants/setup_type.ts rename x-pack/plugins/fleet/common/types/models/{setup_type.ts => setup_technology.ts} (91%) rename x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/{setup_type.ts => setup_technology.ts} (73%) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 6f0ab800863af..677252bf991c9 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -25,7 +25,7 @@ import { useGeneratedHtmlId, } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; -import { SetupType } from '@kbn/fleet-plugin/public'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import type { NewPackagePolicyInput, @@ -511,19 +511,19 @@ const IntegrationSettings = ({ onChange, fields }: IntegrationInfoFieldsProps) = ); -const SetupTypeSelector = ({ - setupType, - onSetupTypeChange, +const SetupTechnologySelector = ({ + setupTechnology, + onSetupTechnologyChange, }: { - setupType: SetupType; - onSetupTypeChange: (value: SetupType) => void; + setupTechnology: SetupTechnology; + onSetupTechnologyChange: (value: SetupTechnology) => void; }) => { const options = [ { - value: SetupType.AGENTLESS, + value: SetupTechnology.AGENTLESS, inputDisplay: ( ), @@ -531,14 +531,14 @@ const SetupTypeSelector = ({ <>

@@ -547,10 +547,10 @@ const SetupTypeSelector = ({ ), }, { - value: SetupType.AGENT_BASED, + value: SetupTechnology.AGENT_BASED, inputDisplay: ( ), @@ -558,14 +558,14 @@ const SetupTypeSelector = ({ <>

@@ -583,7 +583,7 @@ const SetupTypeSelector = ({ buttonContent={ @@ -594,21 +594,21 @@ const SetupTypeSelector = ({ fullWidth label={ } > } - onChange={onSetupTypeChange} + onChange={onSetupTechnologyChange} itemLayoutAlign="top" hasDividers fullWidth @@ -626,7 +626,7 @@ export const CspPolicyTemplateForm = memo { const integrationParam = useParams<{ integration: CloudSecurityPolicyTemplate }>().integration; @@ -635,24 +635,24 @@ export const CspPolicyTemplateForm = memo(SetupType.AGENT_BASED); + const [setupTechnology, setSetupTechnology] = useState(SetupTechnology.AGENT_BASED); const input = getSelectedOption(newPolicy.inputs, integration); const isCspmAws = input.type === CLOUDBEAT_AWS; const isAgentlessAvailable = isCspmAws && agentlessPolicy; useEffect(() => { if (isAgentlessAvailable) { - setSetupType(SetupType.AGENTLESS); + setSetupTechnology(SetupTechnology.AGENTLESS); } else { - setSetupType(SetupType.AGENT_BASED); + setSetupTechnology(SetupTechnology.AGENT_BASED); } }, [isAgentlessAvailable]); useEffect(() => { - if (handleSetupTypeChange) { - handleSetupTypeChange(setupType); + if (handleSetupTechnologyChange) { + handleSetupTechnologyChange(setupTechnology); } - }, [handleSetupTypeChange, setupType]); + }, [handleSetupTechnologyChange, setupTechnology]); const updatePolicy = useCallback( (updatedPolicy: NewPackagePolicy) => { @@ -847,7 +847,7 @@ export const CspPolicyTemplateForm = memo {isAgentlessAvailable && ( - + )} {/* Defines the vars of the enabled input of the active policy template */} diff --git a/x-pack/plugins/fleet/common/constants/index.ts b/x-pack/plugins/fleet/common/constants/index.ts index fb1565f40fa40..ca14d612ffea3 100644 --- a/x-pack/plugins/fleet/common/constants/index.ts +++ b/x-pack/plugins/fleet/common/constants/index.ts @@ -23,7 +23,6 @@ export * from './file_storage'; export * from './message_signing_keys'; export * from './locators'; export * from './secrets'; -export * from './setup_type'; export * from './uninstall_token'; // TODO: This is the default `index.max_result_window` ES setting, which dictates diff --git a/x-pack/plugins/fleet/common/constants/setup_type.ts b/x-pack/plugins/fleet/common/constants/setup_type.ts deleted file mode 100644 index 063c0a0d01301..0000000000000 --- a/x-pack/plugins/fleet/common/constants/setup_type.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const AGENTLESS_POLICY_ID = 'agentless_cspm'; diff --git a/x-pack/plugins/fleet/common/index.ts b/x-pack/plugins/fleet/common/index.ts index dc55269fd9abe..9ac36d753c4e8 100644 --- a/x-pack/plugins/fleet/common/index.ts +++ b/x-pack/plugins/fleet/common/index.ts @@ -61,8 +61,6 @@ export { FLEET_ENROLLMENT_API_PREFIX, API_VERSIONS, APP_API_ROUTES, - SETUP_TYPE_AGENT_BASED, - SETUP_TYPE_AGENTLESS, } from './constants'; export { // Route services diff --git a/x-pack/plugins/fleet/common/types/models/index.ts b/x-pack/plugins/fleet/common/types/models/index.ts index c2ecb997f4e7d..5af1294e52657 100644 --- a/x-pack/plugins/fleet/common/types/models/index.ts +++ b/x-pack/plugins/fleet/common/types/models/index.ts @@ -19,4 +19,4 @@ export * from './download_sources'; export * from './fleet_server_policy_config'; export * from './fleet_proxy'; export * from './secret'; -export * from './setup_type'; +export * from './setup_technology'; diff --git a/x-pack/plugins/fleet/common/types/models/setup_type.ts b/x-pack/plugins/fleet/common/types/models/setup_technology.ts similarity index 91% rename from x-pack/plugins/fleet/common/types/models/setup_type.ts rename to x-pack/plugins/fleet/common/types/models/setup_technology.ts index 1fbb8b3c3daaf..66fb4a09ff9a2 100644 --- a/x-pack/plugins/fleet/common/types/models/setup_type.ts +++ b/x-pack/plugins/fleet/common/types/models/setup_technology.ts @@ -5,7 +5,7 @@ * 2.0. */ -export enum SetupType { +export enum SetupTechnology { AGENTLESS = 'agentless', AGENT_BASED = 'agent-based', } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx index ab498174d0d1b..2d8b96c562e85 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/index.tsx @@ -7,4 +7,4 @@ export { useDevToolsRequest } from './devtools_request'; export { useOnSubmit } from './form'; -export { useSetupType } from './setup_type'; +export { useSetupTechnology } from './setup_technology'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_type.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts similarity index 73% rename from x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_type.ts rename to x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts index ddda53435b75b..8c2ae69f775c4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_type.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts @@ -7,14 +7,15 @@ import { useCallback, useEffect, useState } from 'react'; -import { AGENTLESS_POLICY_ID } from '../../../../../../../../common/constants'; import { ExperimentalFeaturesService } from '../../../../../services'; import type { AgentPolicy, NewAgentPolicy } from '../../../../../types'; -import { SetupType } from '../../../../../types'; +import { SetupTechnology } from '../../../../../types'; import { sendGetOneAgentPolicy } from '../../../../../hooks'; import { SelectedPolicyTab } from '../../components'; -export function useSetupType({ +const AGENTLESS_POLICY_ID = 'agentless_cspm'; + +export function useSetupTechnology({ updateNewAgentPolicy, newAgentPolicy, updateAgentPolicy, @@ -26,7 +27,9 @@ export function useSetupType({ setSelectedPolicyTab: (tab: SelectedPolicyTab) => void; }) { const { agentless: isAgentlessEnabled } = ExperimentalFeaturesService.get(); - const [selectedSetupType, setSelectedSetupType] = useState(SetupType.AGENT_BASED); + const [selectedSetupTechnology, setSelectedSetupTechnology] = useState( + SetupTechnology.AGENT_BASED + ); const [agentlessPolicy, setAgentlessPolicy] = useState(); useEffect(() => { @@ -44,27 +47,27 @@ export function useSetupType({ } }, [isAgentlessEnabled]); - const handleSetupTypeChange = useCallback( - (setupType) => { - if (!isAgentlessEnabled || setupType === selectedSetupType) { + const handleSetupTechnologyChange = useCallback( + (setupTechnology) => { + if (!isAgentlessEnabled || setupTechnology === selectedSetupTechnology) { return; } - if (setupType === SetupType.AGENTLESS) { + if (setupTechnology === SetupTechnology.AGENTLESS) { if (agentlessPolicy) { updateAgentPolicy(agentlessPolicy); setSelectedPolicyTab(SelectedPolicyTab.EXISTING); } - } else if (setupType === SetupType.AGENT_BASED) { + } else if (setupTechnology === SetupTechnology.AGENT_BASED) { updateNewAgentPolicy(newAgentPolicy); setSelectedPolicyTab(SelectedPolicyTab.NEW); } - setSelectedSetupType(setupType); + setSelectedSetupTechnology(setupTechnology); }, [ isAgentlessEnabled, - selectedSetupType, + selectedSetupTechnology, agentlessPolicy, updateAgentPolicy, setSelectedPolicyTab, @@ -74,8 +77,8 @@ export function useSetupType({ ); return { - handleSetupTypeChange, + handleSetupTechnologyChange, agentlessPolicy, - selectedSetupType, + selectedSetupTechnology, }; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index c47b73674e880..b5e29245c63cc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -32,7 +32,7 @@ import { useCancelAddPackagePolicy } from '../hooks'; import { isRootPrivilegesRequired, splitPkgKey } from '../../../../../../../common/services'; import type { NewAgentPolicy, PackagePolicyEditExtensionComponentProps } from '../../../../types'; -import { SetupType } from '../../../../types'; +import { SetupTechnology } from '../../../../types'; import { sendGetAgentStatus, useConfig, @@ -62,7 +62,7 @@ import { import { generateNewAgentPolicyWithDefaults } from '../../../../../../../common/services/generate_new_agent_policy'; import { CreatePackagePolicySinglePageLayout, PostInstallAddAgentModal } from './components'; -import { useDevToolsRequest, useOnSubmit, useSetupType } from './hooks'; +import { useDevToolsRequest, useOnSubmit, useSetupTechnology } from './hooks'; import { PostInstallCloudFormationModal } from './components/post_install_cloud_formation_modal'; import { PostInstallGoogleCloudShellModal } from './components/post_install_google_cloud_shell_modal'; import { PostInstallAzureArmTemplateModal } from './components/post_install_azure_arm_template_modal'; @@ -296,12 +296,13 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ ); } - const { agentlessPolicy, handleSetupTypeChange, selectedSetupType } = useSetupType({ - newAgentPolicy, - updateNewAgentPolicy, - updateAgentPolicy, - setSelectedPolicyTab, - }); + const { agentlessPolicy, handleSetupTechnologyChange, selectedSetupTechnology } = + useSetupTechnology({ + newAgentPolicy, + updateNewAgentPolicy, + updateAgentPolicy, + setSelectedPolicyTab, + }); const replaceStepConfigurePackagePolicy = replaceDefineStepView && packageInfo?.name ? ( @@ -316,7 +317,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ onChange={handleExtensionViewOnChange} validationResults={validationResults} isEditPage={false} - handleSetupTypeChange={handleSetupTypeChange} + handleSetupTechnologyChange={handleSetupTechnologyChange} agentlessPolicy={agentlessPolicy} /> @@ -388,7 +389,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ }, ]; - if (selectedSetupType !== SetupType.AGENTLESS) { + if (selectedSetupTechnology !== SetupTechnology.AGENTLESS) { steps.push({ title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { defaultMessage: 'Where to add this integration?', diff --git a/x-pack/plugins/fleet/public/index.ts b/x-pack/plugins/fleet/public/index.ts index d439b0b8e3134..1efc18a53e1e8 100644 --- a/x-pack/plugins/fleet/public/index.ts +++ b/x-pack/plugins/fleet/public/index.ts @@ -16,7 +16,7 @@ export const plugin = (initializerContext: PluginInitializerContext) => { }; export type { NewPackagePolicy, KibanaSavedObjectType } from './types'; -export { SetupType } from './types'; +export { SetupTechnology } from './types'; export type { AgentDetailsReassignPolicyAction, AgentPolicyDetailsDeployAgentAction, diff --git a/x-pack/plugins/fleet/public/types/index.ts b/x-pack/plugins/fleet/public/types/index.ts index f4fc1110fd8fd..fe1c49af887d9 100644 --- a/x-pack/plugins/fleet/public/types/index.ts +++ b/x-pack/plugins/fleet/public/types/index.ts @@ -144,7 +144,7 @@ export { ElasticsearchAssetType, KibanaAssetType, InstallStatus, - SetupType, + SetupTechnology, } from '../../common/types'; export * from './intra_app_route_state'; diff --git a/x-pack/plugins/fleet/public/types/ui_extensions.ts b/x-pack/plugins/fleet/public/types/ui_extensions.ts index 6b7e71827937f..b5ae9dacf54bc 100644 --- a/x-pack/plugins/fleet/public/types/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/types/ui_extensions.ts @@ -37,7 +37,7 @@ export type PackagePolicyReplaceDefineStepExtensionComponentProps = ( agentPolicy?: AgentPolicy; packageInfo: PackageInfo; agentlessPolicy?: AgentPolicy; - handleSetupTypeChange?: (setupType: string) => void; + handleSetupTechnologyChange?: (setupTechnology: string) => void; }; /** From dac9aacfd0846adf44976f85dac62e51955e5c03 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Wed, 22 Nov 2023 16:02:47 +0100 Subject: [PATCH 07/33] move selector component to a separate file --- .../fleet_extensions/policy_template_form.tsx | 122 ++--------------- .../setup_technology_selector.tsx | 128 ++++++++++++++++++ 2 files changed, 136 insertions(+), 114 deletions(-) create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 677252bf991c9..fbe78b153bd09 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -10,19 +10,15 @@ import semverValid from 'semver/functions/valid'; import semverCoerce from 'semver/functions/coerce'; import semverLt from 'semver/functions/lt'; import { - EuiAccordion, EuiCallOut, EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, - EuiLink, EuiLoadingSpinner, EuiSpacer, - EuiSuperSelect, EuiText, EuiTitle, - useGeneratedHtmlId, } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; import { SetupTechnology } from '@kbn/fleet-plugin/public'; @@ -62,6 +58,7 @@ import { } from './policy_template_selectors'; import { usePackagePolicyList } from '../../common/api/use_package_policy_list'; import { gcpField, getInputVarsFields } from './gcp_credential_form'; +import { SetupTechnologySelector } from './setup_technology_selector'; const DEFAULT_INPUT_TYPE = { kspm: CLOUDBEAT_VANILLA, @@ -511,114 +508,6 @@ const IntegrationSettings = ({ onChange, fields }: IntegrationInfoFieldsProps) = ); -const SetupTechnologySelector = ({ - setupTechnology, - onSetupTechnologyChange, -}: { - setupTechnology: SetupTechnology; - onSetupTechnologyChange: (value: SetupTechnology) => void; -}) => { - const options = [ - { - value: SetupTechnology.AGENTLESS, - inputDisplay: ( - - ), - dropdownDisplay: ( - <> - - - - -

- -

-
- - ), - }, - { - value: SetupTechnology.AGENT_BASED, - inputDisplay: ( - - ), - dropdownDisplay: ( - <> - - - - -

- -

-
- - ), - }, - ]; - - return ( - <> - - - - - } - > - - - } - > - - } - onChange={onSetupTechnologyChange} - itemLayoutAlign="top" - hasDividers - fullWidth - /> - - - - ); -}; - export const CspPolicyTemplateForm = memo( ({ newPolicy, @@ -635,7 +524,9 @@ export const CspPolicyTemplateForm = memo(SetupTechnology.AGENT_BASED); + const [setupTechnology, setSetupTechnology] = useState( + SetupTechnology.AGENT_BASED + ); const input = getSelectedOption(newPolicy.inputs, integration); const isCspmAws = input.type === CLOUDBEAT_AWS; const isAgentlessAvailable = isCspmAws && agentlessPolicy; @@ -847,7 +738,10 @@ export const CspPolicyTemplateForm = memo {isAgentlessAvailable && ( - + )} {/* Defines the vars of the enabled input of the active policy template */} diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx new file mode 100644 index 0000000000000..e1a3579bfac6b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { SetupTechnology } from '@kbn/fleet-plugin/common/types'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + EuiAccordion, + EuiFormRow, + EuiLink, + EuiSpacer, + EuiSuperSelect, + EuiText, + useGeneratedHtmlId, +} from '@elastic/eui'; + +export const SetupTechnologySelector = ({ + setupTechnology, + onSetupTechnologyChange, +}: { + setupTechnology: SetupTechnology; + onSetupTechnologyChange: (value: SetupTechnology) => void; +}) => { + const options = [ + { + value: SetupTechnology.AGENTLESS, + inputDisplay: ( + + ), + dropdownDisplay: ( + <> + + + + +

+ +

+
+ + ), + }, + { + value: SetupTechnology.AGENT_BASED, + inputDisplay: ( + + ), + dropdownDisplay: ( + <> + + + + +

+ +

+
+ + ), + }, + ]; + + return ( + <> + + + + + } + > + + + } + > + + } + onChange={onSetupTechnologyChange} + itemLayoutAlign="top" + hasDividers + fullWidth + /> + + + + ); +}; From 5865d388732889ba9db460e58d497f2d0577300a Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Wed, 22 Nov 2023 16:17:28 +0100 Subject: [PATCH 08/33] move setup technology logic to a custom hook --- .../fleet_extensions/policy_template_form.tsx | 27 +++-------- .../setup_technology_selector.tsx | 45 ++++++++++++++++++- 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index fbe78b153bd09..71cadb9c71446 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -21,7 +21,6 @@ import { EuiTitle, } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; -import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import type { NewPackagePolicyInput, @@ -58,7 +57,7 @@ import { } from './policy_template_selectors'; import { usePackagePolicyList } from '../../common/api/use_package_policy_list'; import { gcpField, getInputVarsFields } from './gcp_credential_form'; -import { SetupTechnologySelector } from './setup_technology_selector'; +import { SetupTechnologySelector, useSetupTechnology } from './setup_technology_selector'; const DEFAULT_INPUT_TYPE = { kspm: CLOUDBEAT_VANILLA, @@ -524,26 +523,12 @@ export const CspPolicyTemplateForm = memo( - SetupTechnology.AGENT_BASED - ); const input = getSelectedOption(newPolicy.inputs, integration); - const isCspmAws = input.type === CLOUDBEAT_AWS; - const isAgentlessAvailable = isCspmAws && agentlessPolicy; - - useEffect(() => { - if (isAgentlessAvailable) { - setSetupTechnology(SetupTechnology.AGENTLESS); - } else { - setSetupTechnology(SetupTechnology.AGENT_BASED); - } - }, [isAgentlessAvailable]); - - useEffect(() => { - if (handleSetupTechnologyChange) { - handleSetupTechnologyChange(setupTechnology); - } - }, [handleSetupTechnologyChange, setupTechnology]); + const { isAgentlessAvailable, setupTechnology, setSetupTechnology } = useSetupTechnology({ + input, + agentlessPolicy, + handleSetupTechnologyChange, + }); const updatePolicy = useCallback( (updatedPolicy: NewPackagePolicy) => { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx index e1a3579bfac6b..13a6df1cf78de 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx @@ -5,9 +5,13 @@ * 2.0. */ -import React from 'react'; +import React, { useEffect, useState } from 'react'; -import { SetupTechnology } from '@kbn/fleet-plugin/common/types'; +import { + AgentPolicy, + SetupTechnology, + NewPackagePolicyInput, +} from '@kbn/fleet-plugin/common/types'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiAccordion, @@ -18,6 +22,43 @@ import { EuiText, useGeneratedHtmlId, } from '@elastic/eui'; +import { CLOUDBEAT_AWS } from '../../../common/constants'; + +export const useSetupTechnology = ({ + input, + agentlessPolicy, + handleSetupTechnologyChange, +}: { + input: NewPackagePolicyInput; + agentlessPolicy?: AgentPolicy; + handleSetupTechnologyChange?: (value: SetupTechnology) => void; +}) => { + const [setupTechnology, setSetupTechnology] = useState( + SetupTechnology.AGENT_BASED + ); + const isCspmAws = input.type === CLOUDBEAT_AWS; + const isAgentlessAvailable = isCspmAws && agentlessPolicy; + + useEffect(() => { + if (isAgentlessAvailable) { + setSetupTechnology(SetupTechnology.AGENTLESS); + } else { + setSetupTechnology(SetupTechnology.AGENT_BASED); + } + }, [isAgentlessAvailable]); + + useEffect(() => { + if (handleSetupTechnologyChange) { + handleSetupTechnologyChange(setupTechnology); + } + }, [handleSetupTechnologyChange, setupTechnology]); + + return { + isAgentlessAvailable, + setupTechnology, + setSetupTechnology, + }; +}; export const SetupTechnologySelector = ({ setupTechnology, From 1eee8249b4f1da0e4030e86554fb320970d0e459 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Thu, 23 Nov 2023 14:04:32 +0100 Subject: [PATCH 09/33] fix imports from fleet-plugin --- .../fleet_extensions/setup_technology_selector.tsx | 7 ++----- x-pack/plugins/fleet/public/index.ts | 7 ++++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx index 13a6df1cf78de..54633008b49b2 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx @@ -7,11 +7,8 @@ import React, { useEffect, useState } from 'react'; -import { - AgentPolicy, - SetupTechnology, - NewPackagePolicyInput, -} from '@kbn/fleet-plugin/common/types'; +import type { AgentPolicy, NewPackagePolicyInput } from '@kbn/fleet-plugin/public'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiAccordion, diff --git a/x-pack/plugins/fleet/public/index.ts b/x-pack/plugins/fleet/public/index.ts index 1efc18a53e1e8..585495f14eebc 100644 --- a/x-pack/plugins/fleet/public/index.ts +++ b/x-pack/plugins/fleet/public/index.ts @@ -15,7 +15,12 @@ export const plugin = (initializerContext: PluginInitializerContext) => { return new FleetPlugin(initializerContext); }; -export type { NewPackagePolicy, KibanaSavedObjectType } from './types'; +export type { + NewPackagePolicy, + KibanaSavedObjectType, + AgentPolicy, + NewPackagePolicyInput, +} from './types'; export { SetupTechnology } from './types'; export type { AgentDetailsReassignPolicyAction, From 5bbb7712f69aa48c23cc2239992f97e830671a3c Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Thu, 23 Nov 2023 14:19:07 +0100 Subject: [PATCH 10/33] memoize isAgentlessAvailable --- .../fleet_extensions/setup_technology_selector.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx index 54633008b49b2..de17a3f1a5e7d 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import type { AgentPolicy, NewPackagePolicyInput } from '@kbn/fleet-plugin/public'; import { SetupTechnology } from '@kbn/fleet-plugin/public'; @@ -34,7 +34,10 @@ export const useSetupTechnology = ({ SetupTechnology.AGENT_BASED ); const isCspmAws = input.type === CLOUDBEAT_AWS; - const isAgentlessAvailable = isCspmAws && agentlessPolicy; + const isAgentlessAvailable = useMemo( + () => Boolean(isCspmAws && agentlessPolicy), + [isCspmAws, agentlessPolicy] + ); useEffect(() => { if (isAgentlessAvailable) { From ada79558b3d11588633cb2fd0ece7ac6bed9660a Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Thu, 23 Nov 2023 14:31:28 +0100 Subject: [PATCH 11/33] move useSetupTechnology hook out --- .../fleet_extensions/policy_template_form.tsx | 5 +- .../setup_technology_selector.tsx | 43 +--------------- .../use_setup_technology.ts | 50 +++++++++++++++++++ x-pack/plugins/fleet/public/index.ts | 7 +-- 4 files changed, 56 insertions(+), 49 deletions(-) rename x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/{ => setup_technology_selector}/setup_technology_selector.tsx (74%) create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 71cadb9c71446..413ae9b3adba8 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -57,7 +57,10 @@ import { } from './policy_template_selectors'; import { usePackagePolicyList } from '../../common/api/use_package_policy_list'; import { gcpField, getInputVarsFields } from './gcp_credential_form'; -import { SetupTechnologySelector, useSetupTechnology } from './setup_technology_selector'; +import { SetupTechnologySelector } from './setup_technology_selector/setup_technology_selector'; +import { + useSetupTechnology +} from './setup_technology_selector/use_setup_technology'; const DEFAULT_INPUT_TYPE = { kspm: CLOUDBEAT_VANILLA, diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx similarity index 74% rename from x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx rename to x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx index de17a3f1a5e7d..c3b6572281da3 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import React, { useEffect, useMemo, useState } from 'react'; +import React from 'react'; -import type { AgentPolicy, NewPackagePolicyInput } from '@kbn/fleet-plugin/public'; import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { @@ -19,46 +18,6 @@ import { EuiText, useGeneratedHtmlId, } from '@elastic/eui'; -import { CLOUDBEAT_AWS } from '../../../common/constants'; - -export const useSetupTechnology = ({ - input, - agentlessPolicy, - handleSetupTechnologyChange, -}: { - input: NewPackagePolicyInput; - agentlessPolicy?: AgentPolicy; - handleSetupTechnologyChange?: (value: SetupTechnology) => void; -}) => { - const [setupTechnology, setSetupTechnology] = useState( - SetupTechnology.AGENT_BASED - ); - const isCspmAws = input.type === CLOUDBEAT_AWS; - const isAgentlessAvailable = useMemo( - () => Boolean(isCspmAws && agentlessPolicy), - [isCspmAws, agentlessPolicy] - ); - - useEffect(() => { - if (isAgentlessAvailable) { - setSetupTechnology(SetupTechnology.AGENTLESS); - } else { - setSetupTechnology(SetupTechnology.AGENT_BASED); - } - }, [isAgentlessAvailable]); - - useEffect(() => { - if (handleSetupTechnologyChange) { - handleSetupTechnologyChange(setupTechnology); - } - }, [handleSetupTechnologyChange, setupTechnology]); - - return { - isAgentlessAvailable, - setupTechnology, - setSetupTechnology, - }; -}; export const SetupTechnologySelector = ({ setupTechnology, diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts new file mode 100644 index 0000000000000..1795b67a9b9a9 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { useEffect, useMemo, useState } from 'react'; + +import { AgentPolicy, NewPackagePolicyInput } from '@kbn/fleet-plugin/common'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; +import { CLOUDBEAT_AWS } from '../../../../common/constants'; + +export const useSetupTechnology = ({ + input, + agentlessPolicy, + handleSetupTechnologyChange, +}: { + input: NewPackagePolicyInput; + agentlessPolicy?: AgentPolicy; + handleSetupTechnologyChange?: (value: SetupTechnology) => void; +}) => { + const [setupTechnology, setSetupTechnology] = useState( + SetupTechnology.AGENT_BASED + ); + const isCspmAws = input.type === CLOUDBEAT_AWS; + const isAgentlessAvailable = useMemo( + () => Boolean(isCspmAws && agentlessPolicy), + [isCspmAws, agentlessPolicy] + ); + + useEffect(() => { + if (isAgentlessAvailable) { + setSetupTechnology(SetupTechnology.AGENTLESS); + } else { + setSetupTechnology(SetupTechnology.AGENT_BASED); + } + }, [isAgentlessAvailable]); + + useEffect(() => { + if (handleSetupTechnologyChange) { + handleSetupTechnologyChange(setupTechnology); + } + }, [handleSetupTechnologyChange, setupTechnology]); + + return { + isAgentlessAvailable, + setupTechnology, + setSetupTechnology, + }; +}; diff --git a/x-pack/plugins/fleet/public/index.ts b/x-pack/plugins/fleet/public/index.ts index 585495f14eebc..1efc18a53e1e8 100644 --- a/x-pack/plugins/fleet/public/index.ts +++ b/x-pack/plugins/fleet/public/index.ts @@ -15,12 +15,7 @@ export const plugin = (initializerContext: PluginInitializerContext) => { return new FleetPlugin(initializerContext); }; -export type { - NewPackagePolicy, - KibanaSavedObjectType, - AgentPolicy, - NewPackagePolicyInput, -} from './types'; +export type { NewPackagePolicy, KibanaSavedObjectType } from './types'; export { SetupTechnology } from './types'; export type { AgentDetailsReassignPolicyAction, From 1716fc8ccefb5b5ad098568803704d91dc81543b Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:34:27 +0000 Subject: [PATCH 12/33] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../components/fleet_extensions/policy_template_form.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 413ae9b3adba8..7959eea46efc1 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -58,9 +58,7 @@ import { import { usePackagePolicyList } from '../../common/api/use_package_policy_list'; import { gcpField, getInputVarsFields } from './gcp_credential_form'; import { SetupTechnologySelector } from './setup_technology_selector/setup_technology_selector'; -import { - useSetupTechnology -} from './setup_technology_selector/use_setup_technology'; +import { useSetupTechnology } from './setup_technology_selector/use_setup_technology'; const DEFAULT_INPUT_TYPE = { kspm: CLOUDBEAT_VANILLA, From db5d71c89cce8ffd7472f08be6f385c98d6b970c Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Thu, 23 Nov 2023 18:47:40 +0100 Subject: [PATCH 13/33] handle case of coming from a specific agent policy --- .../fleet_extensions/policy_template_form.tsx | 2 ++ .../use_setup_technology.ts | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 7959eea46efc1..c8a62d3c9a9fe 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -510,6 +510,7 @@ const IntegrationSettings = ({ onChange, fields }: IntegrationInfoFieldsProps) = export const CspPolicyTemplateForm = memo( ({ + agentPolicy, newPolicy, onChange, validationResults, @@ -527,6 +528,7 @@ export const CspPolicyTemplateForm = memo void; }) => { @@ -27,7 +29,23 @@ export const useSetupTechnology = ({ () => Boolean(isCspmAws && agentlessPolicy), [isCspmAws, agentlessPolicy] ); + const agentPolicyId = useMemo(() => agentPolicy?.id, [agentPolicy]); + const agentlessPolicyId = useMemo(() => agentlessPolicy?.id, [agentlessPolicy]); + /* + handle case when agent policy is coming from outside, + e.g. from the get param or when coming to integration from a specific agent policy + */ + useEffect(() => { + if (agentPolicyId && agentPolicyId !== agentlessPolicyId) { + setSetupTechnology(SetupTechnology.AGENT_BASED); + } + }, [agentPolicyId, agentlessPolicyId]); + + /* + preselecting agenteless when available + and resetting to agent-based when switching to another integration type, which doesn't support agentless + */ useEffect(() => { if (isAgentlessAvailable) { setSetupTechnology(SetupTechnology.AGENTLESS); From 79715dd99910b8c3597916cd2b080d61e5d59257 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 24 Nov 2023 12:50:40 +0100 Subject: [PATCH 14/33] add tests for useSetupTechnology hook --- .../hooks/setup_technology.test.ts | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts new file mode 100644 index 0000000000000..5aa8ad0cad259 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts @@ -0,0 +1,177 @@ +/* + * 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 { renderHook, act } from '@testing-library/react-hooks'; + +import { SetupTechnology } from '../../../../../../../../common/types'; +import { ExperimentalFeaturesService } from '../../../../../services'; +import { sendGetOneAgentPolicy } from '../../../../../hooks'; +import { SelectedPolicyTab } from '../../components'; + +import { useSetupTechnology } from './setup_technology'; + +jest.mock('../../../../../services'); +jest.mock('../../../../../hooks', () => ({ + ...jest.requireActual('../../../../../hooks'), + sendGetOneAgentPolicy: jest.fn(), +})); + +type MockFn = jest.MockedFunction; + +describe('useSetupTechnology', () => { + const updateNewAgentPolicyMock = jest.fn(); + const updateAgentPolicyMock = jest.fn(); + const setSelectedPolicyTabMock = jest.fn(); + const newAgentPolicyMock = { + name: 'mock_new_agent_policy', + namespace: 'default', + }; + const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService); + + beforeEach(() => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + agentless: true, + } as any); + (sendGetOneAgentPolicy as MockFn).mockResolvedValue({ + data: { + item: { id: 'agentless-policy-id' }, + }, + }); + jest.clearAllMocks(); + }); + + it('should initialize with default values when agentless is disabled', () => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + agentless: false, + } as any); + + const { result } = renderHook(() => + useSetupTechnology({ + updateNewAgentPolicy: updateNewAgentPolicyMock, + newAgentPolicy: newAgentPolicyMock, + updateAgentPolicy: updateAgentPolicyMock, + setSelectedPolicyTab: setSelectedPolicyTabMock, + }) + ); + + expect(sendGetOneAgentPolicy).not.toHaveBeenCalled(); + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + expect(result.current.agentlessPolicy).toBeUndefined(); + }); + + it('should fetch agentless policy if agentless is enabled', async () => { + const { result, waitForNextUpdate } = renderHook(() => + useSetupTechnology({ + updateNewAgentPolicy: updateNewAgentPolicyMock, + newAgentPolicy: newAgentPolicyMock, + updateAgentPolicy: updateAgentPolicyMock, + setSelectedPolicyTab: setSelectedPolicyTabMock, + }) + ); + + await waitForNextUpdate(); + + expect(result.current.agentlessPolicy).toEqual({ id: 'agentless-policy-id' }); + }); + + it('should update agent policy and selected policy tab when setup technology is agentless', async () => { + const { result, waitForNextUpdate } = renderHook(() => + useSetupTechnology({ + updateNewAgentPolicy: updateNewAgentPolicyMock, + newAgentPolicy: newAgentPolicyMock, + updateAgentPolicy: updateAgentPolicyMock, + setSelectedPolicyTab: setSelectedPolicyTabMock, + }) + ); + + await waitForNextUpdate(); + + act(() => { + result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS); + }); + + expect(updateAgentPolicyMock).toHaveBeenCalledWith({ id: 'agentless-policy-id' }); + expect(setSelectedPolicyTabMock).toHaveBeenCalledWith(SelectedPolicyTab.EXISTING); + }); + + it('should update new agent policy and selected policy tab when setup technology is agent-based', async () => { + const { result, waitForNextUpdate } = renderHook(() => + useSetupTechnology({ + updateNewAgentPolicy: updateNewAgentPolicyMock, + newAgentPolicy: newAgentPolicyMock, + updateAgentPolicy: updateAgentPolicyMock, + setSelectedPolicyTab: setSelectedPolicyTabMock, + }) + ); + + await waitForNextUpdate(); + + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + + act(() => { + result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS); + }); + + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); + + act(() => { + result.current.handleSetupTechnologyChange(SetupTechnology.AGENT_BASED); + }); + + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + + expect(updateNewAgentPolicyMock).toHaveBeenCalledWith(newAgentPolicyMock); + expect(setSelectedPolicyTabMock).toHaveBeenCalledWith(SelectedPolicyTab.NEW); + }); + + it('should not update agent policy and selected policy tab when agentless is disabled', async () => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + agentless: false, + } as any); + + const { result } = renderHook(() => + useSetupTechnology({ + updateNewAgentPolicy: updateNewAgentPolicyMock, + newAgentPolicy: newAgentPolicyMock, + updateAgentPolicy: updateAgentPolicyMock, + setSelectedPolicyTab: setSelectedPolicyTabMock, + }) + ); + + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + + act(() => { + result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS); + }); + + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + }); + + it('should not update agent policy and selected policy tab when setup technology matches the current one ', async () => { + const { result, waitForNextUpdate } = renderHook(() => + useSetupTechnology({ + updateNewAgentPolicy: updateNewAgentPolicyMock, + newAgentPolicy: newAgentPolicyMock, + updateAgentPolicy: updateAgentPolicyMock, + setSelectedPolicyTab: setSelectedPolicyTabMock, + }) + ); + + await waitForNextUpdate(); + + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + + act(() => { + result.current.handleSetupTechnologyChange(SetupTechnology.AGENT_BASED); + }); + + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + + expect(updateNewAgentPolicyMock).not.toHaveBeenCalled(); + expect(setSelectedPolicyTabMock).not.toHaveBeenCalled(); + }); +}); From 771139ae6502a2b33d831a696e6d28216779218c Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 24 Nov 2023 16:08:26 +0100 Subject: [PATCH 15/33] add unit tests to useSetupTechnology in csp --- .../use_setup_technology.test.ts | 59 +++++++++++++++++++ .../use_setup_technology.ts | 24 ++++---- 2 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts new file mode 100644 index 0000000000000..a5aa5e2df9734 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts @@ -0,0 +1,59 @@ +/* + * 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 { renderHook, act } from '@testing-library/react-hooks'; + +import { SetupTechnology } from '@kbn/fleet-plugin/public'; +import { AgentPolicy, NewPackagePolicyInput } from '@kbn/fleet-plugin/common'; + +import { CLOUDBEAT_AWS } from '../../../../common/constants'; +import { useSetupTechnology } from './use_setup_technology'; + +describe('useSetupTechnology', () => { + it('initializes with AGENT_BASED technology', () => { + const { result } = renderHook(() => + useSetupTechnology({ + input: { type: 'cloudbeat/no-agentless-support' } as NewPackagePolicyInput, + }) + ); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); + }); + + it('sets to AGENTLESS when agentless is available', () => { + const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; + const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; + const { result } = renderHook(() => useSetupTechnology({ input, agentlessPolicy })); + expect(result.current.isAgentlessAvailable).toBeTruthy(); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENTLESS); + }); + + it('sets to AGENT_BASED when agentPolicyId differs from agentlessPolicyId', () => { + const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; + const agentPolicy = { id: 'agentPolicyId' } as AgentPolicy; + const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; + const { result } = renderHook(() => + useSetupTechnology({ input, agentPolicy, agentlessPolicy }) + ); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); + }); + + it('calls handleSetupTechnologyChange when setupTechnology changes', () => { + const handleSetupTechnologyChangeMock = jest.fn(); + const { result } = renderHook(() => + useSetupTechnology({ + input: { type: 'someType' } as NewPackagePolicyInput, + handleSetupTechnologyChange: handleSetupTechnologyChangeMock, + }) + ); + + act(() => { + result.current.setSetupTechnology(SetupTechnology.AGENTLESS); + }); + + expect(handleSetupTechnologyChangeMock).toHaveBeenCalledWith(SetupTechnology.AGENTLESS); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts index 5b3c7fa981b62..898017d6daef5 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts @@ -32,27 +32,23 @@ export const useSetupTechnology = ({ const agentPolicyId = useMemo(() => agentPolicy?.id, [agentPolicy]); const agentlessPolicyId = useMemo(() => agentlessPolicy?.id, [agentlessPolicy]); - /* - handle case when agent policy is coming from outside, - e.g. from the get param or when coming to integration from a specific agent policy - */ useEffect(() => { if (agentPolicyId && agentPolicyId !== agentlessPolicyId) { + /* + handle case when agent policy is coming from outside, + e.g. from the get param or when coming to integration from a specific agent policy + */ setSetupTechnology(SetupTechnology.AGENT_BASED); - } - }, [agentPolicyId, agentlessPolicyId]); - - /* - preselecting agenteless when available - and resetting to agent-based when switching to another integration type, which doesn't support agentless - */ - useEffect(() => { - if (isAgentlessAvailable) { + } else if (isAgentlessAvailable) { + /* + preselecting agenteless when available + and resetting to agent-based when switching to another integration type, which doesn't support agentless + */ setSetupTechnology(SetupTechnology.AGENTLESS); } else { setSetupTechnology(SetupTechnology.AGENT_BASED); } - }, [isAgentlessAvailable]); + }, [agentPolicyId, agentlessPolicyId, isAgentlessAvailable]); useEffect(() => { if (handleSetupTechnologyChange) { From 528d472d431e1185adc13224413a9e87c6a37f29 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 24 Nov 2023 16:55:13 +0100 Subject: [PATCH 16/33] switch feature flag to test on serverless --- x-pack/plugins/fleet/common/experimental_features.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/common/experimental_features.ts b/x-pack/plugins/fleet/common/experimental_features.ts index c8f12d394b6b4..aa865e1c73aa3 100644 --- a/x-pack/plugins/fleet/common/experimental_features.ts +++ b/x-pack/plugins/fleet/common/experimental_features.ts @@ -25,7 +25,7 @@ export const allowedExperimentalValues = Object.freeze>( kafkaOutput: true, outputSecretsStorage: false, remoteESOutput: false, - agentless: false, + agentless: true, }); type ExperimentalConfigKeys = Array; From 422f360d5a11de30d885e841cb4646c2af322036 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 24 Nov 2023 18:30:53 +0100 Subject: [PATCH 17/33] update agentless policy id --- .../single_page_layout/hooks/setup_technology.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts index 8c2ae69f775c4..51fd522157d8b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts @@ -13,7 +13,7 @@ import { SetupTechnology } from '../../../../../types'; import { sendGetOneAgentPolicy } from '../../../../../hooks'; import { SelectedPolicyTab } from '../../components'; -const AGENTLESS_POLICY_ID = 'agentless_cspm'; +const AGENTLESS_POLICY_ID = 'agentless'; export function useSetupTechnology({ updateNewAgentPolicy, From 8975fd00eacea5208c798cd4a6b68d816ba3188c Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Mon, 27 Nov 2023 13:17:10 +0100 Subject: [PATCH 18/33] default to false for agentless settings --- x-pack/plugins/fleet/common/experimental_features.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/common/experimental_features.ts b/x-pack/plugins/fleet/common/experimental_features.ts index aa865e1c73aa3..c8f12d394b6b4 100644 --- a/x-pack/plugins/fleet/common/experimental_features.ts +++ b/x-pack/plugins/fleet/common/experimental_features.ts @@ -25,7 +25,7 @@ export const allowedExperimentalValues = Object.freeze>( kafkaOutput: true, outputSecretsStorage: false, remoteESOutput: false, - agentless: true, + agentless: false, }); type ExperimentalConfigKeys = Array; From 8b26fbd15bde16fa3502ff14c9d36dccbf5a5719 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Wed, 29 Nov 2023 11:49:48 +0100 Subject: [PATCH 19/33] fetch agentless policy only in serverless --- .../hooks/setup_technology.test.ts | 29 ++++++++++++++++++- .../hooks/setup_technology.ts | 8 +++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts index 5aa8ad0cad259..dd2a1dcc81c79 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts @@ -9,7 +9,7 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { SetupTechnology } from '../../../../../../../../common/types'; import { ExperimentalFeaturesService } from '../../../../../services'; -import { sendGetOneAgentPolicy } from '../../../../../hooks'; +import { sendGetOneAgentPolicy, useStartServices } from '../../../../../hooks'; import { SelectedPolicyTab } from '../../components'; import { useSetupTechnology } from './setup_technology'; @@ -18,6 +18,7 @@ jest.mock('../../../../../services'); jest.mock('../../../../../hooks', () => ({ ...jest.requireActual('../../../../../hooks'), sendGetOneAgentPolicy: jest.fn(), + useStartServices: jest.fn(), })); type MockFn = jest.MockedFunction; @@ -41,6 +42,11 @@ describe('useSetupTechnology', () => { item: { id: 'agentless-policy-id' }, }, }); + (useStartServices as MockFn).mockReturnValue({ + cloud: { + isServerlessEnabled: true, + }, + }); jest.clearAllMocks(); }); @@ -78,6 +84,27 @@ describe('useSetupTechnology', () => { expect(result.current.agentlessPolicy).toEqual({ id: 'agentless-policy-id' }); }); + it('should not fetch agentless policy if agentless is enabled but serverless is disabled', async () => { + (useStartServices as MockFn).mockReturnValue({ + cloud: { + isServerlessEnabled: false, + }, + }); + + const { result } = renderHook(() => + useSetupTechnology({ + updateNewAgentPolicy: updateNewAgentPolicyMock, + newAgentPolicy: newAgentPolicyMock, + updateAgentPolicy: updateAgentPolicyMock, + setSelectedPolicyTab: setSelectedPolicyTabMock, + }) + ); + + expect(sendGetOneAgentPolicy).not.toHaveBeenCalled(); + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + expect(result.current.agentlessPolicy).toBeUndefined(); + }); + it('should update agent policy and selected policy tab when setup technology is agentless', async () => { const { result, waitForNextUpdate } = renderHook(() => useSetupTechnology({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts index 51fd522157d8b..22972f4a9a6d4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts @@ -10,7 +10,7 @@ import { useCallback, useEffect, useState } from 'react'; import { ExperimentalFeaturesService } from '../../../../../services'; import type { AgentPolicy, NewAgentPolicy } from '../../../../../types'; import { SetupTechnology } from '../../../../../types'; -import { sendGetOneAgentPolicy } from '../../../../../hooks'; +import { sendGetOneAgentPolicy, useStartServices } from '../../../../../hooks'; import { SelectedPolicyTab } from '../../components'; const AGENTLESS_POLICY_ID = 'agentless'; @@ -27,6 +27,8 @@ export function useSetupTechnology({ setSelectedPolicyTab: (tab: SelectedPolicyTab) => void; }) { const { agentless: isAgentlessEnabled } = ExperimentalFeaturesService.get(); + const { cloud } = useStartServices(); + const isServerless = cloud?.isServerlessEnabled ?? false; const [selectedSetupTechnology, setSelectedSetupTechnology] = useState( SetupTechnology.AGENT_BASED ); @@ -42,10 +44,10 @@ export function useSetupTechnology({ } }; - if (isAgentlessEnabled) { + if (isAgentlessEnabled && isServerless) { fetchAgentlessPolicy(); } - }, [isAgentlessEnabled]); + }, [isAgentlessEnabled, isServerless]); const handleSetupTechnologyChange = useCallback( (setupTechnology) => { From c7a02794da21430338065f987ae0f16e0760127e Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 1 Dec 2023 18:41:00 +0100 Subject: [PATCH 20/33] implement direct access keys setup method --- .../aws_credentials_form.tsx | 62 +++++-------------- .../aws_credentials_form_agentless.tsx | 60 ++++++++++++++++++ .../aws_input_var_fields.tsx | 44 +++++++++++++ .../get_aws_credentials_form_options.tsx | 1 + .../aws_credentials_form/hooks.ts | 5 +- .../fleet_extensions/eks_credentials_form.tsx | 46 +------------- .../fleet_extensions/policy_template_form.tsx | 10 ++- .../policy_template_selectors.tsx | 13 +++- .../use_setup_technology.ts | 13 ++-- .../components/fleet_extensions/utils.ts | 17 ++++- 10 files changed, 165 insertions(+), 106 deletions(-) create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_input_var_fields.tsx diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 4be4ac082f60f..7088ae53b3263 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -6,26 +6,25 @@ */ import React from 'react'; import { - EuiFieldText, - EuiFieldPassword, + EuiCallOut, EuiFormRow, + EuiHorizontalRule, EuiLink, + EuiSelect, EuiSpacer, EuiText, EuiTitle, - EuiSelect, - EuiCallOut, - EuiHorizontalRule, } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { NewPackagePolicyInput, PackageInfo } from '@kbn/fleet-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { - getAwsCredentialsFormManualOptions, - AwsOptions, + DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE, + getAwsCredentialsFormManualOptions, } from './get_aws_credentials_form_options'; import { RadioGroup } from '../csp_boxed_radio_group'; import { @@ -36,11 +35,11 @@ import { import { SetupFormat, useAwsCredentialsForm } from './hooks'; import { AWS_ORGANIZATION_ACCOUNT } from '../policy_template_form'; import { AwsCredentialsType } from '../../../../common/types'; +import { AwsInputVarFields } from './aws_input_var_fields'; interface AWSSetupInfoContentProps { integrationLink: string; } - const AWSSetupInfoContent = ({ integrationLink }: AWSSetupInfoContentProps) => { return ( <> @@ -87,7 +86,14 @@ const getSetupFormatOptions = (): Array<{ id: SetupFormat; label: string }> => [ }, ]; -export const getDefaultAwsVarsGroup = (packageInfo: PackageInfo): AwsCredentialsType => { +export const getDefaultAwsVarsGroup = ( + packageInfo: PackageInfo, + setupTechnology?: SetupTechnology +): AwsCredentialsType => { + if (setupTechnology && setupTechnology === SetupTechnology.AGENTLESS) { + return DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE; + } + const hasCloudFormationTemplate = !!getCspmCloudFormationDefaultValue(packageInfo); if (hasCloudFormationTemplate) { return 'cloud_formation'; @@ -96,7 +102,7 @@ export const getDefaultAwsVarsGroup = (packageInfo: PackageInfo): AwsCredentials return DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE; }; -interface Props { +export interface AwsFormProps { newPolicy: NewPackagePolicy; input: Extract; updatePolicy(updatedPolicy: NewPackagePolicy): void; @@ -217,7 +223,7 @@ export const AwsCredentialsForm = ({ onChange, setIsValid, disabled, -}: Props) => { +}: AwsFormProps) => { const { awsCredentialsType, setupFormat, @@ -304,37 +310,3 @@ const AwsCredentialTypeSelector = ({ />
); - -const AwsInputVarFields = ({ - fields, - onChange, -}: { - fields: Array; - onChange: (key: string, value: string) => void; -}) => ( -
- {fields.map((field) => ( - - <> - {field.type === 'password' && ( - onChange(field.id, event.target.value)} - /> - )} - {field.type === 'text' && ( - onChange(field.id, event.target.value)} - /> - )} - - - ))} -
-); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx new file mode 100644 index 0000000000000..211d02a68026e --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiHorizontalRule, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, + getAwsCredentialsFormOptions, + getInputVarsFields, +} from './get_aws_credentials_form_options'; +import { getPosturePolicy } from '../utils'; +import { AwsInputVarFields } from './aws_input_var_fields'; +import { AwsFormProps } from './aws_credentials_form'; + +const AWSSetupInfoContentAgentless = () => { + return ( + <> + + +

+ +

+
+ + + + + + ); +}; + +export const AwsCredentialsFormAgentless = ({ input, newPolicy, updatePolicy }: AwsFormProps) => { + const options = getAwsCredentialsFormOptions(); + const group = options[DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE]; + const fields = getInputVarsFields(input, group.fields); + + return ( + <> + + + { + updatePolicy(getPosturePolicy(newPolicy, input.type, { [key]: { value } })); + }} + /> + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_input_var_fields.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_input_var_fields.tsx new file mode 100644 index 0000000000000..5ac54872a583b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_input_var_fields.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFieldPassword, EuiFieldText, EuiFormRow } from '@elastic/eui'; +import { AwsOptions } from './get_aws_credentials_form_options'; + +export const AwsInputVarFields = ({ + fields, + onChange, +}: { + fields: Array; + onChange: (key: string, value: string) => void; +}) => ( +
+ {fields.map((field) => ( + + <> + {field.type === 'password' && ( + onChange(field.id, event.target.value)} + /> + )} + {field.type === 'text' && ( + onChange(field.id, event.target.value)} + /> + )} + + + ))} +
+); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx index 71882d4cc67cf..b237d9d19e68e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx @@ -106,6 +106,7 @@ export const getAwsCredentialsFormManualOptions = (): Array<{ }; export const DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE = 'assume_role'; +export const DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE = 'direct_access_keys'; export const getAwsCredentialsFormOptions = (): AwsOptions => ({ assume_role: { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts index 190ae47a61aec..b3d186e8097d5 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts @@ -12,6 +12,7 @@ import { getCspmCloudFormationDefaultValue, getPosturePolicy, NewPackagePolicyPostureInput, + getAwsCredentialsType, } from '../utils'; import { DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE, @@ -43,10 +44,6 @@ const getSetupFormatFromInput = ( return 'cloud_formation'; }; -const getAwsCredentialsType = ( - input: Extract -): AwsCredentialsType | undefined => input.streams[0].vars?.['aws.credentials.type'].value; - export const useAwsCredentialsForm = ({ newPolicy, input, diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/eks_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/eks_credentials_form.tsx index 41f4b857e13f8..fda6ae2f631fa 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/eks_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/eks_credentials_form.tsx @@ -5,22 +5,14 @@ * 2.0. */ import React from 'react'; -import { - EuiFieldText, - EuiFieldPassword, - EuiFormRow, - EuiLink, - EuiSpacer, - EuiText, - EuiTitle, - EuiHorizontalRule, -} from '@elastic/eui'; +import { EuiLink, EuiSpacer, EuiText, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; import { NewPackagePolicyInput } from '@kbn/fleet-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { RadioGroup } from './csp_boxed_radio_group'; import { getPosturePolicy, NewPackagePolicyPostureInput } from './utils'; +import { AwsInputVarFields } from './aws_credentials_form/aws_input_var_fields'; const AWSSetupInfoContent = () => ( <> @@ -279,37 +271,3 @@ const AwsCredentialTypeSelector = ({ onChange={(id) => onChange(id as AwsCredentialsType)} /> ); - -const AwsInputVarFields = ({ - fields, - onChange, -}: { - fields: Array; - onChange: (key: string, value: string) => void; -}) => ( -
- {fields.map((field) => ( - - <> - {field.type === 'password' && ( - onChange(field.id, event.target.value)} - /> - )} - {field.type === 'text' && ( - onChange(field.id, event.target.value)} - /> - )} - - - ))} -
-); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index c8a62d3c9a9fe..eb76a288a8b6e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -545,11 +545,11 @@ export const CspPolicyTemplateForm = memo { - const inputVars = getPostureInputHiddenVars(inputType, packageInfo); + const inputVars = getPostureInputHiddenVars(inputType, packageInfo, setupTechnology); const policy = getPosturePolicy(newPolicy, inputType, inputVars); updatePolicy(policy); }, - [newPolicy, updatePolicy, packageInfo] + [setupTechnology, packageInfo, newPolicy, updatePolicy] ); // search for non null fields of the validation?.vars object @@ -588,6 +588,11 @@ export const CspPolicyTemplateForm = memo { + setEnabledPolicyInput(input.type); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [setupTechnology]); + useEnsureDefaultNamespace({ newPolicy, input, updatePolicy }); useCloudFormationTemplate({ @@ -741,6 +746,7 @@ export const CspPolicyTemplateForm = memo diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx index ef21868dd404d..5b64731b05cea 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { EuiCallOut, EuiSpacer, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { NewPackagePolicy, PackageInfo } from '@kbn/fleet-plugin/common'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { PackagePolicyReplaceDefineStepExtensionComponentProps } from '@kbn/fleet-plugin/public/types'; import { CSPM_POLICY_TEMPLATE, @@ -20,6 +21,7 @@ import { getPolicyTemplateInputOptions, type NewPackagePolicyPostureInput } from import { RadioGroup } from './csp_boxed_radio_group'; import { AzureCredentialsForm } from './azure_credentials_form/azure_credentials_form'; import { AwsCredentialsForm } from './aws_credentials_form/aws_credentials_form'; +import { AwsCredentialsFormAgentless } from './aws_credentials_form/aws_credentials_form_agentless'; import { EksCredentialsForm } from './eks_credentials_form'; import { GcpCredentialsForm } from './gcp_credential_form'; @@ -74,11 +76,20 @@ interface PolicyTemplateVarsFormProps { onChange: PackagePolicyReplaceDefineStepExtensionComponentProps['onChange']; setIsValid: (isValid: boolean) => void; disabled: boolean; + setupTechnology: SetupTechnology; } -export const PolicyTemplateVarsForm = ({ input, ...props }: PolicyTemplateVarsFormProps) => { +export const PolicyTemplateVarsForm = ({ + input, + setupTechnology, + ...props +}: PolicyTemplateVarsFormProps) => { switch (input.type) { case 'cloudbeat/cis_aws': + if (setupTechnology === SetupTechnology.AGENTLESS) { + return ; + } + return ; case 'cloudbeat/cis_eks': return ; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts index 898017d6daef5..5b211a7c878c3 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useState } from 'react'; import { AgentPolicy, NewPackagePolicyInput } from '@kbn/fleet-plugin/common'; import { SetupTechnology } from '@kbn/fleet-plugin/public'; @@ -25,12 +25,9 @@ export const useSetupTechnology = ({ SetupTechnology.AGENT_BASED ); const isCspmAws = input.type === CLOUDBEAT_AWS; - const isAgentlessAvailable = useMemo( - () => Boolean(isCspmAws && agentlessPolicy), - [isCspmAws, agentlessPolicy] - ); - const agentPolicyId = useMemo(() => agentPolicy?.id, [agentPolicy]); - const agentlessPolicyId = useMemo(() => agentlessPolicy?.id, [agentlessPolicy]); + const isAgentlessAvailable = Boolean(isCspmAws && agentlessPolicy); + const agentPolicyId = agentPolicy?.id; + const agentlessPolicyId = agentlessPolicy?.id; useEffect(() => { if (agentPolicyId && agentPolicyId !== agentlessPolicyId) { @@ -41,7 +38,7 @@ export const useSetupTechnology = ({ setSetupTechnology(SetupTechnology.AGENT_BASED); } else if (isAgentlessAvailable) { /* - preselecting agenteless when available + preselecting agentless when available and resetting to agent-based when switching to another integration type, which doesn't support agentless */ setSetupTechnology(SetupTechnology.AGENTLESS); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 148a482714a10..d6c05fe6b9acf 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -12,6 +12,7 @@ import type { RegistryPolicyTemplate, RegistryVarsEntry, } from '@kbn/fleet-plugin/common'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; import merge from 'lodash/merge'; import { CLOUDBEAT_AWS, @@ -30,6 +31,7 @@ import { getDefaultAwsVarsGroup } from './aws_credentials_form/aws_credentials_f import type { PostureInput, CloudSecurityPolicyTemplate } from '../../../common/types'; import { cloudPostureIntegrations } from '../../common/constants'; import { DEFAULT_EKS_VARS_GROUP } from './eks_credentials_form'; +import { AwsCredentialsType } from '../../../common/types'; // Posture policies only support the default namespace export const POSTURE_NAMESPACE = 'default'; @@ -203,11 +205,18 @@ export const getArmTemplateUrlFromCspmPackage = (packageInfo: PackageInfo): stri /** * Input vars that are hidden from the user */ -export const getPostureInputHiddenVars = (inputType: PostureInput, packageInfo: PackageInfo) => { +export const getPostureInputHiddenVars = ( + inputType: PostureInput, + packageInfo: PackageInfo, + setupTechnology: SetupTechnology +) => { switch (inputType) { case 'cloudbeat/cis_aws': return { - 'aws.credentials.type': { value: getDefaultAwsVarsGroup(packageInfo), type: 'text' }, + 'aws.credentials.type': { + value: getDefaultAwsVarsGroup(packageInfo, setupTechnology), + type: 'text', + }, }; case 'cloudbeat/cis_eks': return { 'aws.credentials.type': { value: DEFAULT_EKS_VARS_GROUP, type: 'text' } }; @@ -263,3 +272,7 @@ export const getCspmCloudShellDefaultValue = (packageInfo: PackageInfo): string return cloudShellUrl; }; + +export const getAwsCredentialsType = ( + input: Extract +): AwsCredentialsType | undefined => input.streams[0].vars?.['aws.credentials.type'].value; From b5bdfcc5409cc95e5b9bcd2fa66455d1e962e83f Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 1 Dec 2023 21:48:13 +0100 Subject: [PATCH 21/33] add temporary credentials --- .../aws_credentials_form.tsx | 2 +- .../aws_credentials_form_agentless.tsx | 65 +++++++++++++++++-- .../get_aws_credentials_form_options.tsx | 13 ++++ .../fleet_extensions/policy_template_form.tsx | 1 + 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 7088ae53b3263..5e237f027fa34 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -287,7 +287,7 @@ export const AwsCredentialsForm = ({ ); }; -const AwsCredentialTypeSelector = ({ +export const AwsCredentialTypeSelector = ({ type, onChange, }: { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx index 211d02a68026e..48cd076d4cd12 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx @@ -6,17 +6,31 @@ */ import React from 'react'; -import { EuiHorizontalRule, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import { + EuiFormRow, + EuiHorizontalRule, + EuiSelect, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { AwsCredentialsType } from '../../../../common/types'; +import { cspIntegrationDocsNavigation } from '../../../common/navigation/constants'; import { DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, + getAwsCredentialsFormManualOptionsAgentless, getAwsCredentialsFormOptions, getInputVarsFields, } from './get_aws_credentials_form_options'; -import { getPosturePolicy } from '../utils'; +import { getAwsCredentialsType, getPosturePolicy } from '../utils'; import { AwsInputVarFields } from './aws_input_var_fields'; -import { AwsFormProps } from './aws_credentials_form'; +import { AwsFormProps, ReadDocumentation } from './aws_credentials_form'; +// TODO: create a shared component between agent-based and agentless +// TODO: update tranalsation keys +// TODO: get text const AWSSetupInfoContentAgentless = () => { return ( <> @@ -40,15 +54,58 @@ const AWSSetupInfoContentAgentless = () => { ); }; +// TODO: create a shared component between agent-based and agentless, pass options and label +// TODO: update tranalsation keys +const AwsCredentialTypeSelector = ({ + type, + onChange, +}: { + onChange(type: AwsCredentialsType): void; + type: AwsCredentialsType; +}) => ( + + { + onChange(optionElem.target.value as AwsCredentialsType); + }} + /> + +); + export const AwsCredentialsFormAgentless = ({ input, newPolicy, updatePolicy }: AwsFormProps) => { + const awsCredentialsType = getAwsCredentialsType(input) || DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE; const options = getAwsCredentialsFormOptions(); - const group = options[DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE]; + const group = options[awsCredentialsType]; const fields = getInputVarsFields(input, group.fields); + const integrationLink = cspIntegrationDocsNavigation.cspm.getStartedPath; return ( <> + { + updatePolicy( + getPosturePolicy(newPolicy, input.type, { + 'aws.credentials.type': { value: optionId }, + }) + ); + }} + /> + + {group.info} + + + { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx index b237d9d19e68e..d988d8aa23a0a 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx @@ -105,6 +105,19 @@ export const getAwsCredentialsFormManualOptions = (): Array<{ .filter(({ value }) => value !== 'cloud_formation'); }; +// TODO: move strings to constants +export const getAwsCredentialsFormManualOptionsAgentless = (): Array<{ + value: AwsCredentialsType; + text: string; +}> => { + return Object.entries(getAwsCredentialsFormOptions()) + .map(([key, value]) => ({ + value: key as AwsCredentialsType, + text: value.label, + })) + .filter(({ value }) => value === 'direct_access_keys' || value === 'temporary_keys'); +}; + export const DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE = 'assume_role'; export const DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE = 'direct_access_keys'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index eb76a288a8b6e..5c30aa0013bf7 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -588,6 +588,7 @@ export const CspPolicyTemplateForm = memo { setEnabledPolicyInput(input.type); // eslint-disable-next-line react-hooks/exhaustive-deps From a28c337fe53f18a32cb96cdcc4f25b1a253572cf Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Tue, 5 Dec 2023 11:16:01 +0100 Subject: [PATCH 22/33] create shared components to be used for both agent-based and agentless --- .../aws_credentials_form.tsx | 58 +++++++------ .../aws_credentials_form_agentless.tsx | 83 +++++-------------- .../get_aws_credentials_form_options.tsx | 29 ++++--- 3 files changed, 67 insertions(+), 103 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 5e237f027fa34..6ec77ade97fea 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import { EuiCallOut, EuiFormRow, @@ -22,6 +22,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { + AwsCredentialsTypeOptions, DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE, getAwsCredentialsFormManualOptions, @@ -38,9 +39,9 @@ import { AwsCredentialsType } from '../../../../common/types'; import { AwsInputVarFields } from './aws_input_var_fields'; interface AWSSetupInfoContentProps { - integrationLink: string; + info: ReactNode; } -const AWSSetupInfoContent = ({ integrationLink }: AWSSetupInfoContentProps) => { +export const AWSSetupInfoContent = ({ info }: AWSSetupInfoContentProps) => { return ( <> @@ -54,20 +55,7 @@ const AWSSetupInfoContent = ({ integrationLink }: AWSSetupInfoContentProps) => { - - - - ), - }} - /> + {info} ); @@ -243,7 +231,24 @@ export const AwsCredentialsForm = ({ return ( <> - + + + + ), + }} + /> + } + /> { updatePolicy( @@ -290,19 +299,18 @@ export const AwsCredentialsForm = ({ export const AwsCredentialTypeSelector = ({ type, onChange, + label, + options, }: { onChange(type: AwsCredentialsType): void; type: AwsCredentialsType; + label: string; + options: AwsCredentialsTypeOptions; }) => ( - + { onChange(optionElem.target.value as AwsCredentialsType); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx index 48cd076d4cd12..028d2d1fb5c8d 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx @@ -6,17 +6,9 @@ */ import React from 'react'; -import { - EuiFormRow, - EuiHorizontalRule, - EuiSelect, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; +import { EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { AwsCredentialsType } from '../../../../common/types'; import { cspIntegrationDocsNavigation } from '../../../common/navigation/constants'; import { DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, @@ -26,59 +18,12 @@ import { } from './get_aws_credentials_form_options'; import { getAwsCredentialsType, getPosturePolicy } from '../utils'; import { AwsInputVarFields } from './aws_input_var_fields'; -import { AwsFormProps, ReadDocumentation } from './aws_credentials_form'; - -// TODO: create a shared component between agent-based and agentless -// TODO: update tranalsation keys -// TODO: get text -const AWSSetupInfoContentAgentless = () => { - return ( - <> - - -

- -

-
- - - - - - ); -}; - -// TODO: create a shared component between agent-based and agentless, pass options and label -// TODO: update tranalsation keys -const AwsCredentialTypeSelector = ({ - type, - onChange, -}: { - onChange(type: AwsCredentialsType): void; - type: AwsCredentialsType; -}) => ( - - { - onChange(optionElem.target.value as AwsCredentialsType); - }} - /> - -); +import { + AwsFormProps, + ReadDocumentation, + AWSSetupInfoContent, + AwsCredentialTypeSelector, +} from './aws_credentials_form'; export const AwsCredentialsFormAgentless = ({ input, newPolicy, updatePolicy }: AwsFormProps) => { const awsCredentialsType = getAwsCredentialsType(input) || DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE; @@ -87,12 +32,24 @@ export const AwsCredentialsFormAgentless = ({ input, newPolicy, updatePolicy }: const fields = getInputVarsFields(input, group.fields); const integrationLink = cspIntegrationDocsNavigation.cspm.getStartedPath; + // TODO: get text return ( <> - + + } + /> { updatePolicy( getPosturePolicy(newPolicy, input.type, { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx index d988d8aa23a0a..b23a9c5891ff3 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx @@ -92,31 +92,30 @@ export const getInputVarsFields = (input: NewPackagePolicyInput, fields: AwsCred }); export type AwsOptions = Record; - -export const getAwsCredentialsFormManualOptions = (): Array<{ +export type AwsCredentialsTypeOptions = Array<{ value: AwsCredentialsType; text: string; -}> => { +}>; + +const getAwsCredentialsTypeSelectorOptions = ( + filterFn: ({ value }: { value: AwsCredentialsType }) => boolean +): AwsCredentialsTypeOptions => { return Object.entries(getAwsCredentialsFormOptions()) .map(([key, value]) => ({ value: key as AwsCredentialsType, text: value.label, })) - .filter(({ value }) => value !== 'cloud_formation'); + .filter(filterFn); }; +export const getAwsCredentialsFormManualOptions = (): AwsCredentialsTypeOptions => + getAwsCredentialsTypeSelectorOptions(({ value }) => value !== 'cloud_formation'); + // TODO: move strings to constants -export const getAwsCredentialsFormManualOptionsAgentless = (): Array<{ - value: AwsCredentialsType; - text: string; -}> => { - return Object.entries(getAwsCredentialsFormOptions()) - .map(([key, value]) => ({ - value: key as AwsCredentialsType, - text: value.label, - })) - .filter(({ value }) => value === 'direct_access_keys' || value === 'temporary_keys'); -}; +export const getAwsCredentialsFormManualOptionsAgentless = (): AwsCredentialsTypeOptions => + getAwsCredentialsTypeSelectorOptions( + ({ value }) => value === 'direct_access_keys' || value === 'temporary_keys' + ); export const DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE = 'assume_role'; export const DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE = 'direct_access_keys'; From 2e6cd1bd74d59f5254d33c706de3cea63f8f9c97 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Tue, 5 Dec 2023 13:25:50 +0100 Subject: [PATCH 23/33] rename getAwsCredentialsFormAgentlessOptions --- .../aws_credentials_form/aws_credentials_form_agentless.tsx | 4 ++-- .../aws_credentials_form/get_aws_credentials_form_options.tsx | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx index 028d2d1fb5c8d..058697502e0ed 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx @@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n'; import { cspIntegrationDocsNavigation } from '../../../common/navigation/constants'; import { DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, - getAwsCredentialsFormManualOptionsAgentless, + getAwsCredentialsFormAgentlessOptions, getAwsCredentialsFormOptions, getInputVarsFields, } from './get_aws_credentials_form_options'; @@ -49,7 +49,7 @@ export const AwsCredentialsFormAgentless = ({ input, newPolicy, updatePolicy }: defaultMessage: 'Preferred method', })} type={awsCredentialsType} - options={getAwsCredentialsFormManualOptionsAgentless()} + options={getAwsCredentialsFormAgentlessOptions()} onChange={(optionId) => { updatePolicy( getPosturePolicy(newPolicy, input.type, { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx index b23a9c5891ff3..a0bc171594294 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx @@ -111,8 +111,7 @@ const getAwsCredentialsTypeSelectorOptions = ( export const getAwsCredentialsFormManualOptions = (): AwsCredentialsTypeOptions => getAwsCredentialsTypeSelectorOptions(({ value }) => value !== 'cloud_formation'); -// TODO: move strings to constants -export const getAwsCredentialsFormManualOptionsAgentless = (): AwsCredentialsTypeOptions => +export const getAwsCredentialsFormAgentlessOptions = (): AwsCredentialsTypeOptions => getAwsCredentialsTypeSelectorOptions( ({ value }) => value === 'direct_access_keys' || value === 'temporary_keys' ); From f9b552ddff52d8f9d316bfe3f2e16745ec55b5e3 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Tue, 5 Dec 2023 18:52:39 +0100 Subject: [PATCH 24/33] cover edit/upgrade flow --- .../fleet_extensions/policy_template_form.tsx | 12 +++++++++- .../setup_technology_selector.tsx | 7 +++++- .../use_setup_technology.ts | 24 +++++++++++++++---- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 5c30aa0013bf7..65c9a83bd2ea0 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -21,6 +21,7 @@ import { EuiTitle, } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import type { NewPackagePolicyInput, @@ -531,7 +532,11 @@ export const CspPolicyTemplateForm = memo { @@ -590,6 +595,10 @@ export const CspPolicyTemplateForm = memo { + if (isEditPage) { + return; + } + setEnabledPolicyInput(input.type); // eslint-disable-next-line react-hooks/exhaustive-deps }, [setupTechnology]); @@ -731,8 +740,9 @@ export const CspPolicyTemplateForm = memo updatePolicy({ ...newPolicy, [field]: value })} /> - {isAgentlessAvailable && ( + {shouldRenderAgentlessSelector && ( diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx index c3b6572281da3..349e8d1a4e489 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx @@ -20,9 +20,11 @@ import { } from '@elastic/eui'; export const SetupTechnologySelector = ({ + disabled, setupTechnology, onSetupTechnologyChange, }: { + disabled: boolean; setupTechnology: SetupTechnology; onSetupTechnologyChange: (value: SetupTechnology) => void; }) => { @@ -87,9 +89,11 @@ export const SetupTechnologySelector = ({ <> + void; + isEditPage: boolean; }) => { - const [setupTechnology, setSetupTechnology] = useState( - SetupTechnology.AGENT_BASED - ); const isCspmAws = input.type === CLOUDBEAT_AWS; const isAgentlessAvailable = Boolean(isCspmAws && agentlessPolicy); const agentPolicyId = agentPolicy?.id; const agentlessPolicyId = agentlessPolicy?.id; + const [setupTechnology, setSetupTechnology] = useState(() => { + if (isEditPage && agentPolicyId === SetupTechnology.AGENTLESS) { + return SetupTechnology.AGENTLESS; + } + + return SetupTechnology.AGENT_BASED; + }); useEffect(() => { + if (isEditPage) { + return; + } + if (agentPolicyId && agentPolicyId !== agentlessPolicyId) { /* handle case when agent policy is coming from outside, @@ -45,13 +55,17 @@ export const useSetupTechnology = ({ } else { setSetupTechnology(SetupTechnology.AGENT_BASED); } - }, [agentPolicyId, agentlessPolicyId, isAgentlessAvailable]); + }, [agentPolicyId, agentlessPolicyId, isAgentlessAvailable, isEditPage]); useEffect(() => { + if (isEditPage) { + return; + } + if (handleSetupTechnologyChange) { handleSetupTechnologyChange(setupTechnology); } - }, [handleSetupTechnologyChange, setupTechnology]); + }, [handleSetupTechnologyChange, isEditPage, setupTechnology]); return { isAgentlessAvailable, From b8850a6255fa43e33012860d63096054190350c8 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 8 Dec 2023 13:55:13 +0100 Subject: [PATCH 25/33] add temp setup guide for agentless options --- .../aws_credentials_form_agentless.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx index 058697502e0ed..b0ab98db98cda 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form_agentless.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiSpacer } from '@elastic/eui'; +import { EuiLink, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { cspIntegrationDocsNavigation } from '../../../common/navigation/constants'; @@ -32,14 +32,23 @@ export const AwsCredentialsFormAgentless = ({ input, newPolicy, updatePolicy }: const fields = getInputVarsFields(input, group.fields); const integrationLink = cspIntegrationDocsNavigation.cspm.getStartedPath; - // TODO: get text return ( <> + + + ), + }} /> } /> From b23ca23a14b74ac1a30b90338951f426055518c1 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 8 Dec 2023 14:04:35 +0100 Subject: [PATCH 26/33] remove todo --- .../components/fleet_extensions/policy_template_form.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 687cd29c4e803..e0ca1e8933fc9 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -548,7 +548,7 @@ export const CspPolicyTemplateForm = memo { if (isEditPage) { return; From d357b627ba845dee265f98d2d129a5550a5aaf12 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 8 Dec 2023 14:38:09 +0100 Subject: [PATCH 27/33] unit tests for getDefaultAwsCredentialsType --- .../aws_credentials_form.tsx | 25 +------ .../get_aws_credentials_form_options.tsx | 1 + .../components/fleet_extensions/utils.test.ts | 74 ++++++++++++++++++- .../components/fleet_extensions/utils.ts | 38 ++++++++-- 4 files changed, 104 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 6ec77ade97fea..f7a8a3833d1e3 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -16,23 +16,16 @@ import { EuiTitle, } from '@elastic/eui'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; -import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { NewPackagePolicyInput, PackageInfo } from '@kbn/fleet-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { AwsCredentialsTypeOptions, - DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, - DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE, getAwsCredentialsFormManualOptions, } from './get_aws_credentials_form_options'; import { RadioGroup } from '../csp_boxed_radio_group'; -import { - getCspmCloudFormationDefaultValue, - getPosturePolicy, - NewPackagePolicyPostureInput, -} from '../utils'; +import { getPosturePolicy, NewPackagePolicyPostureInput } from '../utils'; import { SetupFormat, useAwsCredentialsForm } from './hooks'; import { AWS_ORGANIZATION_ACCOUNT } from '../policy_template_form'; import { AwsCredentialsType } from '../../../../common/types'; @@ -74,22 +67,6 @@ const getSetupFormatOptions = (): Array<{ id: SetupFormat; label: string }> => [ }, ]; -export const getDefaultAwsVarsGroup = ( - packageInfo: PackageInfo, - setupTechnology?: SetupTechnology -): AwsCredentialsType => { - if (setupTechnology && setupTechnology === SetupTechnology.AGENTLESS) { - return DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE; - } - - const hasCloudFormationTemplate = !!getCspmCloudFormationDefaultValue(packageInfo); - if (hasCloudFormationTemplate) { - return 'cloud_formation'; - } - - return DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE; -}; - export interface AwsFormProps { newPolicy: NewPackagePolicy; input: Extract; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx index a0bc171594294..cd32f5f7f41dc 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/get_aws_credentials_form_options.tsx @@ -116,6 +116,7 @@ export const getAwsCredentialsFormAgentlessOptions = (): AwsCredentialsTypeOptio ({ value }) => value === 'direct_access_keys' || value === 'temporary_keys' ); +export const DEFAULT_AWS_CREDENTIALS_TYPE = 'cloud_formation'; export const DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE = 'assume_role'; export const DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE = 'direct_access_keys'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts index 266cd98ab0450..b05c7fe096516 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts @@ -4,6 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import type { PackageInfo } from '@kbn/fleet-plugin/common'; +import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { getMaxPackageName, @@ -11,9 +13,9 @@ import { getPosturePolicy, getCspmCloudShellDefaultValue, isBelowMinVersion, + getDefaultAwsCredentialsType, } from './utils'; import { getMockPolicyAWS, getMockPolicyK8s, getMockPolicyEKS } from './mocks'; -import type { PackageInfo } from '@kbn/fleet-plugin/common'; describe('getPosturePolicy', () => { for (const [name, getPolicy, expectedVars] of [ @@ -22,7 +24,11 @@ describe('getPosturePolicy', () => { ['cloudbeat/cis_k8s', getMockPolicyK8s, null], ] as const) { it(`updates package policy with hidden vars for ${name}`, () => { - const inputVars = getPostureInputHiddenVars(name, {} as any); + const inputVars = getPostureInputHiddenVars( + name, + {} as PackageInfo, + SetupTechnology.AGENT_BASED + ); const policy = getPosturePolicy(getPolicy(), name, inputVars); const enabledInputs = policy.inputs.filter( @@ -280,3 +286,67 @@ describe('isBelowMinVersion', () => { } }); }); + +describe('getDefaultAwsCredentialsType', () => { + let packageInfo: PackageInfo; + + beforeEach(() => { + packageInfo = { + policy_templates: [ + { + name: 'cspm', + inputs: [ + { + vars: [ + { + name: 'cloud_formation_template', + default: 'http://example.com/cloud_formation_template', + }, + ], + }, + ], + }, + ], + } as PackageInfo; + }); + + it('should return "direct_access_key" for agentless', () => { + const setupTechnology = SetupTechnology.AGENTLESS; + const result = getDefaultAwsCredentialsType(packageInfo, setupTechnology); + + expect(result).toBe('direct_access_keys'); + }); + + it('should return "assume_role" for agent-based, when cloudformation is not available', () => { + const setupTechnology = SetupTechnology.AGENT_BASED; + packageInfo = { + policy_templates: [ + { + name: 'cspm', + inputs: [ + { + vars: [ + { + name: 'cloud_shell', + default: 'http://example.com/cloud_shell', + }, + ], + }, + ], + }, + ], + } as PackageInfo; + + const result = getDefaultAwsCredentialsType({} as PackageInfo, setupTechnology); + + expect(result).toBe('assume_role'); + }); + + it('should return "cloud_formation" for agent-based, when cloudformation is available', () => { + const setupTechnology = SetupTechnology.AGENT_BASED; + + const result = getDefaultAwsCredentialsType(packageInfo, setupTechnology); + + expect(result).toBe('cloud_formation'); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 0d73d5c9f67ad..29e83d238d931 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -19,22 +19,29 @@ import semverCoerce from 'semver/functions/coerce'; import semverLt from 'semver/functions/lt'; import { CLOUDBEAT_AWS, + CLOUDBEAT_AZURE, CLOUDBEAT_EKS, - CLOUDBEAT_VANILLA, CLOUDBEAT_GCP, - CLOUDBEAT_AZURE, + CLOUDBEAT_VANILLA, CLOUDBEAT_VULN_MGMT_AWS, - SUPPORTED_POLICY_TEMPLATES, - SUPPORTED_CLOUDBEAT_INPUTS, CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE, + SUPPORTED_CLOUDBEAT_INPUTS, + SUPPORTED_POLICY_TEMPLATES, VULN_MGMT_POLICY_TEMPLATE, } from '../../../common/constants'; -import { getDefaultAwsVarsGroup } from './aws_credentials_form/aws_credentials_form'; -import type { PostureInput, CloudSecurityPolicyTemplate } from '../../../common/types'; +import { + AwsCredentialsType, + CloudSecurityPolicyTemplate, + PostureInput, +} from '../../../common/types'; import { cloudPostureIntegrations } from '../../common/constants'; import { DEFAULT_EKS_VARS_GROUP } from './eks_credentials_form'; -import { AwsCredentialsType } from '../../../common/types'; +import { + DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE, + DEFAULT_AWS_CREDENTIALS_TYPE, + DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE, +} from './aws_credentials_form/get_aws_credentials_form_options'; // Posture policies only support the default namespace export const POSTURE_NAMESPACE = 'default'; @@ -205,6 +212,21 @@ export const getArmTemplateUrlFromCspmPackage = (packageInfo: PackageInfo): stri return armTemplateUrl; }; +export const getDefaultAwsCredentialsType = ( + packageInfo: PackageInfo, + setupTechnology?: SetupTechnology +): AwsCredentialsType => { + if (setupTechnology && setupTechnology === SetupTechnology.AGENTLESS) { + return DEFAULT_AGENTLESS_AWS_CREDENTIALS_TYPE; + } + + const hasCloudFormationTemplate = !!getCspmCloudFormationDefaultValue(packageInfo); + if (hasCloudFormationTemplate) { + return DEFAULT_AWS_CREDENTIALS_TYPE; + } + + return DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE; +}; /** * Input vars that are hidden from the user */ @@ -217,7 +239,7 @@ export const getPostureInputHiddenVars = ( case 'cloudbeat/cis_aws': return { 'aws.credentials.type': { - value: getDefaultAwsVarsGroup(packageInfo, setupTechnology), + value: getDefaultAwsCredentialsType(packageInfo, setupTechnology), type: 'text', }, }; From cccd4eea39b3c0282802b6e82a820b58d05fa360 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 8 Dec 2023 15:11:43 +0100 Subject: [PATCH 28/33] fix policy_template_form tests --- .../policy_template_form.test.tsx | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx index 5764b5af44357..229998bbfd93b 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import { CspPolicyTemplateForm, AWS_ORGANIZATION_ACCOUNT, @@ -141,7 +141,7 @@ describe('', () => { }); }); - it('renders and updates name field', () => { + it('renders and updates name field', async () => { const policy = getMockPolicyK8s(); const { getByLabelText } = render(); const name = getByLabelText('Name'); @@ -149,15 +149,15 @@ describe('', () => { userEvent.type(name, '1'); - // Listen to the 2nd triggered by the test. - // The 1st is done on mount to ensure initial state is valid. - expect(onChange).toHaveBeenNthCalledWith(2, { - isValid: true, - updatedPolicy: { ...policy, name: `${policy.name}1` }, + await waitFor(() => { + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: { ...policy, name: `${policy.name}1` }, + }); }); }); - it('renders and updates description field', () => { + it('renders and updates description field', async () => { const policy = getMockPolicyK8s(); const { getByLabelText } = render(); const description = getByLabelText('Description'); @@ -165,11 +165,11 @@ describe('', () => { userEvent.type(description, '1'); - // Listen to the 2nd triggered by the test. - // The 1st is done on mount to ensure initial state is valid. - expect(onChange).toHaveBeenNthCalledWith(2, { - isValid: true, - updatedPolicy: { ...policy, description: `${policy.description}1` }, + await waitFor(() => { + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: { ...policy, description: `${policy.description}1` }, + }); }); }); @@ -186,7 +186,7 @@ describe('', () => { expect(option1).toBeChecked(); }); - it('updates selected KSPM input', () => { + it('updates selected KSPM input', async () => { const k8sPolicy = getMockPolicyK8s(); const eksPolicy = getMockPolicyEKS(); @@ -194,11 +194,11 @@ describe('', () => { const option = getByLabelText('EKS'); userEvent.click(option); - // Listen to the 2nd triggered by the test. - // The 1st is done on mount to ensure initial state is valid. - expect(onChange).toHaveBeenNthCalledWith(2, { - isValid: true, - updatedPolicy: eksPolicy, + await waitFor(() => { + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: eksPolicy, + }); }); }); From f6a54a2184bb6ff775c2dd08bcb39fcfa37acb63 Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 8 Dec 2023 15:41:45 +0100 Subject: [PATCH 29/33] unit tests for use_setup_technology --- .../use_setup_technology.test.ts | 142 +++++++++++++----- 1 file changed, 108 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts index a5aa5e2df9734..a19fdb3678777 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts @@ -14,46 +14,120 @@ import { CLOUDBEAT_AWS } from '../../../../common/constants'; import { useSetupTechnology } from './use_setup_technology'; describe('useSetupTechnology', () => { - it('initializes with AGENT_BASED technology', () => { - const { result } = renderHook(() => - useSetupTechnology({ - input: { type: 'cloudbeat/no-agentless-support' } as NewPackagePolicyInput, - }) - ); - expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); - }); + describe('create page flow', () => { + const isEditPage = false; - it('sets to AGENTLESS when agentless is available', () => { - const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; - const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; - const { result } = renderHook(() => useSetupTechnology({ input, agentlessPolicy })); - expect(result.current.isAgentlessAvailable).toBeTruthy(); - expect(result.current.setupTechnology).toBe(SetupTechnology.AGENTLESS); - }); + it('initializes with AGENT_BASED technology', () => { + const { result } = renderHook(() => + useSetupTechnology({ + input: { type: 'cloudbeat/no-agentless-support' } as NewPackagePolicyInput, + isEditPage, + }) + ); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); + }); + + it('sets to AGENTLESS when agentless is available', () => { + const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; + const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; + const { result } = renderHook(() => useSetupTechnology({ input, agentlessPolicy, isEditPage })); + expect(result.current.isAgentlessAvailable).toBeTruthy(); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENTLESS); + }); - it('sets to AGENT_BASED when agentPolicyId differs from agentlessPolicyId', () => { - const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; - const agentPolicy = { id: 'agentPolicyId' } as AgentPolicy; - const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; - const { result } = renderHook(() => - useSetupTechnology({ input, agentPolicy, agentlessPolicy }) - ); - expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); + it('sets to AGENT_BASED when agentPolicyId differs from agentlessPolicyId', () => { + const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; + const agentPolicy = { id: 'agentPolicyId' } as AgentPolicy; + const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; + const { result } = renderHook(() => + useSetupTechnology({ input, agentPolicy, agentlessPolicy, isEditPage }) + ); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); + }); + + it('calls handleSetupTechnologyChange when setupTechnology changes', () => { + const handleSetupTechnologyChangeMock = jest.fn(); + const { result } = renderHook(() => + useSetupTechnology({ + input: { type: 'someType' } as NewPackagePolicyInput, + handleSetupTechnologyChange: handleSetupTechnologyChangeMock, + isEditPage, + }) + ); + + act(() => { + result.current.setSetupTechnology(SetupTechnology.AGENTLESS); + }); + + expect(handleSetupTechnologyChangeMock).toHaveBeenCalledWith(SetupTechnology.AGENTLESS); + }); }); - it('calls handleSetupTechnologyChange when setupTechnology changes', () => { - const handleSetupTechnologyChangeMock = jest.fn(); - const { result } = renderHook(() => - useSetupTechnology({ - input: { type: 'someType' } as NewPackagePolicyInput, - handleSetupTechnologyChange: handleSetupTechnologyChangeMock, - }) - ); + describe('edit page flow', () => { + const isEditPage = true; - act(() => { - result.current.setSetupTechnology(SetupTechnology.AGENTLESS); + it('initializes with AGENT_BASED technology', () => { + const { result } = renderHook(() => + useSetupTechnology({ + input: { type: 'cloudbeat/no-agentless-support' } as NewPackagePolicyInput, + isEditPage, + }) + ); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); }); - expect(handleSetupTechnologyChangeMock).toHaveBeenCalledWith(SetupTechnology.AGENTLESS); + it('initializes with AGENTLESS technology if the agent policy id is "agentless"', () => { + const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; + const agentPolicy = { id: 'agentless' } as AgentPolicy; + const { result } = renderHook(() => + useSetupTechnology({ + input, + agentPolicy, + isEditPage, + }) + ); + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENTLESS); + }); + + it('should not call handleSetupTechnologyChange when setupTechnology changes', () => { + const handleSetupTechnologyChangeMock = jest.fn(); + const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; + const { result } = renderHook(() => + useSetupTechnology({ + input, + handleSetupTechnologyChange: handleSetupTechnologyChangeMock, + isEditPage, + }) + ); + + act(() => { + result.current.setSetupTechnology(SetupTechnology.AGENTLESS); + }); + + expect(handleSetupTechnologyChangeMock).not.toHaveBeenCalled(); + }); + + it('should not update setupTechnology when agentlessPolicyId becomes available', () => { + const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; + const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; + const { result, rerender } = renderHook(() => + useSetupTechnology({ + input, + isEditPage, + }) + ); + + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); + + act(() => { + rerender({ + input, + agentlessPolicy, + isEditPage, + }); + }); + + expect(result.current.setupTechnology).toBe(SetupTechnology.AGENT_BASED); + }); }); }); From 3adc0fb69b41e9aad4214a4cb122d94bbaac9b2e Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Fri, 8 Dec 2023 16:11:29 +0100 Subject: [PATCH 30/33] fix linting error --- .../setup_technology_selector/use_setup_technology.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts index a19fdb3678777..744a87a009f98 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/use_setup_technology.test.ts @@ -30,7 +30,9 @@ describe('useSetupTechnology', () => { it('sets to AGENTLESS when agentless is available', () => { const agentlessPolicy = { id: 'agentlessPolicyId' } as AgentPolicy; const input = { type: CLOUDBEAT_AWS } as NewPackagePolicyInput; - const { result } = renderHook(() => useSetupTechnology({ input, agentlessPolicy, isEditPage })); + const { result } = renderHook(() => + useSetupTechnology({ input, agentlessPolicy, isEditPage }) + ); expect(result.current.isAgentlessAvailable).toBeTruthy(); expect(result.current.setupTechnology).toBe(SetupTechnology.AGENTLESS); }); From b9123ace8fab9262b79090ca229de329bb77c1fc Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Mon, 11 Dec 2023 17:44:37 +0100 Subject: [PATCH 31/33] add unit test for PolicyTemplateForm component --- .../aws_credentials_form.tsx | 7 +- .../fleet_extensions/gcp_credential_form.tsx | 9 +- .../components/fleet_extensions/mocks.ts | 5 +- .../policy_template_form.test.tsx | 112 +++++++++++++++++- .../setup_technology_selector.tsx | 2 + 5 files changed, 123 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 00e1d30caf11c..48473054850f5 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -24,7 +24,7 @@ import { AwsCredentialsTypeOptions, getAwsCredentialsFormManualOptions, } from './get_aws_credentials_form_options'; -import { RadioGroup } from '../csp_boxed_radio_group'; +import { CspRadioOption, RadioGroup } from '../csp_boxed_radio_group'; import { getPosturePolicy, NewPackagePolicyPostureInput } from '../utils'; import { SetupFormat, useAwsCredentialsForm } from './hooks'; import { AWS_ORGANIZATION_ACCOUNT } from '../policy_template_form'; @@ -54,16 +54,18 @@ export const AWSSetupInfoContent = ({ info }: AWSSetupInfoContentProps) => { ); }; -const getSetupFormatOptions = (): Array<{ id: SetupFormat; label: string }> => [ +const getSetupFormatOptions = (): CspRadioOption[] => [ { id: 'cloud_formation', label: 'CloudFormation', + testId: 'aws-cloudformation-setup-option', }, { id: 'manual', label: i18n.translate('xpack.csp.awsIntegration.setupFormatOptions.manual', { defaultMessage: 'Manual', }), + testId: 'aws-manual-setup-option', }, ]; @@ -292,6 +294,7 @@ export const AwsCredentialTypeSelector = ({ onChange={(optionElem) => { onChange(optionElem.target.value as AwsCredentialsType); }} + data-test-subj={'aws-credentials-type-selector'} />
); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credential_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credential_form.tsx index 45a3f8a6639a5..4039d458548bb 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credential_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credential_form.tsx @@ -31,7 +31,7 @@ import { SETUP_ACCESS_CLOUD_SHELL, SETUP_ACCESS_MANUAL, } from '../../../common/constants'; -import { RadioGroup } from './csp_boxed_radio_group'; +import { CspRadioOption, RadioGroup } from './csp_boxed_radio_group'; import { getCspmCloudShellDefaultValue, getPosturePolicy, @@ -231,12 +231,7 @@ export const gcpField: GcpInputFields = { }, }; -const getSetupFormatOptions = (): Array<{ - id: SetupFormatGCP; - label: string; - disabled: boolean; - testId: string; -}> => [ +const getSetupFormatOptions = (): CspRadioOption[] => [ { id: SETUP_ACCESS_CLOUD_SHELL, label: i18n.translate('xpack.csp.gcpIntegration.setupFormatOptions.googleCloudShell', { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts index ae933a0f941a8..f893545024d78 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts @@ -6,7 +6,7 @@ */ import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; import type { PackageInfo } from '@kbn/fleet-plugin/common'; -import { createNewPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks'; +import { createNewPackagePolicyMock, createAgentPolicyMock } from '@kbn/fleet-plugin/common/mocks'; import { CLOUDBEAT_GCP, CLOUDBEAT_AZURE, @@ -24,6 +24,9 @@ export const getMockPolicyK8s = () => getPolicyMock(CLOUDBEAT_VANILLA, 'kspm', ' export const getMockPolicyEKS = () => getPolicyMock(CLOUDBEAT_EKS, 'kspm', 'eks'); export const getMockPolicyVulnMgmtAWS = () => getPolicyMock(CLOUDBEAT_VULN_MGMT_AWS, 'vuln_mgmt', 'aws'); +export const getMockAgentlessAgentPolicy = () => { + return createAgentPolicyMock({ id: 'agentless' }); +}; export const getMockPackageInfoVulnMgmtAWS = () => { return { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx index 229998bbfd93b..23347ce21013a 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx @@ -5,7 +5,8 @@ * 2.0. */ import React from 'react'; -import { render, waitFor } from '@testing-library/react'; +import { render, waitFor, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { CspPolicyTemplateForm, AWS_ORGANIZATION_ACCOUNT, @@ -15,6 +16,7 @@ import { } from './policy_template_form'; import { TestProvider } from '../../test/test_provider'; import { + getMockAgentlessAgentPolicy, getMockPackageInfoCspmAWS, getMockPackageInfoCspmAzure, getMockPackageInfoCspmGCP, @@ -32,7 +34,6 @@ import type { PackageInfo, PackagePolicy, } from '@kbn/fleet-plugin/common'; -import userEvent from '@testing-library/user-event'; import { getPosturePolicy } from './utils'; import { CLOUDBEAT_AWS, @@ -45,6 +46,7 @@ import { createReactQueryResponse } from '../../test/fixtures/react_query'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; import { usePackagePolicyList } from '../../common/api/use_package_policy_list'; import { CIS_GCP_INPUT_FIELDS_TEST_SUBJECTS } from './gcp_credential_form'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; // mock useParams jest.mock('react-router-dom', () => ({ @@ -94,12 +96,14 @@ describe('', () => { edit = false, agentPolicy, packageInfo = {} as PackageInfo, + agentlessPolicy, }: { edit?: boolean; newPolicy: NewPackagePolicy; agentPolicy?: AgentPolicy; packageInfo?: PackageInfo; onChange?: jest.Mock; + agentlessPolicy?: AgentPolicy; }) => ( {edit && ( @@ -110,6 +114,7 @@ describe('', () => { packageInfo={packageInfo} isEditPage={true} agentPolicy={agentPolicy} + agentlessPolicy={agentlessPolicy} /> )} {!edit && ( @@ -119,6 +124,7 @@ describe('', () => { packageInfo={packageInfo} isEditPage={false} agentPolicy={agentPolicy} + agentlessPolicy={agentlessPolicy} /> )} @@ -1436,6 +1442,108 @@ describe('', () => { }); }); + describe('Agentless', () => { + it('should render setup technology selector for AWS and allow to select agent-based', async () => { + const agentlessPolicy = getMockAgentlessAgentPolicy(); + const newPackagePolicy = getMockPolicyAWS(); + + const { getByTestId, getByRole } = render( + + ); + + // TODO: move test ids to constants + const setupTechnologySelectorAccordion = getByTestId('setup-technology-selector-accordion'); + const setupTechnologySelector = getByTestId('setup-technology-selector'); + const awsCredentialsTypeSelector = getByTestId('aws-credentials-type-selector'); + const options: HTMLOptionElement[] = within(awsCredentialsTypeSelector).getAllByRole( + 'option' + ); + const optionValues = options.map((option) => option.value); + + // default state + expect(setupTechnologySelectorAccordion).toBeInTheDocument(); + expect(setupTechnologySelector).toBeInTheDocument(); + expect(setupTechnologySelector).toHaveTextContent(/agentless/i); + expect(options).toHaveLength(2); + expect(optionValues).toEqual( + expect.arrayContaining(['direct_access_keys', 'temporary_keys']) + ); + + // select agent-based and check for cloudformation option + userEvent.click(setupTechnologySelector); + const agentBasedOption = getByRole('option', { name: /agent-based/i }); + await waitForEuiPopoverOpen(); + userEvent.click(agentBasedOption); + await waitFor(() => { + expect(getByTestId('aws-cloudformation-setup-option')).toBeInTheDocument(); + expect(getByTestId('aws-manual-setup-option')).toBeInTheDocument(); + }); + }); + + it('should not render setup technology selector for KSPM', () => { + const agentlessPolicy = getMockAgentlessAgentPolicy(); + const newPackagePolicy = getMockPolicyEKS(); + + const { queryByTestId } = render( + + ); + + const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + + expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); + }); + + it('should not render setup technology selector for CNVM', () => { + const agentlessPolicy = getMockAgentlessAgentPolicy(); + const newPackagePolicy = getMockPolicyVulnMgmtAWS(); + + const { queryByTestId } = render( + + ); + + const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + + expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); + }); + + it('should not render setup technology selector for CSPM GCP', () => { + const agentlessPolicy = getMockAgentlessAgentPolicy(); + const newPackagePolicy = getMockPolicyGCP(); + + const { queryByTestId } = render( + + ); + + const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + + expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); + }); + + it('should not render setup technology selector for CSPM Azure', () => { + const agentlessPolicy = getMockAgentlessAgentPolicy(); + let newPackagePolicy = getMockPolicyAzure(); + newPackagePolicy = getPosturePolicy(newPackagePolicy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'service_principal_with_client_certificate' }, + }); + + const { queryByTestId } = render( + + ); + + const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + + expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); + }); + }); + it(`renders Service principal with Client Certificate fields`, () => { let policy = getMockPolicyAzure(); policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx index 349e8d1a4e489..c0168a38e4913 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx @@ -100,6 +100,7 @@ export const SetupTechnologySelector = ({ /> } + data-test-subj={'setup-technology-selector-accordion'} >
From b5e4582ee5142b4b34777a1a5b7f0ae71fae7d8e Mon Sep 17 00:00:00 2001 From: Maxim Kholod Date: Mon, 11 Dec 2023 17:56:27 +0100 Subject: [PATCH 32/33] move test subj to const --- .../aws_credentials_form.tsx | 7 ++-- .../policy_template_form.test.tsx | 37 ++++++++++++++----- .../setup_technology_selector.tsx | 8 +++- .../public/components/test_subjects.ts | 9 +++++ 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 48473054850f5..45d26b74523f4 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -30,6 +30,7 @@ import { SetupFormat, useAwsCredentialsForm } from './hooks'; import { AWS_ORGANIZATION_ACCOUNT } from '../policy_template_form'; import { AwsCredentialsType } from '../../../../common/types_old'; import { AwsInputVarFields } from './aws_input_var_fields'; +import { AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ, AWS_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ } from '../../test_subjects'; interface AWSSetupInfoContentProps { info: ReactNode; @@ -58,14 +59,14 @@ const getSetupFormatOptions = (): CspRadioOption[] => [ { id: 'cloud_formation', label: 'CloudFormation', - testId: 'aws-cloudformation-setup-option', + testId: AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ.CLOUDFORMATION, }, { id: 'manual', label: i18n.translate('xpack.csp.awsIntegration.setupFormatOptions.manual', { defaultMessage: 'Manual', }), - testId: 'aws-manual-setup-option', + testId: AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ.MANUAL, }, ]; @@ -294,7 +295,7 @@ export const AwsCredentialTypeSelector = ({ onChange={(optionElem) => { onChange(optionElem.target.value as AwsCredentialsType); }} - data-test-subj={'aws-credentials-type-selector'} + data-test-subj={AWS_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ} /> ); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx index 23347ce21013a..3b549dcc9d9ed 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx @@ -47,6 +47,12 @@ import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; import { usePackagePolicyList } from '../../common/api/use_package_policy_list'; import { CIS_GCP_INPUT_FIELDS_TEST_SUBJECTS } from './gcp_credential_form'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import { + AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ, + AWS_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ, + SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ, + SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ, +} from '../test_subjects'; // mock useParams jest.mock('react-router-dom', () => ({ @@ -1451,10 +1457,11 @@ describe('', () => { ); - // TODO: move test ids to constants - const setupTechnologySelectorAccordion = getByTestId('setup-technology-selector-accordion'); - const setupTechnologySelector = getByTestId('setup-technology-selector'); - const awsCredentialsTypeSelector = getByTestId('aws-credentials-type-selector'); + const setupTechnologySelectorAccordion = getByTestId( + SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ + ); + const setupTechnologySelector = getByTestId(SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ); + const awsCredentialsTypeSelector = getByTestId(AWS_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ); const options: HTMLOptionElement[] = within(awsCredentialsTypeSelector).getAllByRole( 'option' ); @@ -1475,8 +1482,10 @@ describe('', () => { await waitForEuiPopoverOpen(); userEvent.click(agentBasedOption); await waitFor(() => { - expect(getByTestId('aws-cloudformation-setup-option')).toBeInTheDocument(); - expect(getByTestId('aws-manual-setup-option')).toBeInTheDocument(); + expect( + getByTestId(AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ.CLOUDFORMATION) + ).toBeInTheDocument(); + expect(getByTestId(AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ.MANUAL)).toBeInTheDocument(); }); }); @@ -1488,7 +1497,9 @@ describe('', () => { ); - const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + const setupTechnologySelectorAccordion = queryByTestId( + SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ + ); expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); }); @@ -1501,7 +1512,9 @@ describe('', () => { ); - const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + const setupTechnologySelectorAccordion = queryByTestId( + SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ + ); expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); }); @@ -1518,7 +1531,9 @@ describe('', () => { /> ); - const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + const setupTechnologySelectorAccordion = queryByTestId( + SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ + ); expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); }); @@ -1538,7 +1553,9 @@ describe('', () => { /> ); - const setupTechnologySelectorAccordion = queryByTestId('setup-technology-selector-accordion'); + const setupTechnologySelectorAccordion = queryByTestId( + SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ + ); expect(setupTechnologySelectorAccordion).not.toBeInTheDocument(); }); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx index c0168a38e4913..03ca7ab21150e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/setup_technology_selector/setup_technology_selector.tsx @@ -18,6 +18,10 @@ import { EuiText, useGeneratedHtmlId, } from '@elastic/eui'; +import { + SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ, + SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ, +} from '../../test_subjects'; export const SetupTechnologySelector = ({ disabled, @@ -100,7 +104,7 @@ export const SetupTechnologySelector = ({ /> } - data-test-subj={'setup-technology-selector-accordion'} + data-test-subj={SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ} > diff --git a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts index 1f603a67ae1fc..c51d562fec44a 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts @@ -43,3 +43,12 @@ export const CREATE_RULE_ACTION_SUBJ = 'csp:create_rule'; export const CSP_GROUPING = 'cloudSecurityGrouping'; export const CSP_GROUPING_LOADING = 'cloudSecurityGroupingLoading'; export const CSP_FINDINGS_COMPLIANCE_SCORE = 'cloudSecurityFindingsComplianceScore'; + +export const AWS_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ = 'aws-credentials-type-selector'; +export const AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ = { + CLOUDFORMATION: 'aws-cloudformation-setup-option', + MANUAL: 'aws-manual-setup-option', +}; + +export const SETUP_TECHNOLOGY_SELECTOR_ACCORDION_TEST_SUBJ = 'setup-technology-selector-accordion'; +export const SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ = 'setup-technology-selector'; From 81e020819207525a99719be5bce0edfb02f4b493 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:42:03 +0000 Subject: [PATCH 33/33] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../aws_credentials_form/aws_credentials_form.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 45d26b74523f4..3f717a9f4cb22 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -30,7 +30,10 @@ import { SetupFormat, useAwsCredentialsForm } from './hooks'; import { AWS_ORGANIZATION_ACCOUNT } from '../policy_template_form'; import { AwsCredentialsType } from '../../../../common/types_old'; import { AwsInputVarFields } from './aws_input_var_fields'; -import { AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ, AWS_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ } from '../../test_subjects'; +import { + AWS_CREDENTIALS_TYPE_OPTIONS_TEST_SUBJ, + AWS_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ, +} from '../../test_subjects'; interface AWSSetupInfoContentProps { info: ReactNode;