Skip to content

Commit c98a99c

Browse files
authored
updated regex and validation to properly catch non-compliant DNS-1035 labels (#3681)
1 parent dc692b5 commit c98a99c

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

frontend/src/concepts/k8s/__tests__/utils.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
translateDisplayNameForK8s,
88
translateDisplayNameForK8sAndReport,
99
} from '~/concepts/k8s/utils';
10+
import { K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR } from '~/pages/projects/screens/spawner/const';
1011

1112
describe('getDisplayNameFromK8sResource', () => {
1213
it('gets the display name when present', () => {
@@ -49,6 +50,10 @@ describe('translateDisplayNameForK8s', () => {
4950
expect(translateDisplayNameForK8s('-1234', { safeK8sPrefix: 'wb-' })).toBe('wb-1234');
5051
expect(translateDisplayNameForK8s('-1-', { safeK8sPrefix: 'wb-' })).toBe('wb-1');
5152
expect(translateDisplayNameForK8s('1-', { safeK8sPrefix: 'wb-' })).toBe('wb-1');
53+
expect(translateDisplayNameForK8s('213-workbench-1-tls', { safeK8sPrefix: 'wb-' })).toBe(
54+
'wb-213-workbench-1-tls',
55+
);
56+
expect(translateDisplayNameForK8s('$-12hello', { safeK8sPrefix: 'wb-' })).toBe('wb-12hello');
5257
expect(translateDisplayNameForK8s('-validcharacters')).toBe(`validcharacters`);
5358
});
5459
});
@@ -160,3 +165,37 @@ describe('isValidK8sName', () => {
160165
expect(isValidK8sName('ymbols--capitals-and-spaces-these-are-invalid')).toBe(true);
161166
});
162167
});
168+
169+
describe('isValidK8sName for Notebook resource names', () => {
170+
it('identifies invalid names', () => {
171+
expect(isValidK8sName('', K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(false);
172+
expect(isValidK8sName('Test Project 1', K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(false);
173+
expect(isValidK8sName("John Doe's Cool Project!", K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(
174+
false,
175+
);
176+
expect(
177+
isValidK8sName(
178+
'$ymbols & Capitals and Spaces! (These are invalid!)',
179+
K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR,
180+
),
181+
).toBe(false);
182+
expect(isValidK8sName('--213-workbench-1-tls', K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(
183+
false,
184+
);
185+
expect(isValidK8sName('1234', K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(false);
186+
expect(isValidK8sName('213-workbench-1-tls', K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(false);
187+
});
188+
189+
it('identifies valid names', () => {
190+
expect(isValidK8sName('test-project-1', K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(true);
191+
expect(isValidK8sName('john-does-cool-project', K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR)).toBe(
192+
true,
193+
);
194+
expect(
195+
isValidK8sName(
196+
'ymbols--capitals-and-spaces-these-are-invalid',
197+
K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR,
198+
),
199+
).toBe(true);
200+
});
201+
});

frontend/src/concepts/k8s/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ export const translateDisplayNameForK8sAndReport = (
5757
let translatedName = name
5858
.trim()
5959
.toLowerCase()
60-
.replace(/^-*/, '') // remove any leading dashes
61-
.replace(/-*$/, '') // remove any trailing dashes
6260
.replace(/\s/g, '-') // spaces to dashes
6361
.replace(/[^a-z0-9-]/g, '') // remove inverse of good k8s characters
62+
.replace(/^-*/, '') // remove any leading dashes
63+
.replace(/-*$/, '') // remove any trailing dashes
6464
.replace(/[-]+/g, '-'); // simplify double dashes ('A - B' turns into 'a---b' where 'a-b' is enough)
6565

6666
/** Allows constant length checks -- modifies translatedName & appliedCriteria */
@@ -84,8 +84,8 @@ export const translateDisplayNameForK8sAndReport = (
8484
}
8585
appliedCriteria.safeK8sPrefix = true;
8686
appliedCriteria.staticPrefix = true;
87-
} else if (/^\d+$/.test(translatedName)) {
88-
// Avoid pure digit names
87+
} else if (/^\d+/.test(translatedName)) {
88+
// Avoid names that start with a digit
8989
translatedName = `${safeK8sPrefix}${translatedName}`;
9090
appliedCriteria.safeK8sPrefix = true;
9191
}

frontend/src/pages/projects/screens/spawner/SpawnerPage.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ import useNotebookPVCItems from '~/pages/projects/pvc/useNotebookPVCItems';
3737
import { getNotebookPVCMountPathMap } from '~/pages/projects/notebook/utils';
3838
import { getNotebookPVCNames } from '~/pages/projects/pvc/utils';
3939
import { SpawnerPageSectionID } from './types';
40-
import { ScrollableSelectorID, SpawnerPageSectionTitles } from './const';
40+
import {
41+
K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR,
42+
ScrollableSelectorID,
43+
SpawnerPageSectionTitles,
44+
} from './const';
4145
import SpawnerFooter from './SpawnerFooter';
4246
import ImageSelectorField from './imageSelector/ImageSelectorField';
4347
import ContainerSizeSelector from './deploymentSize/ContainerSizeSelector';
@@ -76,6 +80,7 @@ const SpawnerPage: React.FC<SpawnerPageProps> = ({ existingNotebook }) => {
7680
initialData: existingNotebook,
7781
limitNameResourceType: LimitNameResourceType.WORKBENCH,
7882
safePrefix: 'wb-',
83+
regexp: K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR,
7984
});
8085
const [isAttachStorageModalOpen, setIsAttachStorageModalOpen] = React.useState(false);
8186
const [isCreateStorageModalOpen, setIsCreateStorageModalOpen] = React.useState(false);

frontend/src/pages/projects/screens/spawner/const.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const ScrollableSelectorID = 'workbench-spawner-page';
1414

1515
export const FAILED_PHASES = [BuildPhase.ERROR, BuildPhase.FAILED];
1616
export const PENDING_PHASES = [BuildPhase.NEW, BuildPhase.PENDING, BuildPhase.CANCELLED];
17+
export const K8_NOTEBOOK_RESOURCE_NAME_VALIDATOR = /^[a-z]([-a-z0-9]*[a-z0-9])?$/;
1718

1819
// TODO: Convert to enum
1920
export const IMAGE_ANNOTATIONS = {

0 commit comments

Comments
 (0)