mirror of
https://github.com/supabase/supabase.git
synced 2026-10-12 12:55:06 +03:00
## What kind of change does this PR introduce? Bug fix. ## What is the current behavior? Webhook endpoint validation is inconsistent across Studio forms. The webhook sheet accepts incomplete hostnames like `https://webhook`, event type validation is not surfaced clearly, and HTTP endpoint validation differs between webhooks, log drains, cron jobs, and database hooks. ## What is the new behavior? - Tightens webhook endpoint URL validation and rejects incomplete hostnames while still allowing localhost and IP-based endpoints. - Surfaces the Event types validation through the standard form error styling and highlights the existing accordion item border when invalid. - **Extracts a shared HTTP endpoint URL validator and reuses it in webhooks, log drains, cron jobs, and database hooks.** - Adds focused regression tests for the webhook sheet and the shared/consumer validation paths. | After | | --- | | <img width="1728" height="997" alt="Webhooks Settings AWS Healthy Toolshed Supabase-CB0D999C-D0BF-47AA-A10F-342A2E328DF9" src="https://github.com/user-attachments/assets/bcbe4876-f9a7-497a-b288-460087a65546" /> | ## To test Form behaviour (in particular URL validation) on: - Webhook endpoint - Log drains - Cron jobs - Database hooks
39 lines
1.4 KiB
TypeScript
39 lines
1.4 KiB
TypeScript
import { z } from 'zod'
|
|
|
|
import { httpEndpointUrlSchema } from '@/lib/validation/http-url'
|
|
|
|
const httpRequestSchema = z.object({
|
|
function_type: z.literal('http_request'),
|
|
http_url: httpEndpointUrlSchema({
|
|
requiredMessage: 'Please provide a URL',
|
|
invalidMessage: 'Please provide a valid URL',
|
|
prefixMessage: 'Please prefix your URL with http:// or https://',
|
|
}),
|
|
})
|
|
|
|
const supabaseFunctionSchema = z.object({
|
|
function_type: z.literal('supabase_function'),
|
|
http_url: z
|
|
.string()
|
|
.min(1, 'Please select an edge function')
|
|
.refine((val) => !val.includes('undefined'), 'No edge functions available for selection'),
|
|
})
|
|
|
|
export const FormSchema = z
|
|
.object({
|
|
name: z.string().min(1, 'Please provide a name for your webhook'),
|
|
table_id: z.string().min(1, 'Please select a table'),
|
|
http_method: z.enum(['GET', 'POST']),
|
|
timeout_ms: z.coerce
|
|
.number()
|
|
.int()
|
|
.gte(1000, 'Timeout should be at least 1000ms')
|
|
.lte(10000, 'Timeout should not exceed 10,000ms'),
|
|
events: z.array(z.string()).min(1, 'Please select at least one event'),
|
|
httpHeaders: z.array(z.object({ id: z.string(), name: z.string(), value: z.string() })),
|
|
httpParameters: z.array(z.object({ id: z.string(), name: z.string(), value: z.string() })),
|
|
})
|
|
.and(z.discriminatedUnion('function_type', [httpRequestSchema, supabaseFunctionSchema]))
|
|
|
|
export type WebhookFormValues = z.infer<typeof FormSchema>
|