Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/facilitator/src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { describe, it, expect, afterEach } from "vitest";
import { loadConfig } from "../config.js";

const BASE_ENV = {
DATABASE_URL: "postgres://user:pass@localhost:5432/db",
SOLANA_PRIVATE_KEY: "test-key",
};

describe("loadConfig boolean env vars", () => {
const original = { ...process.env };

afterEach(() => {
process.env = { ...original };
});

function load(extra: Record<string, string>) {
process.env = { ...BASE_ENV, ...extra };
return loadConfig();
}

it.each([
["false", false],
["0", false],
["FALSE", false],
["true", true],
["1", true],
["TRUE", true],
])("parses SUPABASE_SMTP_CONFIGURED=%s as %s", (value, expected) => {
expect(load({ SUPABASE_SMTP_CONFIGURED: value }).SUPABASE_SMTP_CONFIGURED).toBe(expected);
expect(load({ OFAC_ENABLED: value }).OFAC_ENABLED).toBe(expected);
});

it("defaults both flags to false when unset", () => {
const config = load({});
expect(config.SUPABASE_SMTP_CONFIGURED).toBe(false);
expect(config.OFAC_ENABLED).toBe(false);
});

it("rejects values that are not a recognized boolean", () => {
expect(() => load({ SUPABASE_SMTP_CONFIGURED: "yes" })).toThrow(/SUPABASE_SMTP_CONFIGURED/);
});
});
12 changes: 10 additions & 2 deletions apps/facilitator/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { z } from "zod";

/**
* Boolean env var. Unlike z.coerce.boolean(), which treats any non-empty
* string (including "false") as true, this accepts only true/false/1/0.
*/
const envBoolean = z
.enum(["true", "false", "1", "0", "TRUE", "FALSE"])
.transform((v) => v === "true" || v === "1" || v === "TRUE");

const envSchema = z.object({
PORT: z.coerce.number().default(4402),
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
Expand Down Expand Up @@ -45,7 +53,7 @@ const envSchema = z.object({
SHUTDOWN_TIMEOUT_MS: z.coerce.number().default(10_000),

/** Enable OFAC compliance screening on settlement routes */
OFAC_ENABLED: z.coerce.boolean().default(false),
OFAC_ENABLED: envBoolean.default("false"),
/** OFAC SDN list refresh interval in milliseconds (default: 24 hours) */
OFAC_REFRESH_INTERVAL_MS: z.coerce.number().default(86_400_000),

Expand All @@ -60,7 +68,7 @@ const envSchema = z.object({
* When false, /signup returns 503 instead of falsely reporting that an OTP
* email was sent (Supabase's built-in email service silently drops mail).
*/
SUPABASE_SMTP_CONFIGURED: z.coerce.boolean().default(false),
SUPABASE_SMTP_CONFIGURED: envBoolean.default("false"),
}).refine(
(data) => data.SOLANA_PRIVATE_KEY || data.KORA_RPC_URL,
{ message: "At least one of SOLANA_PRIVATE_KEY or KORA_RPC_URL is required", path: ["SOLANA_PRIVATE_KEY"] },
Expand Down
Loading