From 4ca05414af2390f1be87154418d88aa5c828bd8f Mon Sep 17 00:00:00 2001 From: Leonhard Breuer Date: Wed, 3 Sep 2025 19:52:01 +0200 Subject: [PATCH 1/4] fix: use shellsafe docker command - add `shEscape` function - add `safeDockerLoginCommand` - use the new functions to contruct better registry login command --- packages/server/src/services/registry.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts index 6468cd970..7c16bf017 100644 --- a/packages/server/src/services/registry.ts +++ b/packages/server/src/services/registry.ts @@ -10,6 +10,18 @@ import { IS_CLOUD } from "../constants"; export type Registry = typeof registry.$inferSelect; +function shQ(s: string): string { + if (!s) return "''"; + return `'${s.replace(/'/g, `'\\''`)}'`; +} + +function safeDockerLoginCommand(registry: string, user: string, pass: string) { + const escapedRegistry = shQ(registry) + const escapedUser = shQ(user) + const escapedPassword = shQ(pass) + return `echo ${escapedPassword} | docker login ${escapedRegistry} -u ${escapedUser} --password-stdin`; +} + export const createRegistry = async ( input: typeof apiCreateRegistry._type, organizationId: string, @@ -37,7 +49,7 @@ export const createRegistry = async ( message: "Select a server to add the registry", }); } - const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`; + const loginCommand = safeDockerLoginCommand(input.registryUrl, input.username, input.password) if (input.serverId && input.serverId !== "none") { await execAsyncRemote(input.serverId, loginCommand); } else if (newRegistry.registryType === "cloud") { From 02215d4e21c1baec76e326212d7227a48f6ed949 Mon Sep 17 00:00:00 2001 From: Leonhard Breuer Date: Wed, 3 Sep 2025 19:59:17 +0200 Subject: [PATCH 2/4] fix: use new command for registry updates --- packages/server/src/services/registry.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts index 7c16bf017..150374be8 100644 --- a/packages/server/src/services/registry.ts +++ b/packages/server/src/services/registry.ts @@ -10,15 +10,15 @@ import { IS_CLOUD } from "../constants"; export type Registry = typeof registry.$inferSelect; -function shQ(s: string): string { +function shEscape(s: string | undefined): string { if (!s) return "''"; return `'${s.replace(/'/g, `'\\''`)}'`; } -function safeDockerLoginCommand(registry: string, user: string, pass: string) { - const escapedRegistry = shQ(registry) - const escapedUser = shQ(user) - const escapedPassword = shQ(pass) +function safeDockerLoginCommand(registry: string | undefined, user: string | undefined, pass: string | undefined) { + const escapedRegistry = shEscape(registry) + const escapedUser = shEscape(user) + const escapedPassword = shEscape(pass) return `echo ${escapedPassword} | docker login ${escapedRegistry} -u ${escapedUser} --password-stdin`; } @@ -103,7 +103,7 @@ export const updateRegistry = async ( .returning() .then((res) => res[0]); - const loginCommand = `echo ${response?.password} | docker login ${response?.registryUrl} --username ${response?.username} --password-stdin`; + const loginCommand = safeDockerLoginCommand(response?.registryUrl, response?.username, response?.password) if ( IS_CLOUD && From 146d82b6c4305da06970f336564ae7736b6f5708 Mon Sep 17 00:00:00 2001 From: Leonhard Breuer Date: Wed, 3 Sep 2025 20:12:16 +0200 Subject: [PATCH 3/4] feat: use `printf` instead of `echo` --- packages/server/src/services/registry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts index 150374be8..8e98d2765 100644 --- a/packages/server/src/services/registry.ts +++ b/packages/server/src/services/registry.ts @@ -19,7 +19,7 @@ function safeDockerLoginCommand(registry: string | undefined, user: string | und const escapedRegistry = shEscape(registry) const escapedUser = shEscape(user) const escapedPassword = shEscape(pass) - return `echo ${escapedPassword} | docker login ${escapedRegistry} -u ${escapedUser} --password-stdin`; + return `printf %s ${escapedPassword} | docker login ${escapedRegistry} -u ${escapedUser} --password-stdin`; } export const createRegistry = async ( From 68945c6888909a884b5ce3d272ad77a0c5563a7a Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 18:17:04 +0000 Subject: [PATCH 4/4] [autofix.ci] apply automated fixes --- packages/server/src/services/registry.ts | 30 +++++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts index 8e98d2765..ec8db8fa8 100644 --- a/packages/server/src/services/registry.ts +++ b/packages/server/src/services/registry.ts @@ -11,15 +11,19 @@ import { IS_CLOUD } from "../constants"; export type Registry = typeof registry.$inferSelect; function shEscape(s: string | undefined): string { - if (!s) return "''"; - return `'${s.replace(/'/g, `'\\''`)}'`; + if (!s) return "''"; + return `'${s.replace(/'/g, `'\\''`)}'`; } -function safeDockerLoginCommand(registry: string | undefined, user: string | undefined, pass: string | undefined) { - const escapedRegistry = shEscape(registry) - const escapedUser = shEscape(user) - const escapedPassword = shEscape(pass) - return `printf %s ${escapedPassword} | docker login ${escapedRegistry} -u ${escapedUser} --password-stdin`; +function safeDockerLoginCommand( + registry: string | undefined, + user: string | undefined, + pass: string | undefined, +) { + const escapedRegistry = shEscape(registry); + const escapedUser = shEscape(user); + const escapedPassword = shEscape(pass); + return `printf %s ${escapedPassword} | docker login ${escapedRegistry} -u ${escapedUser} --password-stdin`; } export const createRegistry = async ( @@ -49,7 +53,11 @@ export const createRegistry = async ( message: "Select a server to add the registry", }); } - const loginCommand = safeDockerLoginCommand(input.registryUrl, input.username, input.password) + const loginCommand = safeDockerLoginCommand( + input.registryUrl, + input.username, + input.password, + ); if (input.serverId && input.serverId !== "none") { await execAsyncRemote(input.serverId, loginCommand); } else if (newRegistry.registryType === "cloud") { @@ -103,7 +111,11 @@ export const updateRegistry = async ( .returning() .then((res) => res[0]); - const loginCommand = safeDockerLoginCommand(response?.registryUrl, response?.username, response?.password) + const loginCommand = safeDockerLoginCommand( + response?.registryUrl, + response?.username, + response?.password, + ); if ( IS_CLOUD &&