Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
*/
import React from 'react';
import { render } from '@testing-library/react';
import { CspPolicyTemplateForm } from './policy_template_form';
import {
CspPolicyTemplateForm,
AWS_ORGANIZATION_ACCOUNT,
AWS_SINGLE_ACCOUNT,
} from './policy_template_form';
import { TestProvider } from '../../test/test_provider';
import {
getMockPackageInfoCspmAWS,
Expand Down Expand Up @@ -712,10 +716,10 @@ describe('<CspPolicyTemplateForm />', () => {
});

describe('AWS Credentials input fields', () => {
it(`renders ${CLOUDBEAT_AWS} Account Type field`, () => {
it(`renders ${CLOUDBEAT_AWS} Account Type field, AWS Organization is enabled for supported versions`, () => {
let policy = getMockPolicyAWS();
policy = getPosturePolicy(policy, CLOUDBEAT_AWS, {
'aws.account_type': { value: 'single_account' },
'aws.account_type': { value: AWS_ORGANIZATION_ACCOUNT },
});

const { getByLabelText } = render(
Expand All @@ -724,13 +728,14 @@ describe('<CspPolicyTemplateForm />', () => {

expect(getByLabelText('Single Account')).toBeInTheDocument();
expect(getByLabelText('AWS Organization')).toBeInTheDocument();
expect(getByLabelText('AWS Organization')).toBeEnabled();
});

it(`${CLOUDBEAT_AWS} form displays upgrade message for unsupported versions and aws organization option is disabled`, () => {
let policy = getMockPolicyAWS();
policy = getPosturePolicy(policy, CLOUDBEAT_AWS, {
'aws.credentials.type': { value: 'cloud_formation' },
'aws.account_type': { value: 'single_account' },
'aws.account_type': { value: AWS_SINGLE_ACCOUNT },
});

const { getByText, getByLabelText } = render(
Expand All @@ -743,13 +748,14 @@ describe('<CspPolicyTemplateForm />', () => {
)
).toBeInTheDocument();
expect(getByLabelText('AWS Organization')).toBeDisabled();
expect(getByLabelText('Single Account')).toBeEnabled();
});

it(`${CLOUDBEAT_AWS} form do not displays upgrade message for supported versions and aws organization option is enabled`, () => {
let policy = getMockPolicyAWS();
policy = getPosturePolicy(policy, CLOUDBEAT_AWS, {
'aws.credentials.type': { value: 'cloud_formation' },
'aws.account_type': { value: 'single_account' },
'aws.account_type': { value: AWS_ORGANIZATION_ACCOUNT },
});

const { queryByText, getByLabelText } = render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { memo, useCallback, useEffect, useState } from 'react';
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
import semverCompare from 'semver/functions/compare';
import semverValid from 'semver/functions/valid';
import {
Expand Down Expand Up @@ -79,17 +79,13 @@ interface IntegrationInfoFieldsProps {
onChange(field: string, value: string): void;
}

type AwsAccountType = 'single_account' | 'organization_account';
export const AWS_SINGLE_ACCOUNT = 'single-account';
export const AWS_ORGANIZATION_ACCOUNT = 'organization-account';
type AwsAccountType = typeof AWS_SINGLE_ACCOUNT | typeof AWS_ORGANIZATION_ACCOUNT;

const getAwsAccountTypeOptions = (isAwsOrgDisabled: boolean): CspRadioGroupProps['options'] => [
{
id: 'single_account',
label: i18n.translate('xpack.csp.fleetIntegration.awsAccountType.singleAccountLabel', {
defaultMessage: 'Single Account',
}),
},
{
id: 'organization_account',
id: AWS_ORGANIZATION_ACCOUNT,
label: i18n.translate('xpack.csp.fleetIntegration.awsAccountType.awsOrganizationLabel', {
defaultMessage: 'AWS Organization',
}),
Expand All @@ -100,13 +96,19 @@ const getAwsAccountTypeOptions = (isAwsOrgDisabled: boolean): CspRadioGroupProps
})
: undefined,
},
{
id: AWS_SINGLE_ACCOUNT,
label: i18n.translate('xpack.csp.fleetIntegration.awsAccountType.singleAccountLabel', {
defaultMessage: 'Single Account',
}),
},
];

const getAwsAccountType = (
input: Extract<NewPackagePolicyPostureInput, { type: 'cloudbeat/cis_aws' }>
): AwsAccountType | undefined => input.streams[0].vars?.['aws.account_type']?.value;

const AWS_ORG_MINIMUM_PACKAGE_VERSION = '1.5.0';
const AWS_ORG_MINIMUM_PACKAGE_VERSION = '1.5.0-preview20';

const AwsAccountTypeSelect = ({
input,
Expand All @@ -119,28 +121,30 @@ const AwsAccountTypeSelect = ({
updatePolicy: (updatedPolicy: NewPackagePolicy) => void;
packageInfo: PackageInfo;
}) => {
// This will disable the aws org option for any version LOWER than 1.5.0
// This will disable the aws org option for any version below 1.5.0-preview20 which introduced support for account_type. https://github.com/elastic/integrations/pull/6682
const isValidSemantic = semverValid(packageInfo.version);
const isAwsOrgDisabled = isValidSemantic
? semverCompare(packageInfo.version, AWS_ORG_MINIMUM_PACKAGE_VERSION) < 0
: true;

const awsAccountTypeOptions = getAwsAccountTypeOptions(isAwsOrgDisabled);
const awsAccountTypeOptions = useMemo(
() => getAwsAccountTypeOptions(isAwsOrgDisabled),
[isAwsOrgDisabled]
);

useEffect(() => {
if (!getAwsAccountType(input)) {
updatePolicy(
getPosturePolicy(newPolicy, input.type, {
'aws.account_type': {
value: awsAccountTypeOptions[0].id,
value: isAwsOrgDisabled ? AWS_SINGLE_ACCOUNT : AWS_ORGANIZATION_ACCOUNT,
type: 'text',
},
})
);
}
// we only wish to call this once on mount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [input]);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need this because we have so many calls to updatePolicy when this page mount that each one is overriding the others. I think we should open a tech debt to consolidate all of those calls and create some getInitialValues function that will handle all of that logic on its own.

For now this will run on input change but won't pass the if condition unless account type is not set which is only the case on initial mount.


return (
<>
Expand Down Expand Up @@ -177,6 +181,28 @@ const AwsAccountTypeSelect = ({
}}
size="m"
/>
{getAwsAccountType(input) === AWS_ORGANIZATION_ACCOUNT && (
<>
<EuiSpacer size="l" />
<EuiText color="subdued" size="s">
<FormattedMessage
id="xpack.csp.fleetIntegration.awsAccountType.awsOrganizationDescription"
defaultMessage="Connect Elastic to every AWS Account (current and future) in your environment by providing Elastic with read-only (configuration) access to your AWS organization."
/>
</EuiText>
</>
)}
{getAwsAccountType(input) === AWS_SINGLE_ACCOUNT && (
<>
<EuiSpacer size="l" />
<EuiText color="subdued" size="s">
<FormattedMessage
id="xpack.csp.fleetIntegration.awsAccountType.singleAccountDescription"
defaultMessage="Deploying to a single account is suitable for an initial POC. To ensure complete coverage, it is strongly recommended to deploy CSPM at the organization-level, which automatically connects all accounts (both current and future)."
/>
</EuiText>
</>
)}
<EuiSpacer size="l" />
</>
);
Expand Down