Skip to content

Commit

Permalink
upcoming: [M3-8139, M3-8140, M3-8141] – Add warning notices re: non-e…
Browse files Browse the repository at this point in the history
…ncryption when creating Images & enabling Backups (#10521)
  • Loading branch information
dwiley-akamai authored Jun 3, 2024
1 parent c03915e commit 5abec31
Show file tree
Hide file tree
Showing 9 changed files with 404 additions and 15 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10521-tests-1717099871186.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tests
---

Add unit tests for CreateImageFromDiskDialog and EnableBackupsDialog and LDE-related E2E assertions for Create Image flow ([#10521](https://github.com/linode/manager/pull/10521))
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Add warning notices regarding non-encryption when creating Images and enabling Backups ([#10521](https://github.com/linode/manager/pull/10521))
176 changes: 175 additions & 1 deletion packages/manager/cypress/e2e/core/images/create-image.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,50 @@
import type { Linode } from '@linode/api-v4';
import type { Linode, Region } from '@linode/api-v4';
import { accountFactory, linodeFactory, regionFactory } from 'src/factories';
import { authenticate } from 'support/api/authentication';
import { mockGetAccount } from 'support/intercepts/account';
import {
mockAppendFeatureFlags,
mockGetFeatureFlagClientstream,
} from 'support/intercepts/feature-flags';
import { ui } from 'support/ui';
import { cleanUp } from 'support/util/cleanup';
import { makeFeatureFlagData } from 'support/util/feature-flags';
import { createTestLinode } from 'support/util/linodes';
import { randomLabel, randomPhrase } from 'support/util/random';
import { mockGetRegions } from 'support/intercepts/regions';
import {
mockGetLinodeDetails,
mockGetLinodes,
} from 'support/intercepts/linodes';

const mockRegions: Region[] = [
regionFactory.build({
capabilities: ['Linodes', 'Disk Encryption'],
id: 'us-east',
label: 'Newark, NJ',
site_type: 'core',
}),
regionFactory.build({
capabilities: ['Linodes', 'Disk Encryption'],
id: 'us-den-edge-1',
label: 'Edge - Denver, CO',
site_type: 'edge',
}),
];

const mockLinodes: Linode[] = [
linodeFactory.build({
label: 'core-region-linode',
region: mockRegions[0].id,
}),
linodeFactory.build({
label: 'edge-region-linode',
region: mockRegions[1].id,
}),
];

const DISK_ENCRYPTION_IMAGES_CAVEAT_COPY =
'Virtual Machine Images are not encrypted.';

authenticate();
describe('create image (e2e)', () => {
Expand Down Expand Up @@ -84,4 +125,137 @@ describe('create image (e2e)', () => {
});
});
});

it('displays notice informing user that Images are not encrypted, provided the LDE feature is enabled and the selected linode is not in an Edge region', () => {
// Mock feature flag -- @TODO LDE: Remove feature flag once LDE is fully rolled out
mockAppendFeatureFlags({
linodeDiskEncryption: makeFeatureFlagData(true),
}).as('getFeatureFlags');
mockGetFeatureFlagClientstream().as('getClientStream');

// Mock responses
const mockAccount = accountFactory.build({
capabilities: ['Linodes', 'Disk Encryption'],
});

mockGetAccount(mockAccount).as('getAccount');
mockGetRegions(mockRegions).as('getRegions');
mockGetLinodes(mockLinodes).as('getLinodes');

// intercept request
cy.visitWithLogin('/images/create');
cy.wait([
'@getFeatureFlags',
'@getClientStream',
'@getAccount',
'@getLinodes',
'@getRegions',
]);

// Find the Linode select and open it
cy.findByLabelText('Linode')
.should('be.visible')
.should('be.enabled')
.should('have.attr', 'placeholder', 'Select a Linode')
.click();

// Select the Linode
ui.autocompletePopper
.findByTitle(mockLinodes[0].label)
.should('be.visible')
.should('be.enabled')
.click();

// Check if notice is visible
cy.findByText(DISK_ENCRYPTION_IMAGES_CAVEAT_COPY).should('be.visible');
});

it('does not display a notice informing user that Images are not encrypted if the LDE feature is disabled', () => {
// Mock feature flag -- @TODO LDE: Remove feature flag once LDE is fully rolled out
mockAppendFeatureFlags({
linodeDiskEncryption: makeFeatureFlagData(false),
}).as('getFeatureFlags');
mockGetFeatureFlagClientstream().as('getClientStream');

// Mock responses
const mockAccount = accountFactory.build({
capabilities: ['Linodes', 'Disk Encryption'],
});

mockGetAccount(mockAccount).as('getAccount');
mockGetRegions(mockRegions).as('getRegions');
mockGetLinodes(mockLinodes).as('getLinodes');

// intercept request
cy.visitWithLogin('/images/create');
cy.wait([
'@getFeatureFlags',
'@getClientStream',
'@getAccount',
'@getLinodes',
'@getRegions',
]);

// Find the Linode select and open it
cy.findByLabelText('Linode')
.should('be.visible')
.should('be.enabled')
.should('have.attr', 'placeholder', 'Select a Linode')
.click();

// Select the Linode
ui.autocompletePopper
.findByTitle(mockLinodes[0].label)
.should('be.visible')
.should('be.enabled')
.click();

// Check if notice is visible
cy.findByText(DISK_ENCRYPTION_IMAGES_CAVEAT_COPY).should('not.exist');
});

it('does not display a notice informing user that Images are not encrypted if the selected linode is in an Edge region', () => {
// Mock feature flag -- @TODO LDE: Remove feature flag once LDE is fully rolled out
mockAppendFeatureFlags({
linodeDiskEncryption: makeFeatureFlagData(true),
}).as('getFeatureFlags');
mockGetFeatureFlagClientstream().as('getClientStream');

// Mock responses
const mockAccount = accountFactory.build({
capabilities: ['Linodes', 'Disk Encryption'],
});

mockGetAccount(mockAccount).as('getAccount');
mockGetRegions(mockRegions).as('getRegions');
mockGetLinodes(mockLinodes).as('getLinodes');
mockGetLinodeDetails(mockLinodes[1].id, mockLinodes[1]);

// intercept request
cy.visitWithLogin('/images/create');
cy.wait([
'@getFeatureFlags',
'@getClientStream',
'@getAccount',
'@getRegions',
'@getLinodes',
]);

// Find the Linode select and open it
cy.findByLabelText('Linode')
.should('be.visible')
.should('be.enabled')
.should('have.attr', 'placeholder', 'Select a Linode')
.click();

// Select the Linode
ui.autocompletePopper
.findByTitle(mockLinodes[1].label)
.should('be.visible')
.should('be.enabled')
.click();

// Check if notice is visible
cy.findByText(DISK_ENCRYPTION_IMAGES_CAVEAT_COPY).should('not.exist');
});
});
3 changes: 3 additions & 0 deletions packages/manager/src/components/DiskEncryption/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ export const DISK_ENCRYPTION_BACKUPS_CAVEAT_COPY =

export const DISK_ENCRYPTION_NODE_POOL_GUIDANCE_COPY =
'To enable disk encryption, delete the node pool and create a new node pool. New node pools are always encrypted.';

export const DISK_ENCRYPTION_IMAGES_CAVEAT_COPY =
'Virtual Machine Images are not encrypted.';
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Checkbox } from 'src/components/Checkbox';
import { DISK_ENCRYPTION_IMAGES_CAVEAT_COPY } from 'src/components/DiskEncryption/constants';
import { useIsDiskEncryptionFeatureEnabled } from 'src/components/DiskEncryption/utils';
import { Link } from 'src/components/Link';
import { Notice } from 'src/components/Notice/Notice';
import { Paper } from 'src/components/Paper';
import { getIsEdgeRegion } from 'src/components/RegionSelect/RegionSelect.utils';
import { Stack } from 'src/components/Stack';
import { SupportLink } from 'src/components/SupportLink';
import { TagsInput } from 'src/components/TagsInput/TagsInput';
Expand All @@ -25,7 +28,9 @@ import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGran
import { useEventsPollingActions } from 'src/queries/events/events';
import { useCreateImageMutation } from 'src/queries/images';
import { useAllLinodeDisksQuery } from 'src/queries/linodes/disks';
import { useLinodeQuery } from 'src/queries/linodes/linodes';
import { useGrants } from 'src/queries/profile';
import { useRegionsQuery } from 'src/queries/regions/regions';

