From ec9dd289244ba24af0fc4e1d9590fc99eb56b64e Mon Sep 17 00:00:00 2001 From: Rafael Dias Zendron Date: Tue, 30 Jun 2026 19:07:15 -0300 Subject: [PATCH] fix(registry): preserve username case for ECR compatibility (#4632) (#4647) Remove .toLowerCase() transform from registryUsernameSchema. AWS ECR requires the username to be exactly 'AWS' (uppercase) for authentication. Docker Hub usernames are case-insensitive for login, so preserving case is safe for all providers. Closes #4632 --- .../__test__/registry/registry-schema.test.ts | 75 +++++++++++++++++++ packages/server/src/db/schema/registry.ts | 11 ++- 2 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 apps/dokploy/__test__/registry/registry-schema.test.ts diff --git a/apps/dokploy/__test__/registry/registry-schema.test.ts b/apps/dokploy/__test__/registry/registry-schema.test.ts new file mode 100644 index 000000000..e5ff60a6c --- /dev/null +++ b/apps/dokploy/__test__/registry/registry-schema.test.ts @@ -0,0 +1,75 @@ +import { apiCreateRegistry, apiTestRegistry } from "@dokploy/server/db/schema"; +import { describe, expect, it } from "vitest"; + +describe("Registry Schema - Username case preservation (#4632)", () => { + const validBase = { + registryName: "AWS ECR", + password: "dXNlcm5hbWU6cGFzc3dvcmQ=", // dummy base64 token + registryUrl: "123456789.dkr.ecr.us-east-1.amazonaws.com", + registryType: "cloud" as const, + imagePrefix: null, + }; + + it("should preserve uppercase username (AWS ECR requires 'AWS')", () => { + const result = apiCreateRegistry.safeParse({ + ...validBase, + username: "AWS", + }); + expect(result.success).toBe(true); + if (result.success) { + expect(result.data.username).toBe("AWS"); + } + }); + + it("should not lowercase mixed-case usernames", () => { + const result = apiCreateRegistry.safeParse({ + ...validBase, + username: "MyUser", + }); + expect(result.success).toBe(true); + if (result.success) { + expect(result.data.username).toBe("MyUser"); + } + }); + + it("should still trim whitespace from username", () => { + const result = apiCreateRegistry.safeParse({ + ...validBase, + username: " AWS ", + }); + expect(result.success).toBe(true); + if (result.success) { + expect(result.data.username).toBe("AWS"); + } + }); + + it("should reject empty username", () => { + const result = apiCreateRegistry.safeParse({ + ...validBase, + username: "", + }); + expect(result.success).toBe(false); + }); + + it("should also preserve case in apiTestRegistry", () => { + const result = apiTestRegistry.safeParse({ + ...validBase, + username: "AWS", + }); + expect(result.success).toBe(true); + if (result.success) { + expect(result.data.username).toBe("AWS"); + } + }); + + it("should accept lowercase usernames too (backward compat)", () => { + const result = apiCreateRegistry.safeParse({ + ...validBase, + username: "myuser", + }); + expect(result.success).toBe(true); + if (result.success) { + expect(result.data.username).toBe("myuser"); + } + }); +}); diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 02b2f4c55..ff1c6e330 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -44,12 +44,11 @@ export const registryRelations = relations(registry, ({ many }) => ({ }), })); -// Image references require a lowercase namespace (e.g. Docker Hub username). -const registryUsernameSchema = z - .string() - .trim() - .min(1) - .transform((s) => s.toLowerCase()); +// Registry usernames should NOT be lowercased. +// Some registries (e.g. AWS ECR) require a specific case: the username must be +// exactly "AWS" (uppercase) for ECR authentication. Docker Hub usernames are +// case-insensitive for login, so preserving case is safe for all providers. +const registryUsernameSchema = z.string().trim().min(1); // Registry URLs must be hostname[:port] only — no shell metacharacters // Empty string is allowed (means default/Docker Hub registry)