From dfff91c6f3bb9f6d084195e0e3fa704052488c74 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Tue, 16 Jun 2026 07:12:40 -0600 Subject: [PATCH] fix: support hashtag and special chars in branch names for git clone Branch names were interpolated unquoted into the git clone shell command, so a `#` (valid in git branch names) started a shell comment and dropped the rest of the command, causing the clone to fail (#4585). Escape the branch name with shell-quote (already a dependency) across all providers: gitlab, github, gitea, bitbucket and custom git. --- packages/server/src/utils/providers/bitbucket.ts | 3 ++- packages/server/src/utils/providers/git.ts | 3 ++- packages/server/src/utils/providers/gitea.ts | 3 ++- packages/server/src/utils/providers/github.ts | 3 ++- packages/server/src/utils/providers/gitlab.ts | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/server/src/utils/providers/bitbucket.ts b/packages/server/src/utils/providers/bitbucket.ts index d2be27a677..10b15ca022 100644 --- a/packages/server/src/utils/providers/bitbucket.ts +++ b/packages/server/src/utils/providers/bitbucket.ts @@ -10,6 +10,7 @@ import { } from "@dokploy/server/services/bitbucket"; import type { InferResultType } from "@dokploy/server/types/with"; import { TRPCError } from "@trpc/server"; +import { quote } from "shell-quote"; import type { z } from "zod"; export type ApplicationWithBitbucket = InferResultType< @@ -125,7 +126,7 @@ export const cloneBitbucketRepository = async ({ const repoclone = `bitbucket.org/${bitbucketOwner}/${repoToUse}.git`; const cloneUrl = getBitbucketCloneUrl(bitbucket, repoclone); command += `echo "Cloning Repo ${repoclone} to ${outputPath}: ✅";`; - command += `git clone --branch ${bitbucketBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; + command += `git clone --branch ${quote([bitbucketBranch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; return command; }; diff --git a/packages/server/src/utils/providers/git.ts b/packages/server/src/utils/providers/git.ts index 4c06109217..13544efb29 100644 --- a/packages/server/src/utils/providers/git.ts +++ b/packages/server/src/utils/providers/git.ts @@ -4,6 +4,7 @@ import { findSSHKeyById, updateSSHKeyById, } from "@dokploy/server/services/ssh-key"; +import { quote } from "shell-quote"; import { execAsync, execAsyncRemote } from "../process/execAsync"; interface CloneGitRepository { @@ -78,7 +79,7 @@ export const cloneGitRepository = async ({ command += "chmod 600 /tmp/id_rsa;"; command += `export GIT_SSH_COMMAND="${gitSshCommand}";`; } - command += `if ! git clone --branch ${customGitBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${customGitUrl} ${outputPath}; then + command += `if ! git clone --branch ${quote([customGitBranch ?? ""])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${customGitUrl} ${outputPath}; then echo "❌ [ERROR] Fail to clone the repository ${customGitUrl}"; exit 1; fi diff --git a/packages/server/src/utils/providers/gitea.ts b/packages/server/src/utils/providers/gitea.ts index 20c86a5895..b7750915d8 100644 --- a/packages/server/src/utils/providers/gitea.ts +++ b/packages/server/src/utils/providers/gitea.ts @@ -7,6 +7,7 @@ import { } from "@dokploy/server/services/gitea"; import type { InferResultType } from "@dokploy/server/types/with"; import { TRPCError } from "@trpc/server"; +import { quote } from "shell-quote"; export const getErrorCloneRequirements = (entity: { giteaRepository?: string | null; @@ -177,7 +178,7 @@ export const cloneGiteaRepository = async ({ ); command += `echo "Cloning Repo ${repoClone} to ${outputPath}: ✅";`; - command += `git clone --branch ${giteaBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; + command += `git clone --branch ${quote([giteaBranch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; return command; }; diff --git a/packages/server/src/utils/providers/github.ts b/packages/server/src/utils/providers/github.ts index 6309cf307d..7cfa612c89 100644 --- a/packages/server/src/utils/providers/github.ts +++ b/packages/server/src/utils/providers/github.ts @@ -6,6 +6,7 @@ import type { InferResultType } from "@dokploy/server/types/with"; import { createAppAuth } from "@octokit/auth-app"; import { TRPCError } from "@trpc/server"; import { Octokit } from "octokit"; +import { quote } from "shell-quote"; import type { z } from "zod"; export const authGithub = (githubProvider: Github): Octokit => { @@ -167,7 +168,7 @@ export const cloneGithubRepository = async ({ const cloneUrl = `https://oauth2:${token}@${repoclone}`; command += `echo "Cloning Repo ${repoclone} to ${outputPath}: ✅";`; - command += `git clone --branch ${branch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; + command += `git clone --branch ${quote([branch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; return command; }; diff --git a/packages/server/src/utils/providers/gitlab.ts b/packages/server/src/utils/providers/gitlab.ts index 02121d346c..45f7d53c98 100644 --- a/packages/server/src/utils/providers/gitlab.ts +++ b/packages/server/src/utils/providers/gitlab.ts @@ -8,6 +8,7 @@ import { } from "@dokploy/server/services/gitlab"; import type { InferResultType } from "@dokploy/server/types/with"; import { TRPCError } from "@trpc/server"; +import { quote } from "shell-quote"; import type { z } from "zod"; export const refreshGitlabToken = async (gitlabProviderId: string) => { @@ -152,7 +153,7 @@ export const cloneGitlabRepository = async ({ const repoClone = getGitlabRepoClone(gitlab, gitlabPathNamespace); const cloneUrl = getGitlabCloneUrl(gitlab, repoClone); command += `echo "Cloning Repo ${repoClone} to ${outputPath}: ✅";`; - command += `git clone --branch ${gitlabBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; + command += `git clone --branch ${quote([gitlabBranch])} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; return command; };