export const CreateImageTab = () => {
const [selectedLinodeId, setSelectedLinodeId] = React.useState<null | number>(
Expand Down Expand Up @@ -59,6 +64,10 @@ export const CreateImageTab = () => {
globalGrantType: 'add_images',
});

const {
isDiskEncryptionFeatureEnabled,
} = useIsDiskEncryptionFeatureEnabled();

const onSubmit = handleSubmit(async (values) => {
try {
await createImage(values);
Expand Down Expand Up @@ -92,6 +101,23 @@ export const CreateImageTab = () => {

const isRawDisk = selectedDisk?.filesystem === 'raw';

/*
We only want to display the notice about disk encryption if:
1. the Disk Encryption feature is enabled
2. the selected linode is not in an Edge region
*/
const { data: regionsData } = useRegionsQuery();

const { data: linode } = useLinodeQuery(
selectedLinodeId ?? -1,
Boolean(selectedLinodeId) && isDiskEncryptionFeatureEnabled
);

const linodeIsInEdgeRegion = getIsEdgeRegion(
regionsData ?? [],
linode?.region ?? ''
);

return (
<form onSubmit={onSubmit}>
<Stack spacing={2}>
Expand All @@ -113,7 +139,7 @@ export const CreateImageTab = () => {
<Typography variant="h2">Select Linode & Disk</Typography>
<Typography sx={{ maxWidth: { md: '80%', sm: '100%' } }}>
By default, Linode images are limited to 6144 MB of data per disk.
Ensure your content doesn't exceed this limit, or{' '}
Ensure your content doesn&rsquo;t exceed this limit, or{' '}
<SupportLink
entity={
selectedLinodeId !== null
Expand All @@ -123,9 +149,9 @@ export const CreateImageTab = () => {
text="open a support ticket"
title="Request to increase Image size limit when capturing from Linode disk"
/>{' '}
to request a higher limit. Additionally, images can't be created
from a raw disk or a disk that's formatted using a custom file
system.
to request a higher limit. Additionally, images can&rsquo;t be
created from a raw disk or a disk that&rsquo;s formatted using a
custom file system.
</Typography>
<LinodeSelect
getOptionDisabled={
Expand Down Expand Up @@ -156,6 +182,17 @@ export const CreateImageTab = () => {
required
value={selectedLinodeId}
/>
{isDiskEncryptionFeatureEnabled &&
!linodeIsInEdgeRegion &&
selectedLinodeId !== null && (
<Notice variant="warning">
<Typography
sx={(theme) => ({ fontFamily: theme.font.normal })}
>
{DISK_ENCRYPTION_IMAGES_CAVEAT_COPY}
</Typography>
</Notice>
)}
<Controller
render={({ field, fieldState }) => (
<Autocomplete
Expand Down
Loading

0 comments on commit 5abec31

Please sign in to comment.