From 702af64444bab39f0aaf68da6f7ae7272d6e8aac Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Wed, 10 Dec 2025 00:25:23 -0600 Subject: [PATCH 1/2] feat(registry): enhance registry URL validation and update handling - Made the registry URL field optional and added refined validation to ensure only valid hostnames are accepted, excluding protocols and paths. - Updated the handling of registry URL in the form to default to an empty string if not provided. - Added descriptive guidance in the form to assist users in entering the correct format for the registry URL. --- .../cluster/registry/handle-registry.tsx | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx index 4321088f2..dc4b810dd 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx @@ -45,7 +45,34 @@ const AddRegistrySchema = z.object({ password: z.string().min(1, { message: "Password is required", }), - registryUrl: z.string(), + registryUrl: z + .string() + .optional() + .refine( + (val) => { + // If empty or undefined, skip validation (field is optional) + if (!val || val.trim().length === 0) { + return true; + } + // Validate that it's a valid hostname (no protocol, no path, optional port) + // Valid formats: example.com, registry.example.com, [::1], example.com:5000 + // Invalid: https://example.com, example.com/path + const trimmed = val.trim(); + // Check for protocol or path - these are not allowed + if (/^https?:\/\//i.test(trimmed) || trimmed.includes("/")) { + return false; + } + // Basic hostname validation: allow alphanumeric, dots, hyphens, underscores, and IPv6 in brackets + // Allow optional port at the end + const hostnameRegex = + /^(?:\[[^\]]+\]|[a-zA-Z0-9](?:[a-zA-Z0-9._-]{0,253}[a-zA-Z0-9])?)(?::\d+)?$/; + return hostnameRegex.test(trimmed); + }, + { + message: + "Invalid registry URL. Please enter only the hostname (e.g., example.com or registry.example.com). Do not include protocol (https://) or paths.", + }, + ), imagePrefix: z.string(), serverId: z.string().optional(), }); @@ -125,7 +152,7 @@ export const HandleRegistry = ({ registryId }: Props) => { password: data.password, registryName: data.registryName, username: data.username, - registryUrl: data.registryUrl, + registryUrl: data.registryUrl || "", registryType: "cloud", imagePrefix: data.imagePrefix, serverId: data.serverId, @@ -261,6 +288,10 @@ export const HandleRegistry = ({ registryId }: Props) => { render={({ field }) => ( Registry URL + + Enter only the hostname (e.g., + aws_account_id.dkr.ecr.us-west-2.amazonaws.com). + { await testRegistry({ username: username, password: password, - registryUrl: registryUrl, + registryUrl: registryUrl || "", registryName: registryName, registryType: "cloud", imagePrefix: imagePrefix, From 31cdae1b726fd8c32b56faf77ac760d1c1c04298 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Wed, 10 Dec 2025 00:31:03 -0600 Subject: [PATCH 2/2] feat(registry): improve server selection guidance in registry settings - Enhanced the user interface for server selection in the registry settings, providing clearer instructions based on whether the server is cloud-based or not. - Added conditional messaging to inform users about authentication processes related to the selected server, improving overall user experience. --- .../cluster/registry/handle-registry.tsx | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx index dc4b810dd..f751e262e 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx @@ -126,6 +126,9 @@ export const HandleRegistry = ({ registryId }: Props) => { const registryName = form.watch("registryName"); const imagePrefix = form.watch("imagePrefix"); const serverId = form.watch("serverId"); + const selectedServer = servers?.find( + (server) => server.serverId === serverId, + ); useEffect(() => { if (registry) { @@ -313,8 +316,40 @@ export const HandleRegistry = ({ registryId }: Props) => { Server {!isCloud && "(Optional)"} - Select a server to test the registry. this will run the - following command on the server + {!isCloud ? ( + <> + {serverId && serverId !== "none" && selectedServer ? ( + <> + Authentication will be performed on{" "} + {selectedServer.name}. This + registry will be available on this server. + + ) : ( + <> + Choose where to authenticate with the registry. By + default, authentication occurs on the Dokploy + server. Select a specific server to authenticate + from that server instead. + + )} + + ) : ( + <> + {serverId && serverId !== "none" && selectedServer ? ( + <> + Authentication will be performed on{" "} + {selectedServer.name}. This + registry will be available on this server. + + ) : ( + <> + Select a server to authenticate with the registry. + The authentication will be performed from the + selected server. + + )} + + )}