From 610c3536e556638a4a897c8249e1a98468775f04 Mon Sep 17 00:00:00 2001 From: Amogh Bharadwaj Date: Mon, 13 Nov 2023 12:05:59 -0500 Subject: [PATCH] Add validation for mirror name in UI (#649) Fixes #648 Validates that mirror name must contain only letters, numbers and underscores --- ui/app/mirrors/create/handlers.ts | 21 ++++++++++++++++----- ui/app/mirrors/create/schema.ts | 10 ++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/ui/app/mirrors/create/handlers.ts b/ui/app/mirrors/create/handlers.ts index 31ff45a66b..20c13bbfb7 100644 --- a/ui/app/mirrors/create/handlers.ts +++ b/ui/app/mirrors/create/handlers.ts @@ -7,7 +7,12 @@ import { import { QRepConfig, QRepWriteType } from '@/grpc_generated/flow'; import { Dispatch, SetStateAction } from 'react'; import { CDCConfig, TableMapRow } from '../../dto/MirrorsDTO'; -import { cdcSchema, qrepSchema, tableMappingSchema } from './schema'; +import { + cdcSchema, + flowNameSchema, + qrepSchema, + tableMappingSchema, +} from './schema'; const validateCDCFields = ( tableMapping: TableMapRow[], @@ -85,10 +90,13 @@ export const handleCreateCDC = async ( setLoading: Dispatch>, route: RouteCallback ) => { - if (!flowJobName) { - setMsg({ ok: false, msg: 'Mirror name is required' }); + const flowNameValid = flowNameSchema.safeParse(flowJobName); + if (!flowNameValid.success) { + const flowNameErr = flowNameValid.error.issues[0].message; + setMsg({ ok: false, msg: flowNameErr }); return; } + const isValid = validateCDCFields(rows, setMsg, config); if (!isValid) return; const tableNameMapping = reformattedTableMapping(rows); @@ -125,10 +133,13 @@ export const handleCreateQRep = async ( route: RouteCallback, xmin?: boolean ) => { - if (!flowJobName) { - setMsg({ ok: false, msg: 'Mirror name is required' }); + const flowNameValid = flowNameSchema.safeParse(flowJobName); + if (!flowNameValid.success) { + const flowNameErr = flowNameValid.error.issues[0].message; + setMsg({ ok: false, msg: flowNameErr }); return; } + if (xmin == true) { config.watermarkColumn = 'xmin'; config.query = `SELECT * FROM ${config.watermarkTable} WHERE xmin::text::bigint BETWEEN {{.start}} AND {{.end}}`; diff --git a/ui/app/mirrors/create/schema.ts b/ui/app/mirrors/create/schema.ts index d7d03d45fa..1d14b02569 100644 --- a/ui/app/mirrors/create/schema.ts +++ b/ui/app/mirrors/create/schema.ts @@ -1,5 +1,15 @@ import * as z from 'zod'; +export const flowNameSchema = z + .string({ + invalid_type_error: 'Mirror name is invalid.', + required_error: 'Mirror name is required.', + }) + .min(1, { message: 'Mirror name cannot be empty.' }) + .regex(/^[\w]*$/, { + message: 'Mirror name must contain only letters, numbers and underscores', + }); + export const tableMappingSchema = z .array( z.object({