mirror of
https://github.com/supabase/supabase.git
synced 2026-05-08 18:00:20 -04:00
fd17b246e1
## 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
63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { httpEndpointUrlSchema, isValidHttpEndpointUrl } from './http-url'
|
|
|
|
const schema = httpEndpointUrlSchema({
|
|
requiredMessage: 'required',
|
|
invalidMessage: 'invalid',
|
|
prefixMessage: 'prefix',
|
|
})
|
|
|
|
describe('isValidHttpEndpointUrl', () => {
|
|
it('accepts valid http and https endpoints', () => {
|
|
expect(isValidHttpEndpointUrl('https://api.supabase.com/webhooks')).toBe(true)
|
|
expect(isValidHttpEndpointUrl('http://localhost:3000/hooks')).toBe(true)
|
|
expect(isValidHttpEndpointUrl('https://127.0.0.1:4318/v1/logs')).toBe(true)
|
|
expect(isValidHttpEndpointUrl('https://[::1]:4318/v1/logs')).toBe(true)
|
|
})
|
|
|
|
it('rejects invalid endpoint URLs', () => {
|
|
expect(isValidHttpEndpointUrl('https://webhook')).toBe(false)
|
|
expect(isValidHttpEndpointUrl('ftp://api.supabase.com/webhooks')).toBe(false)
|
|
expect(isValidHttpEndpointUrl('not a url')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('httpEndpointUrlSchema', () => {
|
|
it('rejects empty values', () => {
|
|
const result = schema.safeParse('')
|
|
|
|
expect(result.success).toBe(false)
|
|
if (!result.success) {
|
|
expect(result.error.issues[0].message).toBe('required')
|
|
}
|
|
})
|
|
|
|
it('rejects URLs without an http or https prefix', () => {
|
|
const result = schema.safeParse('api.supabase.com/webhooks')
|
|
|
|
expect(result.success).toBe(false)
|
|
if (!result.success) {
|
|
expect(result.error.issues[0].message).toBe('prefix')
|
|
}
|
|
})
|
|
|
|
it('rejects incomplete hostnames', () => {
|
|
const result = schema.safeParse('https://webhook')
|
|
|
|
expect(result.success).toBe(false)
|
|
if (!result.success) {
|
|
expect(result.error.issues[0].message).toBe('invalid')
|
|
}
|
|
})
|
|
|
|
it('accepts valid endpoints after trimming', () => {
|
|
const result = schema.safeParse(' https://api.supabase.com/webhooks ')
|
|
|
|
expect(result.success).toBe(true)
|
|
if (result.success) {
|
|
expect(result.data).toBe('https://api.supabase.com/webhooks')
|
|
}
|
|
})
|
|
})
|