diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index 9f267e07569c21..7641745b897f4e 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -63,6 +63,7 @@ export interface CloudPostureIntegrationProps { icon?: string; tooltip?: string; isBeta?: boolean; + testId?: string; }>; } @@ -85,6 +86,7 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { defaultMessage: 'CIS AWS', }), icon: 'logoAWS', + testId: 'cisAwsTestId', }, { type: CLOUDBEAT_GCP, @@ -95,6 +97,7 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { defaultMessage: 'CIS GCP', }), icon: googleCloudLogo, + testId: 'cisGcpTestId', }, // needs to be a function that disables/enabled based on integration version { @@ -108,6 +111,7 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { disabled: false, isBeta: true, icon: 'logoAzure', + testId: 'cisAzureTestId', }, ], }, diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx index 9a50658a6a1f3b..829d1480978899 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx @@ -24,6 +24,7 @@ export interface CspRadioOption { icon?: string; tooltip?: string; isBeta?: boolean; + testId?: string; } export const RadioGroup = ({ @@ -34,7 +35,6 @@ export const RadioGroup = ({ onChange, }: CspRadioGroupProps) => { const { euiTheme } = useEuiTheme(); - return (
=> [ { id: SETUP_ACCESS_CLOUD_SHELL, @@ -240,6 +241,7 @@ const getSetupFormatOptions = (): Array<{ defaultMessage: 'Google Cloud Shell', }), disabled: false, + testId: 'gcpGoogleCloudShellOptionTestId', }, { id: SETUP_ACCESS_MANUAL, @@ -247,6 +249,7 @@ const getSetupFormatOptions = (): Array<{ defaultMessage: 'Manual', }), disabled: false, + testId: 'gcpManualOptionTestId', }, ]; 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 9d1c52a0c1ee3b..a4ec591d51c759 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 @@ -127,12 +127,14 @@ const getGcpAccountTypeOptions = (isGcpOrgDisabled: boolean): CspRadioGroupProps defaultMessage: 'Supported from integration version 1.6.0 and above', }) : undefined, + testId: 'gcpOrganizationAccountTestId', }, { id: GCP_SINGLE_ACCOUNT, label: i18n.translate('xpack.csp.fleetIntegration.gcpAccountType.gcpSingleAccountLabel', { defaultMessage: 'Single Account', }), + testId: 'gcpSingleAccountTestId', }, ]; 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 9db4c9bf22a75d..148a482714a107 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 @@ -225,6 +225,7 @@ export const getPolicyTemplateInputOptions = (policyTemplate: CloudSecurityPolic icon: o.icon, disabled: o.disabled, isBeta: o.isBeta, + testId: o.testId, })); export const getMaxPackageName = ( diff --git a/x-pack/test/cloud_security_posture_functional/config.ts b/x-pack/test/cloud_security_posture_functional/config.ts index 05f1477d84af17..53d87d2378db50 100644 --- a/x-pack/test/cloud_security_posture_functional/config.ts +++ b/x-pack/test/cloud_security_posture_functional/config.ts @@ -38,7 +38,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { * 2. merge the updated version number change to kibana */ `--xpack.fleet.packages.0.name=cloud_security_posture`, - `--xpack.fleet.packages.0.version=1.5.0`, + `--xpack.fleet.packages.0.version=1.6.0`, // `--xpack.fleet.registryUrl=https://localhost:8080`, ], }, diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts new file mode 100644 index 00000000000000..924a2ae6c0dca1 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts @@ -0,0 +1,82 @@ +/* + * 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 type { FtrProviderContext } from '../ftr_provider_context'; + +export function AddCisIntegrationFormPageProvider({ + getService, + getPageObjects, +}: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common', 'header']); + + const cisGcp = { + getIntegrationFormEntirePage: () => testSubjects.find('dataCollectionSetupStep'), + + getIntegrationPolicyTable: () => testSubjects.find('integrationPolicyTable'), + + getIntegrationFormEditPage: () => testSubjects.find('editPackagePolicy_page'), + + findOptionInPage: async (text: string) => { + await PageObjects.header.waitUntilLoadingHasFinished(); + const optionToBeClicked = await testSubjects.find(text); + return await optionToBeClicked; + }, + + clickOptionButton: async (text: string) => { + const optionToBeClicked = await cisGcp.findOptionInPage(text); + await optionToBeClicked.click(); + }, + + clickSaveButton: async () => { + const optionToBeClicked = await cisGcp.findOptionInPage('createPackagePolicySaveButton'); + await optionToBeClicked.click(); + }, + + getPostInstallModal: async () => { + return await testSubjects.find('confirmModalTitleText'); + }, + + isPostInstallGoogleCloudShellModal: async (isOrg: boolean, orgID?: string, prjID?: string) => { + const googleCloudShellModal = await testSubjects.find('postInstallGoogleCloudShellModal'); + const googleCloudShellModalVisibleText = await googleCloudShellModal.getVisibleText(); + const stringProjectId = prjID ? prjID : ''; + const stringOrganizationId = orgID ? `ORG_ID=${orgID}` : 'ORG_ID='; + const orgIdExist = googleCloudShellModalVisibleText.includes(stringOrganizationId); + const prjIdExist = googleCloudShellModalVisibleText.includes(stringProjectId); + + if (isOrg) { + return orgIdExist === true && prjIdExist === true; + } else { + return orgIdExist === false && prjIdExist === true; + } + }, + + checkGcpFieldExist: async (text: string) => { + const field = await testSubjects.findAll(text); + return field.length; + }, + + fillInTextField: async (selector: string, text: string) => { + const test = await testSubjects.find(selector); + await test.type(text); + }, + }; + + const navigateToAddIntegrationCspmPage = async () => { + await PageObjects.common.navigateToUrl( + 'fleet', // Defined in Security Solution plugin + 'integrations/cloud_security_posture/add-integration/cspm', + { shouldUseHashForSubUrl: false } + ); + }; + + return { + cisGcp, + navigateToAddIntegrationCspmPage, + }; +} diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/index.ts b/x-pack/test/cloud_security_posture_functional/page_objects/index.ts index 36dbf1bdc0fe9d..84a75d27e4e2a0 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/index.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/index.ts @@ -8,11 +8,13 @@ import { pageObjects as xpackFunctionalPageObjects } from '../../functional/page_objects'; import { FindingsPageProvider } from './findings_page'; import { CspDashboardPageProvider } from './csp_dashboard_page'; +import { AddCisIntegrationFormPageProvider } from './add_cis_integration_form_page'; import { VulnerabilityDashboardPageProvider } from './vulnerability_dashboard_page_object'; export const cloudSecurityPosturePageObjects = { findings: FindingsPageProvider, cloudPostureDashboard: CspDashboardPageProvider, + cisAddIntegration: AddCisIntegrationFormPageProvider, vulnerabilityDashboard: VulnerabilityDashboardPageProvider, }; export const pageObjects = { diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integration.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integration.ts new file mode 100644 index 00000000000000..5935fc49b06a02 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integration.ts @@ -0,0 +1,107 @@ +/* + * 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 expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +const CIS_GCP_OPTION_TEST_ID = 'cisGcpTestId'; +const GCP_ORGANIZATION_TEST_ID = 'gcpOrganizationAccountTestId'; +const GCP_SINGLE_ACCOUNT_TEST_ID = 'gcpSingleAccountTestId'; +const GCP_CLOUD_SHELL_TEST_ID = 'gcpGoogleCloudShellOptionTestId'; +const GCP_MANUAL_TEST_ID = 'gcpManualOptionTestId'; +const PRJ_ID_TEST_ID = 'project_id_test_id'; +const ORG_ID_TEST_ID = 'organization_id_test_id'; +const CREDENTIALS_TYPE_TEST_ID = 'credentials_type_test_id'; + +// eslint-disable-next-line import/no-default-export +export default function (providerContext: FtrProviderContext) { + const { getPageObjects, getService } = providerContext; + const pageObjects = getPageObjects(['cloudPostureDashboard', 'cisAddIntegration', 'header']); + const kibanaServer = getService('kibanaServer'); + + describe('Test adding Cloud Security Posture Integrations', function () { + this.tags(['cloud_security_posture_cis_integration']); + let cisIntegrationGcp: typeof pageObjects.cisAddIntegration.cisGcp; + let cisIntegration: typeof pageObjects.cisAddIntegration; + + beforeEach(async () => { + cisIntegration = pageObjects.cisAddIntegration; + cisIntegrationGcp = pageObjects.cisAddIntegration.cisGcp; + + await cisIntegration.navigateToAddIntegrationCspmPage(); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + + describe('CIS_GCP Organization', () => { + it('Switch between Manual and Google cloud shell', async () => { + await cisIntegrationGcp.clickOptionButton(CIS_GCP_OPTION_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_ORGANIZATION_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_MANUAL_TEST_ID); + /* Check for existing fields. In Manual, Credential field should be visible */ + expect((await cisIntegrationGcp.checkGcpFieldExist(PRJ_ID_TEST_ID)) === 1).to.be(true); + expect((await cisIntegrationGcp.checkGcpFieldExist(ORG_ID_TEST_ID)) === 1).to.be(true); + expect((await cisIntegrationGcp.checkGcpFieldExist(CREDENTIALS_TYPE_TEST_ID)) === 1).to.be( + true + ); + + await cisIntegrationGcp.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID); + /* Check for existing fields. In Google Cloud Shell, Credential field should NOT be visible */ + expect((await cisIntegrationGcp.checkGcpFieldExist(PRJ_ID_TEST_ID)) === 1).to.be(true); + expect((await cisIntegrationGcp.checkGcpFieldExist(ORG_ID_TEST_ID)) === 1).to.be(true); + expect((await cisIntegrationGcp.checkGcpFieldExist(CREDENTIALS_TYPE_TEST_ID)) === 0).to.be( + true + ); + }); + + it('Post Installation Google Cloud Shell modal pops up after user clicks on Save button when adding integration, when there are no Project ID or Organization ID provided, it should use default value', async () => { + await cisIntegrationGcp.clickOptionButton(CIS_GCP_OPTION_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_ORGANIZATION_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID); + await cisIntegrationGcp.clickSaveButton(); + pageObjects.header.waitUntilLoadingHasFinished(); + expect((await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(true)) === true).to.be( + true + ); + }); + + it('Post Installation Google Cloud Shell modal pops up after user clicks on Save button when adding integration, when there are Project ID or Organization ID provided, it should use that value', async () => { + const projectName = 'PRJ_NAME_TEST'; + const organizationName = 'ORG_NAME_TEST'; + await cisIntegrationGcp.clickOptionButton(CIS_GCP_OPTION_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_ORGANIZATION_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID); + await cisIntegrationGcp.fillInTextField('project_id_test_id', projectName); + await cisIntegrationGcp.fillInTextField('organization_id_test_id', organizationName); + + await cisIntegrationGcp.clickSaveButton(); + pageObjects.header.waitUntilLoadingHasFinished(); + expect( + (await cisIntegrationGcp.isPostInstallGoogleCloudShellModal( + true, + organizationName, + projectName + )) === true + ).to.be(true); + }); + + it('Organization ID field on cloud shell command should only be shown if user chose Google Cloud Shell, if user chose Single Account it shouldn not show up', async () => { + await cisIntegrationGcp.clickOptionButton(CIS_GCP_OPTION_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_SINGLE_ACCOUNT_TEST_ID); + await cisIntegrationGcp.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID); + + await cisIntegrationGcp.clickSaveButton(); + pageObjects.header.waitUntilLoadingHasFinished(); + expect((await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(false)) === true).to.be( + true + ); + }); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/pages/index.ts b/x-pack/test/cloud_security_posture_functional/pages/index.ts index c1bcdaea38cf8e..9d4e17ec0c88c9 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/index.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/index.ts @@ -15,5 +15,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./findings_alerts')); loadTestFile(require.resolve('./compliance_dashboard')); loadTestFile(require.resolve('./vulnerability_dashboard')); + loadTestFile(require.resolve('./cis_integration')); }); }