diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/secret-router.ts index 374df8d1d..67fd09ac8 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/secret-router.ts @@ -36,6 +36,12 @@ const SecretReferenceNodeTree: z.ZodType = SecretReference children: z.lazy(() => SecretReferenceNodeTree.array()) }); +const SecretNameSchema = z + .string() + .trim() + .min(1) + .refine((el) => !el.includes(" "), "Secret name cannot contain spaces."); + export const registerSecretRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", @@ -51,7 +57,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim().describe(SECRETS.ATTACH_TAGS.secretName) + secretName: SecretNameSchema.describe(SECRETS.ATTACH_TAGS.secretName) }), body: z.object({ projectSlug: z.string().trim().describe(SECRETS.ATTACH_TAGS.projectSlug), @@ -114,7 +120,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim().describe(SECRETS.DETACH_TAGS.secretName) + secretName: z.string().describe(SECRETS.DETACH_TAGS.secretName) }), body: z.object({ projectSlug: z.string().trim().describe(SECRETS.DETACH_TAGS.projectSlug), @@ -442,7 +448,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim().describe(RAW_SECRETS.CREATE.secretName) + secretName: SecretNameSchema.describe(RAW_SECRETS.CREATE.secretName) }), body: z.object({ workspaceId: z.string().trim().describe(RAW_SECRETS.CREATE.workspaceId), @@ -549,7 +555,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim().describe(RAW_SECRETS.UPDATE.secretName) + secretName: SecretNameSchema.describe(RAW_SECRETS.UPDATE.secretName) }), body: z.object({ workspaceId: z.string().trim().describe(RAW_SECRETS.UPDATE.workspaceId), @@ -575,7 +581,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { .optional() .nullable() .describe(RAW_SECRETS.UPDATE.secretReminderRepeatDays), - newSecretName: z.string().min(1).optional().describe(RAW_SECRETS.UPDATE.newSecretName), + newSecretName: SecretNameSchema.optional().describe(RAW_SECRETS.UPDATE.newSecretName), secretComment: z.string().optional().describe(RAW_SECRETS.UPDATE.secretComment) }), response: { @@ -660,7 +666,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim().describe(RAW_SECRETS.DELETE.secretName) + secretName: z.string().min(1).describe(RAW_SECRETS.DELETE.secretName) }), body: z.object({ workspaceId: z.string().trim().describe(RAW_SECRETS.DELETE.workspaceId), @@ -1855,7 +1861,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { .describe(RAW_SECRETS.CREATE.secretPath), secrets: z .object({ - secretKey: z.string().trim().describe(RAW_SECRETS.CREATE.secretName), + secretKey: SecretNameSchema.describe(RAW_SECRETS.CREATE.secretName), secretValue: z .string() .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) @@ -1956,14 +1962,14 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { .describe(RAW_SECRETS.UPDATE.secretPath), secrets: z .object({ - secretKey: z.string().trim().describe(RAW_SECRETS.UPDATE.secretName), + secretKey: SecretNameSchema.describe(RAW_SECRETS.UPDATE.secretName), secretValue: z .string() .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) .describe(RAW_SECRETS.UPDATE.secretValue), secretComment: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.secretComment), skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.UPDATE.skipMultilineEncoding), - newSecretName: z.string().min(1).optional().describe(RAW_SECRETS.UPDATE.newSecretName), + newSecretName: SecretNameSchema.optional().describe(RAW_SECRETS.UPDATE.newSecretName), tagIds: z.string().array().optional().describe(RAW_SECRETS.UPDATE.tagIds), secretReminderNote: z.string().optional().nullable().describe(RAW_SECRETS.UPDATE.secretReminderNote), secretMetadata: ResourceMetadataSchema.optional(), @@ -2062,7 +2068,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { .describe(RAW_SECRETS.DELETE.secretPath), secrets: z .object({ - secretKey: z.string().trim().describe(RAW_SECRETS.DELETE.secretName), + secretKey: z.string().describe(RAW_SECRETS.DELETE.secretName), type: z.nativeEnum(SecretType).default(SecretType.Shared) }) .array() diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx index 07e41cf04..308f5f1a6 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx @@ -340,7 +340,14 @@ export const OverviewPage = () => { const pathSegment = secretPath.split("/").filter(Boolean); const parentPath = `/${pathSegment.slice(0, -1).join("/")}`; const folderName = pathSegment.at(-1); - if (folderName && parentPath) { + const canCreateFolder = permission.can( + ProjectPermissionActions.Create, + subject(ProjectPermissionSub.SecretFolders, { + environment: env, + secretPath: parentPath + }) + ); + if (folderName && parentPath && canCreateFolder) { await createFolder({ projectId: workspaceId, path: parentPath,