From 294f33bc1e2eb2fc802e0c09e39a76c5cf340c4a Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 23 Sep 2025 02:59:12 +0400 Subject: [PATCH 1/6] fix: allow empty secret names --- backend/src/server/lib/schemas.ts | 8 +++----- frontend/src/components/v2/Input/Input.tsx | 10 ++++++++++ .../components/CreateSecretForm/CreateSecretForm.tsx | 11 +++++++++++ .../components/CreateSecretForm/CreateSecretForm.tsx | 11 +++++++++++ .../components/SecretListView/SecretItem.tsx | 11 +++++++++++ 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/backend/src/server/lib/schemas.ts b/backend/src/server/lib/schemas.ts index 00651d2cc..d0750926d 100644 --- a/backend/src/server/lib/schemas.ts +++ b/backend/src/server/lib/schemas.ts @@ -43,8 +43,6 @@ export const GenericResourceNameSchema = z export const BaseSecretNameSchema = z.string().trim().min(1); export const SecretNameSchema = BaseSecretNameSchema.refine( - (el) => !el.includes(" "), - "Secret name cannot contain spaces." -) - .refine((el) => !el.includes(":"), "Secret name cannot contain colon.") - .refine((el) => !el.includes("/"), "Secret name cannot contain forward slash."); + (el) => !el.includes(":"), + "Secret name cannot contain colon." +).refine((el) => !el.includes("/"), "Secret name cannot contain forward slash."); diff --git a/frontend/src/components/v2/Input/Input.tsx b/frontend/src/components/v2/Input/Input.tsx index d325719e6..f8814f464 100644 --- a/frontend/src/components/v2/Input/Input.tsx +++ b/frontend/src/components/v2/Input/Input.tsx @@ -1,6 +1,9 @@ import { ChangeEvent, forwardRef, InputHTMLAttributes, ReactNode } from "react"; import { cva, VariantProps } from "cva"; import { twMerge } from "tailwind-merge"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faWarning } from "@fortawesome/free-solid-svg-icons"; +import { Tooltip } from "../Tooltip"; type Props = { placeholder?: string; @@ -12,6 +15,7 @@ type Props = { isReadOnly?: boolean; autoCapitalization?: boolean; containerClassName?: string; + warningMessage?: string | ReactNode; }; const inputVariants = cva( @@ -84,6 +88,7 @@ export const Input = forwardRef( size = "md", isReadOnly, autoCapitalization, + warningMessage, ...props }, ref @@ -120,6 +125,11 @@ export const Input = forwardRef( inputVariants({ className, isError, size, isRounded, variant }) )} /> + {warningMessage && !rightIcon && ( + + + + )} {rightIcon && {rightIcon}} ); diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx index d4f8bbafe..af6876de9 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -217,6 +217,17 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { // @ts-expect-error this is for multiple ref single component secretKeyInputRef.current = e; }} + warningMessage={ + secretKey?.includes(" ") ? ( +
+ Secret key contains whitespaces. +
+
If this is the desired format, you need to encode it with{" "} + %20 when making API + requests. +
+ ) : undefined + } placeholder="Type your secret name" onPaste={handlePaste} autoCapitalization={currentProject?.autoCapitalization} diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx index a1ac9c8cb..3378dee01 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -178,6 +178,17 @@ export const CreateSecretForm = ({ // @ts-expect-error this is for multiple ref single component secretKeyInputRef.current = e; }} + warningMessage={ + secretKey?.includes(" ") ? ( +
+ Secret key contains whitespaces. +
+
If this is the desired format, you need to encode it with{" "} + %20 when making API + requests. +
+ ) : undefined + } placeholder="Type your secret name" onPaste={handlePaste} autoCapitalization={autoCapitalize} diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx index 6191e2a18..594899474 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx @@ -487,6 +487,17 @@ export const SecretItem = memo( placeholder={error?.message} isError={Boolean(error)} onKeyUp={() => trigger("key")} + warningMessage={ + field.value.includes(" ") ? ( +
+ Secret key contains whitespaces. +
+
If this is the desired format, you need to encode it with{" "} + %20 when + making API requests. +
+ ) : undefined + } {...field} className="w-full px-0 placeholder:text-red-500 focus:text-bunker-100 focus:ring-transparent" /> From 2fac3c19b1e0da607a69fcf92bc25835c3b3cabf Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 23 Sep 2025 04:08:23 +0400 Subject: [PATCH 2/6] fix: re-add secret key space support --- frontend/src/components/v2/Input/Input.tsx | 2 +- .../components/CreateSecretForm/CreateSecretForm.tsx | 8 +++++--- .../components/CreateSecretForm/CreateSecretForm.tsx | 8 +++++--- .../components/SecretListView/SecretItem.tsx | 10 ++++++---- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/v2/Input/Input.tsx b/frontend/src/components/v2/Input/Input.tsx index f8814f464..019c80614 100644 --- a/frontend/src/components/v2/Input/Input.tsx +++ b/frontend/src/components/v2/Input/Input.tsx @@ -126,7 +126,7 @@ export const Input = forwardRef( )} /> {warningMessage && !rightIcon && ( - + )} diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx index af6876de9..2dc1ddcb0 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -222,9 +222,11 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
Secret key contains whitespaces.
-
If this is the desired format, you need to encode it with{" "} - %20 when making API - requests. +
If this is the desired format, you need to provide it as{" "} + + {secretKey.trim().replaceAll(" ", "%20")} + {" "} + when making API requests.
) : undefined } diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx index 3378dee01..82cc6b5e0 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -183,9 +183,11 @@ export const CreateSecretForm = ({
Secret key contains whitespaces.
-
If this is the desired format, you need to encode it with{" "} - %20 when making API - requests. +
If this is the desired format, you need to provide it as{" "} + + {secretKey.trim().replaceAll(" ", "%20")} + {" "} + when making API requests.
) : undefined } diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx index 594899474..20c4c34b4 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx @@ -488,13 +488,15 @@ export const SecretItem = memo( isError={Boolean(error)} onKeyUp={() => trigger("key")} warningMessage={ - field.value.includes(" ") ? ( + field.value?.includes(" ") ? (
Secret key contains whitespaces.
-
If this is the desired format, you need to encode it with{" "} - %20 when - making API requests. +
If this is the desired format, you need to provide it as{" "} + + {field.value.trim().replaceAll(" ", "%20")} + {" "} + when making API requests.
) : undefined } From b73d6fcbe8b8837ed85ec26d014f0ecebcc5bbe4 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 23 Sep 2025 05:07:00 +0400 Subject: [PATCH 3/6] requested changes --- frontend/src/components/v2/Input/Input.tsx | 13 ++----- .../CreateSecretForm/CreateSecretForm.tsx | 35 ++++++++++++------- .../CreateSecretForm/CreateSecretForm.tsx | 34 +++++++++++------- .../components/SecretListView/SecretItem.tsx | 32 +++++++++++------ 4 files changed, 69 insertions(+), 45 deletions(-) diff --git a/frontend/src/components/v2/Input/Input.tsx b/frontend/src/components/v2/Input/Input.tsx index 019c80614..398c6410d 100644 --- a/frontend/src/components/v2/Input/Input.tsx +++ b/frontend/src/components/v2/Input/Input.tsx @@ -1,9 +1,6 @@ import { ChangeEvent, forwardRef, InputHTMLAttributes, ReactNode } from "react"; import { cva, VariantProps } from "cva"; import { twMerge } from "tailwind-merge"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faWarning } from "@fortawesome/free-solid-svg-icons"; -import { Tooltip } from "../Tooltip"; type Props = { placeholder?: string; @@ -15,7 +12,7 @@ type Props = { isReadOnly?: boolean; autoCapitalization?: boolean; containerClassName?: string; - warningMessage?: string | ReactNode; + warning?: ReactNode; }; const inputVariants = cva( @@ -88,7 +85,7 @@ export const Input = forwardRef( size = "md", isReadOnly, autoCapitalization, - warningMessage, + warning, ...props }, ref @@ -125,11 +122,7 @@ export const Input = forwardRef( inputVariants({ className, isError, size, isRounded, variant }) )} /> - {warningMessage && !rightIcon && ( - - - - )} + {Boolean(warning) && !rightIcon && warning} {rightIcon && {rightIcon}} ); diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx index 2dc1ddcb0..7c993ee8b 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -1,7 +1,7 @@ import { ClipboardEvent, useRef } from "react"; import { Controller, useForm } from "react-hook-form"; import { subject } from "@casl/ability"; -import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; +import { faTriangleExclamation, faWarning } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; @@ -12,7 +12,8 @@ import { FilterableSelect, FormControl, Input, - PasswordGenerator + PasswordGenerator, + Tooltip } from "@app/components/v2"; import { CreatableSelect } from "@app/components/v2/CreatableSelect"; import { InfisicalSecretInput } from "@app/components/v2/InfisicalSecretInput"; @@ -217,17 +218,27 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { // @ts-expect-error this is for multiple ref single component secretKeyInputRef.current = e; }} - warningMessage={ + warning={ secretKey?.includes(" ") ? ( -
- Secret key contains whitespaces. -
-
If this is the desired format, you need to provide it as{" "} - - {secretKey.trim().replaceAll(" ", "%20")} - {" "} - when making API requests. -
+ + Secret key contains whitespaces. +
+
If this is the desired format, you need to provide it as{" "} + + {encodeURIComponent(secretKey.trim())} + {" "} + when making API requests. + + } + > + +
) : undefined } placeholder="Type your secret name" diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx index 82cc6b5e0..c54f63f84 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -1,12 +1,12 @@ import { ClipboardEvent, useRef } from "react"; import { Controller, useForm } from "react-hook-form"; -import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; +import { faTriangleExclamation, faWarning } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; -import { Button, FormControl, Input, PasswordGenerator } from "@app/components/v2"; +import { Button, FormControl, Input, PasswordGenerator, Tooltip } from "@app/components/v2"; import { CreatableSelect } from "@app/components/v2/CreatableSelect"; import { InfisicalSecretInput } from "@app/components/v2/InfisicalSecretInput"; import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission } from "@app/context"; @@ -178,17 +178,27 @@ export const CreateSecretForm = ({ // @ts-expect-error this is for multiple ref single component secretKeyInputRef.current = e; }} - warningMessage={ + warning={ secretKey?.includes(" ") ? ( -
- Secret key contains whitespaces. -
-
If this is the desired format, you need to provide it as{" "} - - {secretKey.trim().replaceAll(" ", "%20")} - {" "} - when making API requests. -
+ + Secret key contains whitespaces. +
+
If this is the desired format, you need to provide it as{" "} + + {encodeURIComponent(secretKey.trim())} + {" "} + when making API requests. + + } + > + +
) : undefined } placeholder="Type your secret name" diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx index 20c4c34b4..f9b18422a 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx @@ -43,7 +43,7 @@ import { twMerge } from "tailwind-merge"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { hasSecretReadValueOrDescribePermission } from "@app/lib/fn/permission"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faEyeSlash, faKey, faRotate } from "@fortawesome/free-solid-svg-icons"; +import { faEyeSlash, faKey, faRotate, faWarning } from "@fortawesome/free-solid-svg-icons"; import { PendingAction } from "@app/hooks/api/secretFolders/types"; import { format } from "date-fns"; import { CreateReminderForm } from "@app/pages/secret-manager/SecretDashboardPage/components/SecretListView/CreateReminderForm"; @@ -487,17 +487,27 @@ export const SecretItem = memo( placeholder={error?.message} isError={Boolean(error)} onKeyUp={() => trigger("key")} - warningMessage={ + warning={ field.value?.includes(" ") ? ( -
- Secret key contains whitespaces. -
-
If this is the desired format, you need to provide it as{" "} - - {field.value.trim().replaceAll(" ", "%20")} - {" "} - when making API requests. -
+ + Secret key contains whitespaces. +
+
If this is the desired format, you need to provide it as{" "} + + {encodeURIComponent(field.value.trim())} + {" "} + when making API requests. + + } + > + +
) : undefined } {...field} From b09c4d6be559aa5e188d0ef1cfe4c24a32b271b5 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 23 Sep 2025 23:18:46 +0400 Subject: [PATCH 4/6] Update SecretItem.tsx --- .../components/SecretListView/SecretItem.tsx | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx index f9b18422a..4f64d950d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx @@ -487,29 +487,6 @@ export const SecretItem = memo( placeholder={error?.message} isError={Boolean(error)} onKeyUp={() => trigger("key")} - warning={ - field.value?.includes(" ") ? ( - - Secret key contains whitespaces. -
-
If this is the desired format, you need to provide it as{" "} - - {encodeURIComponent(field.value.trim())} - {" "} - when making API requests. - - } - > - -
- ) : undefined - } {...field} className="w-full px-0 placeholder:text-red-500 focus:text-bunker-100 focus:ring-transparent" /> From 9948cdb3797c2d943b2d9d6e279956994ec1726a Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 23 Sep 2025 23:36:24 +0400 Subject: [PATCH 5/6] requested changes --- frontend/src/components/v2/Input/Input.tsx | 2 +- .../components/SecretListView/SecretItem.tsx | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/v2/Input/Input.tsx b/frontend/src/components/v2/Input/Input.tsx index 398c6410d..fa3982abd 100644 --- a/frontend/src/components/v2/Input/Input.tsx +++ b/frontend/src/components/v2/Input/Input.tsx @@ -118,7 +118,7 @@ export const Input = forwardRef( onInput={handleInput} className={twMerge( leftIcon ? "pl-10" : "pl-2.5", - rightIcon ? "pr-10" : "pr-2.5", + rightIcon || warning ? "pr-10" : "pr-2.5", inputVariants({ className, isError, size, isRounded, variant }) )} /> diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx index 4f64d950d..8e40ef40d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx @@ -487,6 +487,30 @@ export const SecretItem = memo( placeholder={error?.message} isError={Boolean(error)} onKeyUp={() => trigger("key")} + warning={ + field?.value !== (originalSecret.originalKey || originalSecret.key) && + field.value?.includes(" ") ? ( + + Secret key contains whitespaces. +
+
If this is the desired format, you need to provide it as{" "} + + {encodeURIComponent(field.value.trim())} + {" "} + when making API requests. + + } + > + +
+ ) : undefined + } {...field} className="w-full px-0 placeholder:text-red-500 focus:text-bunker-100 focus:ring-transparent" /> From e5c381223930a8d80876b4acfd614e367551b49f Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 23 Sep 2025 23:58:35 +0400 Subject: [PATCH 6/6] Update SecretRenameRow.tsx --- .../SecretRenameRow.tsx | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx index 5e1f27f57..37ff5aadf 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx @@ -1,7 +1,7 @@ import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; import { subject } from "@casl/ability"; -import { faCheck, faClose, faCopy } from "@fortawesome/free-solid-svg-icons"; +import { faCheck, faClose, faCopy, faWarning } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; import { AnimatePresence, motion } from "framer-motion"; @@ -78,6 +78,7 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath } control, reset, trigger, + watch, getValues, formState: { isDirty, isSubmitting, errors } } = useForm({ @@ -145,14 +146,35 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath } setIsSecNameCopied.on(); }; + const currentSecretValue = watch("key"); + return (
- + Key + {currentSecretValue?.trim()?.includes(" ") && + currentSecretValue?.trim() !== secretKey && ( + + Secret key contains whitespaces. +
+
If this is the desired format, you need to provide it as{" "} + + {encodeURIComponent(secretKey.trim())} + {" "} + when making API requests. +
+ } + > + + + )}