mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Bug fix (security hardening). ## What is the current behavior? [PRODSEC-120](https://linear.app/supabase/issue/PRODSEC-120/mythos-ant-2026-btrnt5a3-server-action-accepts-client-controlled-crm) — the marketing form server action accepts the full \`crm\` config (Notion \`database_id\`, HubSpot \`formGuid\`, Customer.io \`event\`, \`staticProperties\`, etc.) from the client, so a crafted submission can write to any Notion database the integration token reaches, post to any HubSpot form in the portal, or trigger arbitrary Customer.io events. ## What is the new behavior? The client now posts only \`{ slug, formId }\` plus the field values; \`submitFormAction\` validates the ref with Zod, looks the trusted CRM config up from the in-process \`_go/**\` page registry via a resolver wired up in \`instrumentation.ts\`, and fails closed if the form isn't found. \`SectionRenderer\` also strips \`crm\` from the section before it crosses into the client bundle (so \`database_id\` / \`formGuid\` no longer ship in page HTML), \`getAllGoPages\` rejects any form section with \`crm\` but no stable \`id\`, and per-submission size/character limits were tightened. ## Additional context Separate follow-ups (not in this PR): confirm \`NOTION_FORMS_API_KEY\` is write-only and scoped to the forms subtree, and chase down the \`NOTION_EVENTS_API_KEY\` validity issue raised on the Linear ticket. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** - Forms now support unique identifiers for enhanced tracking and management - Server-side form configuration management for improved reliability * **Improvements** - Enhanced form validation during page initialization to catch configuration issues - Improved form submission handling with better error detection and reporting - Strengthened form operations with fail-safe configuration resolution <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46239?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
import { validateGoPageInvariants } from 'marketing'
|
|
|
|
import rawPages from '@/_go'
|
|
import { goPageSchema, type GoPage } from '@/types/go'
|
|
|
|
export function getAllGoPages(): GoPage[] {
|
|
const pages: GoPage[] = []
|
|
const seenSlugs = new Set<string>()
|
|
|
|
for (const raw of rawPages) {
|
|
const result = goPageSchema.safeParse(raw)
|
|
|
|
if (!result.success) {
|
|
throw new Error(
|
|
`Invalid go page definition (slug: "${(raw as any).slug ?? 'unknown'}"):\n${result.error.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`).join('\n')}`
|
|
)
|
|
}
|
|
|
|
const invariantErrors = validateGoPageInvariants(result.data)
|
|
if (invariantErrors.length > 0) {
|
|
throw new Error(
|
|
`Invalid go page definition (slug: "${result.data.slug}"):\n${invariantErrors.map((m) => ` - ${m}`).join('\n')}`
|
|
)
|
|
}
|
|
|
|
if (seenSlugs.has(result.data.slug)) {
|
|
throw new Error(`Duplicate slug "${result.data.slug}" in _go registry`)
|
|
}
|
|
|
|
seenSlugs.add(result.data.slug)
|
|
pages.push(result.data)
|
|
}
|
|
|
|
return pages
|
|
}
|
|
|
|
export function getAllGoSlugs(): string[] {
|
|
return getAllGoPages().map((p) => p.slug)
|
|
}
|
|
|
|
export function getGoPageBySlug(slug: string): GoPage | undefined {
|
|
return getAllGoPages().find((p) => p.slug === slug)
|
|
}
|