From fcfb7d409cce7960fcd0dbafe4cb40a2a23b827a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Mets=C3=A4nheimo?= Date: Thu, 26 Feb 2026 18:26:02 +0200 Subject: [PATCH] fix(schema): support all Unicode letters in tag validation (#7311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * allow international characters in tag regex for UI and schema validation * update validation messages to match this Co-authored-by: Miro Metsänheimo --- .../bruno-app/src/components/TagList/index.js | 6 ++-- .../bruno-schema/src/collections/index.js | 2 +- .../src/collections/itemSchema.spec.js | 34 +++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/bruno-app/src/components/TagList/index.js b/packages/bruno-app/src/components/TagList/index.js index 309aae366..b35af1743 100644 --- a/packages/bruno-app/src/components/TagList/index.js +++ b/packages/bruno-app/src/components/TagList/index.js @@ -7,7 +7,7 @@ import { useTheme } from 'providers/Theme/index'; const TagList = ({ tagsHintList = [], handleAddTag, tags, handleRemoveTag, onSave, handleValidation, collectionFormat }) => { const { displayedTheme } = useTheme(); const isBruFormat = collectionFormat === 'bru'; - const tagNameRegex = isBruFormat ? /^[\w-]+$/ : /^[\w-][\w\s-]*[\w-]$|^[\w-]+$/; + const tagNameRegex = isBruFormat ? /^[\p{L}\p{N}_-]+$/u : /^[\p{L}\p{N}_-](?:[\p{L}\p{N}_\s-]*[\p{L}\p{N}_-])?$/u; const [text, setText] = useState(''); const [error, setError] = useState(''); @@ -22,8 +22,8 @@ const TagList = ({ tagsHintList = [], handleAddTag, tags, handleRemoveTag, onSav } if (!tagNameRegex.test(text)) { setError(isBruFormat - ? 'Tags in BRU format must only contain alpha-numeric characters, "-", "_".' - : 'Tags must only contain alpha-numeric characters, spaces, "-", "_"' + ? 'Tags in BRU format must only contain letters, numbers, "-", "_".' + : 'Tags must only contain letters, numbers, spaces, "-", "_"' ); return; } diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 1fbf149bb..92787067c 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -545,7 +545,7 @@ const itemSchema = Yup.object({ type: Yup.string().oneOf(['http-request', 'graphql-request', 'folder', 'js', 'grpc-request', 'ws-request']).required('type is required'), seq: Yup.number().min(1), name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'), - tags: Yup.array().of(Yup.string().matches(/^[\w-][\w\s-]*[\w-]$|^[\w-]+$/, 'tag must contain only alphanumeric characters, spaces, hyphens, or underscores')), + tags: Yup.array().of(Yup.string().matches(/^[\p{L}\p{N}_-](?:[\p{L}\p{N}_\s-]*[\p{L}\p{N}_-])?$/u, 'tag must contain only letters, numbers, spaces, hyphens, or underscores')), request: Yup.mixed().when('type', { is: (type) => type === 'grpc-request', then: grpcRequestSchema.required('request is required when item-type is grpc-request'), diff --git a/packages/bruno-schema/src/collections/itemSchema.spec.js b/packages/bruno-schema/src/collections/itemSchema.spec.js index 9d52132da..87bd048cf 100644 --- a/packages/bruno-schema/src/collections/itemSchema.spec.js +++ b/packages/bruno-schema/src/collections/itemSchema.spec.js @@ -15,6 +15,40 @@ describe('Item Schema Validation', () => { expect(isValid).toBeTruthy(); }); + it('item schema must validate tag regex rules', async () => { + const validItem = { + uid: uuid(), + name: 'A Folder', + type: 'folder', + tags: ['tag_1', 'Äiti-123 test'] + }; + + const isValid = await itemSchema.validate(validItem); + expect(isValid).toBeTruthy(); + + let invalidItem = { + uid: uuid(), + name: 'A Folder', + type: 'folder', + tags: [' invalid-tag'] + }; + + await expect(itemSchema.validate(invalidItem)).rejects.toThrow( + 'tag must contain only letters, numbers, spaces, hyphens, or underscores' + ); + + invalidItem = { + uid: uuid(), + name: 'A Folder', + type: 'folder', + tags: ['tag🔥name'] + }; + + await expect(itemSchema.validate(invalidItem)).rejects.toThrow( + 'tag must contain only letters, numbers, spaces, hyphens, or underscores' + ); + }); + it('item schema must throw an error if name is missing', async () => { const item = { uid: uuid(),