feat(validation): enhance registry URL validation in schema

- Introduced a new validation schema for registry URLs, ensuring they conform to a specific format (hostname[:port]) and disallow shell metacharacters.
- Updated the `createSchema`, `apiCreateRegistry`, and `apiTestRegistry` functions to utilize the new registry URL validation.
- Improved security and input integrity for registry URL fields.
- Updated the `removeRegistry` function to escape the registry URL during logout to prevent command injection vulnerabilities.
This commit is contained in:
Mauricio Siu
2026-05-09 01:09:50 -06:00
parent b9e97eb321
commit 547ba2d04b
2 changed files with 15 additions and 4 deletions
+14 -3
View File
@@ -44,11 +44,22 @@ export const registryRelations = relations(registry, ({ many }) => ({
}),
}));
// Registry URLs must be hostname[:port] only — no shell metacharacters
// Empty string is allowed (means default/Docker Hub registry)
const registryUrlSchema = z
.string()
.refine(
(val) =>
val === "" ||
/^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?(:\d{1,5})?$/.test(val),
"Registry URL must be a valid hostname or hostname:port (e.g. registry.example.com or localhost:5000)",
);
const createSchema = createInsertSchema(registry, {
registryName: z.string().min(1),
username: z.string().min(1),
password: z.string().min(1),
registryUrl: z.string(),
registryUrl: registryUrlSchema,
organizationId: z.string().min(1),
registryId: z.string().min(1),
registryType: z.enum(["cloud"]),
@@ -61,7 +72,7 @@ export const apiCreateRegistry = createSchema
registryName: z.string().min(1),
username: z.string().min(1),
password: z.string().min(1),
registryUrl: z.string(),
registryUrl: registryUrlSchema,
registryType: z.enum(["cloud"]),
imagePrefix: z.string().nullable().optional(),
})
@@ -74,7 +85,7 @@ export const apiTestRegistry = createSchema.pick({}).extend({
registryName: z.string().optional(),
username: z.string().min(1),
password: z.string().min(1),
registryUrl: z.string(),
registryUrl: registryUrlSchema,
registryType: z.enum(["cloud"]),
imagePrefix: z.string().nullable().optional(),
serverId: z.string().optional(),
+1 -1
View File
@@ -85,7 +85,7 @@ export const removeRegistry = async (registryId: string) => {
}
if (!IS_CLOUD) {
await execAsync(`docker logout ${response.registryUrl}`);
await execAsync(`docker logout ${shEscape(response.registryUrl)}`);
}
return response;