From 771d0dd8ab0853903bb1563c44065d86b0b26030 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 19:35:55 +0000 Subject: [PATCH 1/2] Initial plan From 44645a6fbed9f1c18c4ba84c49a53d275d3c9550 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 19:41:56 +0000 Subject: [PATCH 2/2] fix: properly quote registry username in docker login to handle special characters like $ Co-authored-by: Siumauricio <47042324+Siumauricio@users.noreply.github.com> --- apps/dokploy/__test__/cluster/upload.test.ts | 34 +++++++++++++++++++ .../compose/domain/host-rule-format.test.ts | 2 +- .../servers/actions/show-server-actions.tsx | 2 +- .../settings/servers/handle-servers.tsx | 2 +- .../settings/servers/show-servers.tsx | 12 +++---- .../components/shared/breadcrumb-sidebar.tsx | 4 +-- packages/server/src/utils/cluster/upload.ts | 2 +- 7 files changed, 46 insertions(+), 12 deletions(-) diff --git a/apps/dokploy/__test__/cluster/upload.test.ts b/apps/dokploy/__test__/cluster/upload.test.ts index ca95cf663..1ccb9e22d 100644 --- a/apps/dokploy/__test__/cluster/upload.test.ts +++ b/apps/dokploy/__test__/cluster/upload.test.ts @@ -206,4 +206,38 @@ describe("getRegistryTag", () => { expect(result).toBe("docker.io/myuser/repo"); }); }); + + describe("special characters in username", () => { + it("should handle Harbor robot account username with $ (e.g. robot$library+dokploy)", () => { + const registry = createMockRegistry({ + username: "robot$library+dokploy", + }); + const result = getRegistryTag(registry, "nginx"); + expect(result).toBe("docker.io/robot$library+dokploy/nginx"); + }); + + it("should handle username with $ and other special characters", () => { + const registry = createMockRegistry({ + username: "robot$test+app", + }); + const result = getRegistryTag(registry, "myapp:latest"); + expect(result).toBe("docker.io/robot$test+app/myapp:latest"); + }); + + it("should handle username with multiple $ symbols", () => { + const registry = createMockRegistry({ + username: "user$name$test", + }); + const result = getRegistryTag(registry, "app"); + expect(result).toBe("docker.io/user$name$test/app"); + }); + + it("should handle username with + and - symbols", () => { + const registry = createMockRegistry({ + username: "robot+test-user", + }); + const result = getRegistryTag(registry, "nginx:latest"); + expect(result).toBe("docker.io/robot+test-user/nginx:latest"); + }); + }); }); diff --git a/apps/dokploy/__test__/compose/domain/host-rule-format.test.ts b/apps/dokploy/__test__/compose/domain/host-rule-format.test.ts index 27e696b20..097c916ea 100644 --- a/apps/dokploy/__test__/compose/domain/host-rule-format.test.ts +++ b/apps/dokploy/__test__/compose/domain/host-rule-format.test.ts @@ -1,7 +1,7 @@ import type { Domain } from "@dokploy/server"; import { createDomainLabels } from "@dokploy/server"; -import { parse, stringify } from "yaml"; import { describe, expect, it } from "vitest"; +import { parse, stringify } from "yaml"; /** * Regression tests for Traefik Host rule label format. diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx index ea2300cc5..334d25b20 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-server-actions.tsx @@ -1,5 +1,6 @@ import { Activity } from "lucide-react"; import { useState } from "react"; +import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -7,7 +8,6 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { ShowStorageActions } from "./show-storage-actions"; import { ShowTraefikActions } from "./show-traefik-actions"; diff --git a/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx index d9d1977a7..99804ba6b 100644 --- a/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx @@ -1,5 +1,5 @@ import { zodResolver } from "@hookform/resolvers/zod"; -import { PlusIcon, Pencil } from "lucide-react"; +import { Pencil, PlusIcon } from "lucide-react"; import Link from "next/link"; import { useTranslation } from "next-i18next"; import { useEffect, useState } from "react"; diff --git a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx index 111f10e28..85e7f3ee7 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx @@ -1,17 +1,17 @@ import { format } from "date-fns"; import { + Clock, + Key, KeyIcon, Loader2, MoreHorizontal, - ServerIcon, - Clock, - User, - Key, Network, - Terminal, - Settings, Pencil, + ServerIcon, + Settings, + Terminal, Trash2, + User, } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/router"; diff --git a/apps/dokploy/components/shared/breadcrumb-sidebar.tsx b/apps/dokploy/components/shared/breadcrumb-sidebar.tsx index c3428e301..4b8dc9112 100644 --- a/apps/dokploy/components/shared/breadcrumb-sidebar.tsx +++ b/apps/dokploy/components/shared/breadcrumb-sidebar.tsx @@ -1,13 +1,13 @@ +import { ChevronDown } from "lucide-react"; import Link from "next/link"; import { Fragment } from "react"; -import { ChevronDown } from "lucide-react"; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, - BreadcrumbSeparator, BreadcrumbPage, + BreadcrumbSeparator, } from "@/components/ui/breadcrumb"; import { DropdownMenu, diff --git a/packages/server/src/utils/cluster/upload.ts b/packages/server/src/utils/cluster/upload.ts index e2cf4a4a4..aa014a05c 100644 --- a/packages/server/src/utils/cluster/upload.ts +++ b/packages/server/src/utils/cluster/upload.ts @@ -117,7 +117,7 @@ const getRegistryCommands = ( ): string => { return ` echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" ; -echo "${registry.password}" | docker login ${registry.registryUrl} -u ${registry.username} --password-stdin || { +echo "${registry.password}" | docker login ${registry.registryUrl} -u '${registry.username}' --password-stdin || { echo "❌ DockerHub Failed" ; exit 1; }