mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-10 05:55:18 +00:00
feat(validation): add branch name validation across provider schemas
- Introduced a regex validation for branch names in Bitbucket, Git, Gitea, GitHub, and GitLab provider schemas to ensure valid branch formats. - Updated the corresponding schemas to include the new validation rule, enhancing input integrity and preventing potential errors. - Added a utility for branch validation in the server utils.
This commit is contained in:
+2
-1
@@ -5,6 +5,7 @@ import { useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -57,7 +58,7 @@ const BitbucketProviderSchema = z.object({
|
|||||||
slug: z.string().optional(),
|
slug: z.string().optional(),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z.string().min(1, "Branch is required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
bitbucketId: z.string().min(1, "Bitbucket Provider is required"),
|
bitbucketId: z.string().min(1, "Bitbucket Provider is required"),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
enableSubmodules: z.boolean().optional(),
|
enableSubmodules: z.boolean().optional(),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { GitIcon } from "@/components/icons/data-tools-icons";
|
import { GitIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -41,7 +42,7 @@ const GitProviderSchema = z.object({
|
|||||||
repositoryURL: z.string().min(1, {
|
repositoryURL: z.string().min(1, {
|
||||||
message: "Repository URL is required",
|
message: "Repository URL is required",
|
||||||
}),
|
}),
|
||||||
branch: z.string().min(1, "Branch required"),
|
branch: z.string().min(1, "Branch required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
sshKey: z.string().optional(),
|
sshKey: z.string().optional(),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
enableSubmodules: z.boolean().default(false),
|
enableSubmodules: z.boolean().default(false),
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ import { useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { GiteaIcon } from "@/components/icons/data-tools-icons";
|
import { GiteaIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -72,7 +73,7 @@ const GiteaProviderSchema = z.object({
|
|||||||
owner: z.string().min(1, "Owner is required"),
|
owner: z.string().min(1, "Owner is required"),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z.string().min(1, "Branch is required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
giteaId: z.string().min(1, "Gitea Provider is required"),
|
giteaId: z.string().min(1, "Gitea Provider is required"),
|
||||||
watchPaths: z.array(z.string()).default([]),
|
watchPaths: z.array(z.string()).default([]),
|
||||||
enableSubmodules: z.boolean().optional(),
|
enableSubmodules: z.boolean().optional(),
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ import { useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { GithubIcon } from "@/components/icons/data-tools-icons";
|
import { GithubIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -55,7 +56,7 @@ const GithubProviderSchema = z.object({
|
|||||||
owner: z.string().min(1, "Owner is required"),
|
owner: z.string().min(1, "Owner is required"),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z.string().min(1, "Branch is required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
githubId: z.string().min(1, "Github Provider is required"),
|
githubId: z.string().min(1, "Github Provider is required"),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
triggerType: z.enum(["push", "tag"]).default("push"),
|
triggerType: z.enum(["push", "tag"]).default("push"),
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ import { useEffect, useMemo } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -58,7 +59,7 @@ const GitlabProviderSchema = z.object({
|
|||||||
id: z.number().nullable(),
|
id: z.number().nullable(),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z.string().min(1, "Branch is required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
gitlabId: z.string().min(1, "Gitlab Provider is required"),
|
gitlabId: z.string().min(1, "Gitlab Provider is required"),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
enableSubmodules: z.boolean().default(false),
|
enableSubmodules: z.boolean().default(false),
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ import { useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
import { BitbucketIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -57,7 +58,7 @@ const BitbucketProviderSchema = z.object({
|
|||||||
slug: z.string().optional(),
|
slug: z.string().optional(),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z.string().min(1, "Branch is required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
bitbucketId: z.string().min(1, "Bitbucket Provider is required"),
|
bitbucketId: z.string().min(1, "Bitbucket Provider is required"),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
enableSubmodules: z.boolean().default(false),
|
enableSubmodules: z.boolean().default(false),
|
||||||
|
|||||||
+2
-1
@@ -6,6 +6,7 @@ import { useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { GitIcon } from "@/components/icons/data-tools-icons";
|
import { GitIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -41,7 +42,7 @@ const GitProviderSchema = z.object({
|
|||||||
repositoryURL: z.string().min(1, {
|
repositoryURL: z.string().min(1, {
|
||||||
message: "Repository URL is required",
|
message: "Repository URL is required",
|
||||||
}),
|
}),
|
||||||
branch: z.string().min(1, "Branch required"),
|
branch: z.string().min(1, "Branch required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
sshKey: z.string().optional(),
|
sshKey: z.string().optional(),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
enableSubmodules: z.boolean().default(false),
|
enableSubmodules: z.boolean().default(false),
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ import { useEffect } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { GiteaIcon } from "@/components/icons/data-tools-icons";
|
import { GiteaIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -57,7 +58,7 @@ const GiteaProviderSchema = z.object({
|
|||||||
owner: z.string().min(1, "Owner is required"),
|
owner: z.string().min(1, "Owner is required"),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z.string().min(1, "Branch is required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
giteaId: z.string().min(1, "Gitea Provider is required"),
|
giteaId: z.string().min(1, "Gitea Provider is required"),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
enableSubmodules: z.boolean().default(false),
|
enableSubmodules: z.boolean().default(false),
|
||||||
|
|||||||
+5
-1
@@ -1,3 +1,4 @@
|
|||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
|
import { standardSchemaResolver as zodResolver } from "@hookform/resolvers/standard-schema";
|
||||||
import { CheckIcon, ChevronsUpDown, HelpCircle, X } from "lucide-react";
|
import { CheckIcon, ChevronsUpDown, HelpCircle, X } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@@ -55,7 +56,10 @@ const GithubProviderSchema = z.object({
|
|||||||
owner: z.string().min(1, "Owner is required"),
|
owner: z.string().min(1, "Owner is required"),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z
|
||||||
|
.string()
|
||||||
|
.min(1, "Branch is required")
|
||||||
|
.regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
githubId: z.string().min(1, "Github Provider is required"),
|
githubId: z.string().min(1, "Github Provider is required"),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
triggerType: z.enum(["push", "tag"]).default("push"),
|
triggerType: z.enum(["push", "tag"]).default("push"),
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ import { useEffect, useMemo } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
import { GitlabIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -58,7 +59,7 @@ const GitlabProviderSchema = z.object({
|
|||||||
gitlabPathNamespace: z.string().min(1),
|
gitlabPathNamespace: z.string().min(1),
|
||||||
})
|
})
|
||||||
.required(),
|
.required(),
|
||||||
branch: z.string().min(1, "Branch is required"),
|
branch: z.string().min(1, "Branch is required").regex(VALID_BRANCH_REGEX, "Invalid branch name"),
|
||||||
gitlabId: z.string().min(1, "Gitlab Provider is required"),
|
gitlabId: z.string().min(1, "Gitlab Provider is required"),
|
||||||
watchPaths: z.array(z.string()).optional(),
|
watchPaths: z.array(z.string()).optional(),
|
||||||
enableSubmodules: z.boolean().default(false),
|
enableSubmodules: z.boolean().default(false),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation";
|
||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
bigint,
|
bigint,
|
||||||
@@ -432,17 +433,22 @@ export const apiSaveBuildType = createSchema
|
|||||||
.required()
|
.required()
|
||||||
.merge(createSchema.pick({ publishDirectory: true, isStaticSpa: true }));
|
.merge(createSchema.pick({ publishDirectory: true, isStaticSpa: true }));
|
||||||
|
|
||||||
|
const branchField = z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.regex(VALID_BRANCH_REGEX, "Invalid branch name");
|
||||||
|
|
||||||
export const apiSaveGithubProvider = createSchema
|
export const apiSaveGithubProvider = createSchema
|
||||||
.pick({
|
.pick({
|
||||||
applicationId: true,
|
applicationId: true,
|
||||||
repository: true,
|
repository: true,
|
||||||
branch: true,
|
|
||||||
owner: true,
|
owner: true,
|
||||||
buildPath: true,
|
buildPath: true,
|
||||||
githubId: true,
|
githubId: true,
|
||||||
})
|
})
|
||||||
.required()
|
.required()
|
||||||
.extend({
|
.extend({
|
||||||
|
branch: branchField,
|
||||||
triggerType: z.enum(["push", "tag"]).default("push"),
|
triggerType: z.enum(["push", "tag"]).default("push"),
|
||||||
})
|
})
|
||||||
.required()
|
.required()
|
||||||
@@ -451,7 +457,6 @@ export const apiSaveGithubProvider = createSchema
|
|||||||
export const apiSaveGitlabProvider = createSchema
|
export const apiSaveGitlabProvider = createSchema
|
||||||
.pick({
|
.pick({
|
||||||
applicationId: true,
|
applicationId: true,
|
||||||
gitlabBranch: true,
|
|
||||||
gitlabBuildPath: true,
|
gitlabBuildPath: true,
|
||||||
gitlabOwner: true,
|
gitlabOwner: true,
|
||||||
gitlabRepository: true,
|
gitlabRepository: true,
|
||||||
@@ -460,11 +465,11 @@ export const apiSaveGitlabProvider = createSchema
|
|||||||
gitlabPathNamespace: true,
|
gitlabPathNamespace: true,
|
||||||
})
|
})
|
||||||
.required()
|
.required()
|
||||||
|
.extend({ gitlabBranch: branchField })
|
||||||
.merge(createSchema.pick({ enableSubmodules: true, watchPaths: true }));
|
.merge(createSchema.pick({ enableSubmodules: true, watchPaths: true }));
|
||||||
|
|
||||||
export const apiSaveBitbucketProvider = createSchema
|
export const apiSaveBitbucketProvider = createSchema
|
||||||
.pick({
|
.pick({
|
||||||
bitbucketBranch: true,
|
|
||||||
bitbucketBuildPath: true,
|
bitbucketBuildPath: true,
|
||||||
bitbucketOwner: true,
|
bitbucketOwner: true,
|
||||||
bitbucketRepository: true,
|
bitbucketRepository: true,
|
||||||
@@ -473,18 +478,19 @@ export const apiSaveBitbucketProvider = createSchema
|
|||||||
applicationId: true,
|
applicationId: true,
|
||||||
})
|
})
|
||||||
.required()
|
.required()
|
||||||
|
.extend({ bitbucketBranch: branchField })
|
||||||
.merge(createSchema.pick({ enableSubmodules: true, watchPaths: true }));
|
.merge(createSchema.pick({ enableSubmodules: true, watchPaths: true }));
|
||||||
|
|
||||||
export const apiSaveGiteaProvider = createSchema
|
export const apiSaveGiteaProvider = createSchema
|
||||||
.pick({
|
.pick({
|
||||||
applicationId: true,
|
applicationId: true,
|
||||||
giteaBranch: true,
|
|
||||||
giteaBuildPath: true,
|
giteaBuildPath: true,
|
||||||
giteaOwner: true,
|
giteaOwner: true,
|
||||||
giteaRepository: true,
|
giteaRepository: true,
|
||||||
giteaId: true,
|
giteaId: true,
|
||||||
})
|
})
|
||||||
.required()
|
.required()
|
||||||
|
.extend({ giteaBranch: branchField })
|
||||||
.merge(createSchema.pick({ enableSubmodules: true, watchPaths: true }));
|
.merge(createSchema.pick({ enableSubmodules: true, watchPaths: true }));
|
||||||
|
|
||||||
export const apiSaveDockerProvider = createSchema
|
export const apiSaveDockerProvider = createSchema
|
||||||
@@ -499,7 +505,6 @@ export const apiSaveDockerProvider = createSchema
|
|||||||
|
|
||||||
export const apiSaveGitProvider = createSchema
|
export const apiSaveGitProvider = createSchema
|
||||||
.pick({
|
.pick({
|
||||||
customGitBranch: true,
|
|
||||||
applicationId: true,
|
applicationId: true,
|
||||||
customGitBuildPath: true,
|
customGitBuildPath: true,
|
||||||
customGitUrl: true,
|
customGitUrl: true,
|
||||||
@@ -507,6 +512,7 @@ export const apiSaveGitProvider = createSchema
|
|||||||
enableSubmodules: true,
|
enableSubmodules: true,
|
||||||
})
|
})
|
||||||
.required()
|
.required()
|
||||||
|
.extend({ customGitBranch: branchField })
|
||||||
.merge(
|
.merge(
|
||||||
createSchema.pick({
|
createSchema.pick({
|
||||||
customGitSSHKeyId: true,
|
customGitSSHKeyId: true,
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export * from "./utils/notifications/docker-cleanup";
|
|||||||
export * from "./utils/notifications/dokploy-restart";
|
export * from "./utils/notifications/dokploy-restart";
|
||||||
export * from "./utils/notifications/server-threshold";
|
export * from "./utils/notifications/server-threshold";
|
||||||
export * from "./utils/notifications/utils";
|
export * from "./utils/notifications/utils";
|
||||||
|
export * from "./utils/git-branch-validation";
|
||||||
export * from "./utils/process/execAsync";
|
export * from "./utils/process/execAsync";
|
||||||
export * from "./utils/process/spawnAsync";
|
export * from "./utils/process/spawnAsync";
|
||||||
export * from "./utils/providers/bitbucket";
|
export * from "./utils/providers/bitbucket";
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// Valid git branch names per git-check-ref-format rules.
|
||||||
|
// Rejects shell metacharacters that would enable command injection.
|
||||||
|
export const VALID_BRANCH_REGEX = /^[a-zA-Z0-9._\-/]+$/;
|
||||||
Reference in New Issue
Block a user