mirror of
https://github.com/samvallad33/vestige.git
synced 2026-07-24 23:41:01 +02:00
Launch-critical fixes for the public July-14 signup surface (swarm-audited by
MiniMax M3, Claude-verified against the frontend RPC call path):
- migration: DROP the "anon can insert with check(true)" RLS policy. It let
anon write arbitrary rows straight to the table, bypassing all join_waitlist
validation. The frontend already calls the join_waitlist RPC (rest/v1/rpc/),
never a direct insert, so signup is unaffected. RLS stays enabled with no
permissive INSERT policy = direct anon inserts denied by default.
- join_waitlist: cap email <=254, reject control chars, truncate referrer <=2048.
- waitlist-welcome edge fn: FAIL CLOSED — if WAITLIST_WEBHOOK_SECRET is unset,
return 401 instead of serving (was an open Resend relay). Guard the referral
code against ^[a-z2-9]{7}$ and cap email length before sending.
- vercel.json: add baseline security headers (nosniff, Referrer-Policy,
X-Frame-Options: DENY, HSTS, Permissions-Policy). CSP deferred (would break
the WebGPU hero's inline bootstrap without nonces) — documented.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
73 lines
1.9 KiB
JSON
73 lines
1.9 KiB
JSON
{
|
|
"$schema": "https://openapi.vercel.sh/vercel.json",
|
|
"framework": null,
|
|
"installCommand": "pnpm install --frozen-lockfile",
|
|
"buildCommand": "VESTIGE_BASE_PATH= VITE_ROOT_REDIRECT=/launch pnpm --filter @vestige/dashboard build",
|
|
"outputDirectory": "apps/dashboard/build",
|
|
"cleanUrls": true,
|
|
"trailingSlash": false,
|
|
"headers": [
|
|
{
|
|
"source": "/_app/immutable/(.*)",
|
|
"headers": [
|
|
{
|
|
"key": "Cache-Control",
|
|
"value": "public, max-age=31536000, immutable"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"source": "/((?!_app/immutable/).*)",
|
|
"headers": [
|
|
{
|
|
"key": "Cache-Control",
|
|
"value": "public, max-age=0, must-revalidate"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"source": "/(.*)",
|
|
"headers": [
|
|
{
|
|
"key": "X-Content-Type-Options",
|
|
"value": "nosniff"
|
|
},
|
|
{
|
|
"key": "Referrer-Policy",
|
|
"value": "strict-origin-when-cross-origin"
|
|
},
|
|
{
|
|
"key": "X-Frame-Options",
|
|
"value": "DENY"
|
|
},
|
|
{
|
|
"key": "Strict-Transport-Security",
|
|
"value": "max-age=63072000; includeSubDomains"
|
|
},
|
|
{
|
|
"key": "Permissions-Policy",
|
|
"value": "camera=(), microphone=(), geolocation=()"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"_csp_note": "CSP TODO: the WebGPU launch page uses SvelteKit inline bootstrap scripts (and likely inline styles); a strict Content-Security-Policy needs nonces/hashes wired through the SvelteKit adapter or it will break the page. Omitting CSP intentionally rather than shipping one that blocks the launch hero. Add later via svelte.config kit.csp once script/style sources are enumerated.",
|
|
"redirects": [
|
|
{
|
|
"source": "/dashboard/launch",
|
|
"destination": "/launch",
|
|
"permanent": false
|
|
},
|
|
{
|
|
"source": "/dashboard/launch/:path*",
|
|
"destination": "/launch",
|
|
"permanent": false
|
|
}
|
|
],
|
|
"rewrites": [
|
|
{
|
|
"source": "/((?!_app/|favicon\\.svg|manifest\\.json|robots\\.txt|.*\\..*).*)",
|
|
"destination": "/200.html"
|
|
}
|
|
]
|
|
}
|