From d862e0a3ad09136a815262d19a3a4b7ac3b7ddc1 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 28 Mar 2026 22:50:22 +0000 Subject: [PATCH] fix: strip quoted env var values before Zod validation Infisical export and some .env loaders produce values wrapped in single quotes (e.g. NEXT_PUBLIC_SUPPORT_EMAIL='support@codebuff.com'), causing Zod format validators (z.email(), z.url()) to reject them. - Add stripEnvQuotes() to common/src/env-schema.ts so clientProcessEnv values are sanitised before schema validation runs - Add the same stripping logic to sdk/test/setup-env.ts preload so test environment values are also cleaned up early Co-Authored-By: James --- common/src/env-schema.ts | 37 ++++++++++++++++++++++++++++--------- sdk/test/setup-env.ts | 24 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/common/src/env-schema.ts b/common/src/env-schema.ts index 23eb38f9a4..8bf4c5a17d 100644 --- a/common/src/env-schema.ts +++ b/common/src/env-schema.ts @@ -20,18 +20,37 @@ export type ClientInput = { } export type ClientEnv = z.infer +/** + * Strip wrapping single or double quotes from an env var value. + * Some secret managers (e.g. Infisical export) produce values like: + * NEXT_PUBLIC_SUPPORT_EMAIL='support@codebuff.com' + * which sets the value to the literal string `'support@codebuff.com'` + * (with quotes), causing Zod format validators (z.email(), z.url()) to fail. + */ +function stripEnvQuotes(value: string | undefined): string | undefined { + if ( + value && + value.length >= 2 && + ((value.startsWith("'") && value.endsWith("'")) || + (value.startsWith('"') && value.endsWith('"'))) + ) { + return value.slice(1, -1) + } + return value +} + // Bun will inject all these values, so we need to reference them individually (no for-loops) export const clientProcessEnv: ClientInput = { - NEXT_PUBLIC_CB_ENVIRONMENT: process.env.NEXT_PUBLIC_CB_ENVIRONMENT, - NEXT_PUBLIC_CODEBUFF_APP_URL: process.env.NEXT_PUBLIC_CODEBUFF_APP_URL, - NEXT_PUBLIC_SUPPORT_EMAIL: process.env.NEXT_PUBLIC_SUPPORT_EMAIL, - NEXT_PUBLIC_POSTHOG_API_KEY: process.env.NEXT_PUBLIC_POSTHOG_API_KEY, - NEXT_PUBLIC_POSTHOG_HOST_URL: process.env.NEXT_PUBLIC_POSTHOG_HOST_URL, + NEXT_PUBLIC_CB_ENVIRONMENT: stripEnvQuotes(process.env.NEXT_PUBLIC_CB_ENVIRONMENT), + NEXT_PUBLIC_CODEBUFF_APP_URL: stripEnvQuotes(process.env.NEXT_PUBLIC_CODEBUFF_APP_URL), + NEXT_PUBLIC_SUPPORT_EMAIL: stripEnvQuotes(process.env.NEXT_PUBLIC_SUPPORT_EMAIL), + NEXT_PUBLIC_POSTHOG_API_KEY: stripEnvQuotes(process.env.NEXT_PUBLIC_POSTHOG_API_KEY), + NEXT_PUBLIC_POSTHOG_HOST_URL: stripEnvQuotes(process.env.NEXT_PUBLIC_POSTHOG_HOST_URL), NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: - process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, + stripEnvQuotes(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY), NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL: - process.env.NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL, + stripEnvQuotes(process.env.NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL), NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID: - process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID, - NEXT_PUBLIC_WEB_PORT: process.env.NEXT_PUBLIC_WEB_PORT, + stripEnvQuotes(process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID), + NEXT_PUBLIC_WEB_PORT: stripEnvQuotes(process.env.NEXT_PUBLIC_WEB_PORT), } diff --git a/sdk/test/setup-env.ts b/sdk/test/setup-env.ts index 45b4fa8148..c40411e2c2 100644 --- a/sdk/test/setup-env.ts +++ b/sdk/test/setup-env.ts @@ -33,6 +33,30 @@ const serverDefaults: Record = { DISCORD_APPLICATION_ID: 'test', } +/** + * Strip wrapping single or double quotes from env var values. + * Infisical export and some .env loaders may produce values like: + * NEXT_PUBLIC_SUPPORT_EMAIL='support@codebuff.com' + * which sets the value to the literal string `'support@codebuff.com'` + * (with quotes), causing Zod format validators (z.email(), z.url()) to fail. + */ +function stripEnvQuotes(defaults: Record) { + for (const key of Object.keys(defaults)) { + const value = process.env[key] + if ( + value && + value.length >= 2 && + ((value.startsWith("'") && value.endsWith("'")) || + (value.startsWith('"') && value.endsWith('"'))) + ) { + process.env[key] = value.slice(1, -1) + } + } +} + +stripEnvQuotes(testDefaults) +stripEnvQuotes(serverDefaults) + for (const [key, value] of Object.entries(testDefaults)) { if (!process.env[key]) { process.env[key] = value