From 30816e2ef2bdb45430d37d630ded665b5703a754 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Jul 2026 10:53:40 -0700 Subject: [PATCH 1/3] fix(connectors): allow self-hosted private DB hosts via opt-in flag Database/connector tools rejected any host resolving to a private/reserved/ loopback IP, blocking the common self-hosted topology where the DB is reached by a Docker/K8s/Swarm service name. Add an opt-in ALLOW_PRIVATE_DATABASE_HOSTS flag that bypasses the private-host block in validateDatabaseHost while still resolving and pinning DNS. Blocked on the hosted platform regardless of the env var, mirroring DISABLE_AUTH. Fixes #4319 --- apps/sim/.env.example | 3 + apps/sim/lib/core/config/env-flags.ts | 29 ++++++++ apps/sim/lib/core/config/env.ts | 1 + .../core/security/input-validation.server.ts | 14 ++-- .../core/security/input-validation.test.ts | 69 +++++++++++++++++++ packages/testing/src/mocks/env-flags.mock.ts | 1 + 6 files changed, 113 insertions(+), 4 deletions(-) diff --git a/apps/sim/.env.example b/apps/sim/.env.example index d26ff64e52f..4083be6cdb0 100644 --- a/apps/sim/.env.example +++ b/apps/sim/.env.example @@ -12,6 +12,9 @@ BETTER_AUTH_URL=http://localhost:3000 # Authentication Bypass (Optional - for self-hosted deployments behind private networks) # DISABLE_AUTH=true # Uncomment to bypass authentication entirely. Creates an anonymous session for all requests. +# Private Database Hosts (Optional - for self-hosted deployments only) +# ALLOW_PRIVATE_DATABASE_HOSTS=true # Uncomment to let database/connector tools reach private/reserved/loopback hosts (e.g. Docker/K8s service names, localhost). Loosens the SSRF boundary; only enable on a trusted private network. + # NextJS (Required) NEXT_PUBLIC_APP_URL=http://localhost:3000 # INTERNAL_API_BASE_URL=http://sim-app.default.svc.cluster.local:3000 # Optional: internal URL for server-side /api self-calls; defaults to NEXT_PUBLIC_APP_URL diff --git a/apps/sim/lib/core/config/env-flags.ts b/apps/sim/lib/core/config/env-flags.ts index 63037fd3cb1..9c03585336b 100644 --- a/apps/sim/lib/core/config/env-flags.ts +++ b/apps/sim/lib/core/config/env-flags.ts @@ -74,6 +74,35 @@ if (isTruthy(env.DISABLE_AUTH)) { }) } +/** + * Whether database/connector tools may connect to private, reserved, or loopback + * hosts (e.g. Docker/K8s service names, localhost). Off by default: the SSRF guard + * in {@link validateDatabaseHost} blocks these so an untrusted user cannot pivot + * into the deployment's internal network. Self-hosted operators can opt in when + * their database lives on the same private network. Blocked on the hosted platform + * regardless of the env var, mirroring {@link isAuthDisabled}. + */ +export const allowPrivateDatabaseHosts = isTruthy(env.ALLOW_PRIVATE_DATABASE_HOSTS) && !isHosted + +if (isTruthy(env.ALLOW_PRIVATE_DATABASE_HOSTS)) { + import('@sim/logger') + .then(({ createLogger }) => { + const logger = createLogger('EnvFlags') + if (isHosted) { + logger.error( + 'ALLOW_PRIVATE_DATABASE_HOSTS is set but ignored on hosted environment. Private/reserved database hosts remain blocked for security.' + ) + } else { + logger.warn( + 'ALLOW_PRIVATE_DATABASE_HOSTS is enabled. Database/connector tools may reach private, reserved, and loopback hosts. Only use this in trusted private networks.' + ) + } + }) + .catch(() => { + // Fallback during config compilation when logger is unavailable + }) +} + /** * Is user registration disabled */ diff --git a/apps/sim/lib/core/config/env.ts b/apps/sim/lib/core/config/env.ts index 7bc8eb44d9a..91659f96398 100644 --- a/apps/sim/lib/core/config/env.ts +++ b/apps/sim/lib/core/config/env.ts @@ -33,6 +33,7 @@ export const env = createEnv({ DISABLE_REGISTRATION: z.boolean().optional(), // Flag to disable new user registration EMAIL_PASSWORD_SIGNUP_ENABLED: z.boolean().optional().default(true), // Enable email/password authentication (server-side enforcement) DISABLE_AUTH: z.boolean().optional(), // Bypass authentication entirely (self-hosted only, creates anonymous session) + ALLOW_PRIVATE_DATABASE_HOSTS: z.boolean().optional(), // Opt-in (self-hosted only): let database/connector tools reach private/reserved/loopback hosts (e.g. Docker/K8s service names). Loosens the SSRF boundary; ignored on the hosted platform. ALLOWED_LOGIN_EMAILS: z.string().optional(), // Comma-separated list of allowed email addresses for login ALLOWED_LOGIN_DOMAINS: z.string().optional(), // Comma-separated list of allowed email domains for login BLOCKED_SIGNUP_DOMAINS: z.string().optional(), // Comma-separated list of email domains blocked from signing up (e.g., "gmail.com,yahoo.com") diff --git a/apps/sim/lib/core/security/input-validation.server.ts b/apps/sim/lib/core/security/input-validation.server.ts index bd344e38997..d05e90f3a4b 100644 --- a/apps/sim/lib/core/security/input-validation.server.ts +++ b/apps/sim/lib/core/security/input-validation.server.ts @@ -6,7 +6,7 @@ import { createLogger } from '@sim/logger' import { toError } from '@sim/utils/errors' import * as ipaddr from 'ipaddr.js' import { Agent, type RequestInit as UndiciRequestInit, fetch as undiciFetch } from 'undici' -import { isHosted } from '@/lib/core/config/env-flags' +import { allowPrivateDatabaseHosts, isHosted } from '@/lib/core/config/env-flags' import { type ValidationResult, validateExternalUrl } from '@/lib/core/security/input-validation' import { PayloadSizeLimitError } from '@/lib/core/utils/stream-limits' @@ -152,6 +152,12 @@ export async function validateUrlWithDNS( * database hostnames (e.g. underscores in Docker/K8s service names). It only * blocks localhost and private/reserved IPs. * + * Self-hosted operators can set `ALLOW_PRIVATE_DATABASE_HOSTS` to reach databases + * on their private network (e.g. a Docker/Swarm service name that resolves to an + * internal IP). The opt-in only bypasses the private/reserved/loopback block; DNS + * is still resolved so the caller can pin the connection to the resolved IP. The + * bypass is never honored on the hosted platform (see {@link allowPrivateDatabaseHosts}). + * * @param host - The database hostname to validate * @param paramName - Name of the parameter for error messages * @returns AsyncValidationResult with resolved IP @@ -166,18 +172,18 @@ export async function validateDatabaseHost( const lowerHost = host.toLowerCase() - if (lowerHost === 'localhost') { + if (lowerHost === 'localhost' && !allowPrivateDatabaseHosts) { return { isValid: false, error: `${paramName} cannot be localhost` } } - if (ipaddr.isValid(lowerHost) && isPrivateOrReservedIP(lowerHost)) { + if (ipaddr.isValid(lowerHost) && isPrivateOrReservedIP(lowerHost) && !allowPrivateDatabaseHosts) { return { isValid: false, error: `${paramName} cannot be a private IP address` } } try { const { address } = await dns.lookup(host, { verbatim: true }) - if (isPrivateOrReservedIP(address)) { + if (isPrivateOrReservedIP(address) && !allowPrivateDatabaseHosts) { logger.warn('Database host resolves to blocked IP address', { paramName, hostname: host, diff --git a/apps/sim/lib/core/security/input-validation.test.ts b/apps/sim/lib/core/security/input-validation.test.ts index 7e8be4caa12..ce8c3e51cd7 100644 --- a/apps/sim/lib/core/security/input-validation.test.ts +++ b/apps/sim/lib/core/security/input-validation.test.ts @@ -28,6 +28,7 @@ import { } from '@/lib/core/security/input-validation' import { isPrivateOrReservedIP, + validateDatabaseHost, validateUrlWithDNS, } from '@/lib/core/security/input-validation.server' import { sanitizeForLogging } from '@/lib/core/security/redaction' @@ -762,6 +763,74 @@ describe('validateUrlWithDNS', () => { }) }) +describe('validateDatabaseHost', () => { + afterEach(() => { + envFlagsMock.allowPrivateDatabaseHosts = false + }) + + describe('default (SSRF guard on)', () => { + it('rejects a missing host', async () => { + const result = await validateDatabaseHost(undefined) + expect(result.isValid).toBe(false) + expect(result.error).toContain('required') + }) + + it('rejects localhost', async () => { + const result = await validateDatabaseHost('localhost') + expect(result.isValid).toBe(false) + expect(result.error).toContain('localhost') + }) + + it('rejects a literal private IP', async () => { + const result = await validateDatabaseHost('10.0.0.5') + expect(result.isValid).toBe(false) + expect(result.error).toContain('private IP') + }) + + it('rejects a literal loopback IP', async () => { + const result = await validateDatabaseHost('127.0.0.1') + expect(result.isValid).toBe(false) + expect(result.error).toContain('private IP') + }) + + it('accepts a public IP and pins the resolved address', async () => { + const result = await validateDatabaseHost('1.1.1.1') + expect(result.isValid).toBe(true) + expect(result.resolvedIP).toBe('1.1.1.1') + }) + }) + + describe('self-host opt-in (ALLOW_PRIVATE_DATABASE_HOSTS)', () => { + beforeEach(() => { + envFlagsMock.allowPrivateDatabaseHosts = true + }) + + it('allows localhost and still resolves an IP to pin', async () => { + const result = await validateDatabaseHost('localhost') + expect(result.isValid).toBe(true) + expect(result.resolvedIP).toBeDefined() + }) + + it('allows a literal private IP and pins it', async () => { + const result = await validateDatabaseHost('10.0.0.5') + expect(result.isValid).toBe(true) + expect(result.resolvedIP).toBe('10.0.0.5') + }) + + it('allows a literal loopback IP and pins it', async () => { + const result = await validateDatabaseHost('127.0.0.1') + expect(result.isValid).toBe(true) + expect(result.resolvedIP).toBe('127.0.0.1') + }) + + it('still surfaces unresolvable hostnames', async () => { + const result = await validateDatabaseHost('this-host-does-not-exist.invalid') + expect(result.isValid).toBe(false) + expect(result.error).toContain('could not be resolved') + }) + }) +}) + describe('validateInteger', () => { describe('valid integers', () => { it.concurrent('should accept positive integers', () => { diff --git a/packages/testing/src/mocks/env-flags.mock.ts b/packages/testing/src/mocks/env-flags.mock.ts index 6165c236fae..2dcbe178c75 100644 --- a/packages/testing/src/mocks/env-flags.mock.ts +++ b/packages/testing/src/mocks/env-flags.mock.ts @@ -17,6 +17,7 @@ export const envFlagsMock = { isBillingEnabled: false, isEmailVerificationEnabled: false, isAuthDisabled: false, + allowPrivateDatabaseHosts: false, isRegistrationDisabled: false, isEmailPasswordEnabled: false, isTriggerDevEnabled: false, From 90f6e6f9507f06e30b7ea5cf3945af8bc7a36add Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Jul 2026 11:00:26 -0700 Subject: [PATCH 2/3] fix(connectors): pin postgres IP in all ssl modes; strip IPv6 brackets Address review on #5322: - validateDatabaseHost now strips surrounding IPv6 brackets before the localhost/private-IP checks and DNS lookup, so a bracketed loopback like [::1] is classified correctly instead of failing as unresolvable. - PostgreSQL connector always connects to the validated, pinned IP (removed the ssl='preferred' carve-out that passed the original hostname and let the driver re-resolve during connection). Matches the MySQL/MongoDB pin pattern. - Add postgres connector pinning tests and bracketed-IPv6 host tests. --- .../app/api/tools/postgresql/utils.test.ts | 73 +++++++++++++++++++ apps/sim/app/api/tools/postgresql/utils.ts | 6 +- .../core/security/input-validation.server.ts | 8 +- .../core/security/input-validation.test.ts | 12 +++ 4 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 apps/sim/app/api/tools/postgresql/utils.test.ts diff --git a/apps/sim/app/api/tools/postgresql/utils.test.ts b/apps/sim/app/api/tools/postgresql/utils.test.ts new file mode 100644 index 00000000000..a02f96b950f --- /dev/null +++ b/apps/sim/app/api/tools/postgresql/utils.test.ts @@ -0,0 +1,73 @@ +/** + * @vitest-environment node + */ +import { beforeEach, describe, expect, it, vi } from 'vitest' +import type { PostgresConnectionConfig } from '@/tools/postgresql/types' + +const { mockValidateDatabaseHost, mockPostgres } = vi.hoisted(() => ({ + mockValidateDatabaseHost: vi.fn(), + mockPostgres: vi.fn(() => ({})), +})) + +vi.mock('postgres', () => ({ default: mockPostgres })) + +vi.mock('@/lib/core/security/input-validation.server', () => ({ + validateDatabaseHost: mockValidateDatabaseHost, +})) + +import { createPostgresConnection } from '@/app/api/tools/postgresql/utils' + +function makeConfig(overrides: Partial = {}): PostgresConnectionConfig { + return { + host: 'db.example.com', + port: 5432, + database: 'app', + username: 'app', + password: 'secret', + ssl: 'required', + ...overrides, + } +} + +describe('createPostgresConnection DNS pinning', () => { + beforeEach(() => { + vi.clearAllMocks() + mockValidateDatabaseHost.mockResolvedValue({ + isValid: true, + resolvedIP: '93.184.216.34', + originalHostname: 'db.example.com', + }) + }) + + it('never opens a connection when host validation fails (no SSRF window)', async () => { + mockValidateDatabaseHost.mockResolvedValue({ + isValid: false, + error: 'host resolves to a blocked IP address', + }) + + await expect( + createPostgresConnection(makeConfig({ host: 'rebind.attacker.example' })) + ).rejects.toThrow('host resolves to a blocked IP address') + expect(mockPostgres).not.toHaveBeenCalled() + }) + + it.each(['disabled', 'required', 'preferred'] as const)( + 'connects to the validated IP for ssl=%s (hostname never re-resolved)', + async (ssl) => { + await createPostgresConnection(makeConfig({ host: 'rebind.attacker.example', ssl })) + + expect(mockValidateDatabaseHost).toHaveBeenCalledWith('rebind.attacker.example', 'host') + const options = mockPostgres.mock.calls[0][0] + // The TCP target is always the validated IP — re-resolution can never happen. + expect(options.host).toBe('93.184.216.34') + } + ) + + it('preserves the hostname as the TLS servername for verifying ssl modes', async () => { + await createPostgresConnection(makeConfig({ host: 'db.example.com', ssl: 'required' })) + + const options = mockPostgres.mock.calls[0][0] + expect(options.host).toBe('93.184.216.34') + expect(options.ssl).toMatchObject({ servername: 'db.example.com' }) + }) +}) diff --git a/apps/sim/app/api/tools/postgresql/utils.ts b/apps/sim/app/api/tools/postgresql/utils.ts index dfeeab9eadb..bee9ff987fe 100644 --- a/apps/sim/app/api/tools/postgresql/utils.ts +++ b/apps/sim/app/api/tools/postgresql/utils.ts @@ -9,7 +9,6 @@ export async function createPostgresConnection(config: PostgresConnectionConfig) } const resolvedHost = hostValidation.resolvedIP ?? config.host - const pinIP = config.ssl !== 'preferred' const sslConfig: boolean | 'prefer' | { rejectUnauthorized: boolean; servername?: string } = config.ssl === 'disabled' @@ -19,7 +18,10 @@ export async function createPostgresConnection(config: PostgresConnectionConfig) : { rejectUnauthorized: false, servername: config.host } const sql = postgres({ - host: pinIP ? resolvedHost : config.host, + // Always connect to the validated, pinned IP to prevent DNS rebinding between + // host validation and connection. For SSL modes that verify, the original + // hostname is preserved as the TLS servername (SNI) above. + host: resolvedHost, port: config.port, database: config.database, username: config.username, diff --git a/apps/sim/lib/core/security/input-validation.server.ts b/apps/sim/lib/core/security/input-validation.server.ts index d05e90f3a4b..adb733ce754 100644 --- a/apps/sim/lib/core/security/input-validation.server.ts +++ b/apps/sim/lib/core/security/input-validation.server.ts @@ -171,17 +171,19 @@ export async function validateDatabaseHost( } const lowerHost = host.toLowerCase() + const cleanHost = + lowerHost.startsWith('[') && lowerHost.endsWith(']') ? lowerHost.slice(1, -1) : lowerHost - if (lowerHost === 'localhost' && !allowPrivateDatabaseHosts) { + if (cleanHost === 'localhost' && !allowPrivateDatabaseHosts) { return { isValid: false, error: `${paramName} cannot be localhost` } } - if (ipaddr.isValid(lowerHost) && isPrivateOrReservedIP(lowerHost) && !allowPrivateDatabaseHosts) { + if (ipaddr.isValid(cleanHost) && isPrivateOrReservedIP(cleanHost) && !allowPrivateDatabaseHosts) { return { isValid: false, error: `${paramName} cannot be a private IP address` } } try { - const { address } = await dns.lookup(host, { verbatim: true }) + const { address } = await dns.lookup(cleanHost, { verbatim: true }) if (isPrivateOrReservedIP(address) && !allowPrivateDatabaseHosts) { logger.warn('Database host resolves to blocked IP address', { diff --git a/apps/sim/lib/core/security/input-validation.test.ts b/apps/sim/lib/core/security/input-validation.test.ts index ce8c3e51cd7..10bf732db44 100644 --- a/apps/sim/lib/core/security/input-validation.test.ts +++ b/apps/sim/lib/core/security/input-validation.test.ts @@ -793,6 +793,12 @@ describe('validateDatabaseHost', () => { expect(result.error).toContain('private IP') }) + it('rejects a bracketed IPv6 loopback as a private IP (not unresolvable)', async () => { + const result = await validateDatabaseHost('[::1]') + expect(result.isValid).toBe(false) + expect(result.error).toContain('private IP') + }) + it('accepts a public IP and pins the resolved address', async () => { const result = await validateDatabaseHost('1.1.1.1') expect(result.isValid).toBe(true) @@ -823,6 +829,12 @@ describe('validateDatabaseHost', () => { expect(result.resolvedIP).toBe('127.0.0.1') }) + it('allows a bracketed IPv6 loopback and pins the unbracketed address', async () => { + const result = await validateDatabaseHost('[::1]') + expect(result.isValid).toBe(true) + expect(result.resolvedIP).toBe('::1') + }) + it('still surfaces unresolvable hostnames', async () => { const result = await validateDatabaseHost('this-host-does-not-exist.invalid') expect(result.isValid).toBe(false) From 0eeff7af68f8fe72282099a6804e608333dd61ef Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Jul 2026 11:13:24 -0700 Subject: [PATCH 3/3] fix(connectors): rename flag to isPrivateDatabaseHostsAllowed; trim comment - Rename env-flag const to satisfy the env-flags 'is' prefix CI check (env var ALLOW_PRIVATE_DATABASE_HOSTS is unchanged). - Tighten the postgres pinning comment to a single line. --- apps/sim/app/api/tools/postgresql/utils.ts | 4 +--- apps/sim/lib/core/config/env-flags.ts | 2 +- .../lib/core/security/input-validation.server.ts | 14 +++++++++----- .../sim/lib/core/security/input-validation.test.ts | 4 ++-- packages/testing/src/mocks/env-flags.mock.ts | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/sim/app/api/tools/postgresql/utils.ts b/apps/sim/app/api/tools/postgresql/utils.ts index bee9ff987fe..983f983288c 100644 --- a/apps/sim/app/api/tools/postgresql/utils.ts +++ b/apps/sim/app/api/tools/postgresql/utils.ts @@ -18,9 +18,7 @@ export async function createPostgresConnection(config: PostgresConnectionConfig) : { rejectUnauthorized: false, servername: config.host } const sql = postgres({ - // Always connect to the validated, pinned IP to prevent DNS rebinding between - // host validation and connection. For SSL modes that verify, the original - // hostname is preserved as the TLS servername (SNI) above. + // Pin the validated IP (never the hostname) to prevent DNS rebinding; SNI stays the hostname above. host: resolvedHost, port: config.port, database: config.database, diff --git a/apps/sim/lib/core/config/env-flags.ts b/apps/sim/lib/core/config/env-flags.ts index 9c03585336b..ce8aef23e50 100644 --- a/apps/sim/lib/core/config/env-flags.ts +++ b/apps/sim/lib/core/config/env-flags.ts @@ -82,7 +82,7 @@ if (isTruthy(env.DISABLE_AUTH)) { * their database lives on the same private network. Blocked on the hosted platform * regardless of the env var, mirroring {@link isAuthDisabled}. */ -export const allowPrivateDatabaseHosts = isTruthy(env.ALLOW_PRIVATE_DATABASE_HOSTS) && !isHosted +export const isPrivateDatabaseHostsAllowed = isTruthy(env.ALLOW_PRIVATE_DATABASE_HOSTS) && !isHosted if (isTruthy(env.ALLOW_PRIVATE_DATABASE_HOSTS)) { import('@sim/logger') diff --git a/apps/sim/lib/core/security/input-validation.server.ts b/apps/sim/lib/core/security/input-validation.server.ts index adb733ce754..a81853c5514 100644 --- a/apps/sim/lib/core/security/input-validation.server.ts +++ b/apps/sim/lib/core/security/input-validation.server.ts @@ -6,7 +6,7 @@ import { createLogger } from '@sim/logger' import { toError } from '@sim/utils/errors' import * as ipaddr from 'ipaddr.js' import { Agent, type RequestInit as UndiciRequestInit, fetch as undiciFetch } from 'undici' -import { allowPrivateDatabaseHosts, isHosted } from '@/lib/core/config/env-flags' +import { isHosted, isPrivateDatabaseHostsAllowed } from '@/lib/core/config/env-flags' import { type ValidationResult, validateExternalUrl } from '@/lib/core/security/input-validation' import { PayloadSizeLimitError } from '@/lib/core/utils/stream-limits' @@ -156,7 +156,7 @@ export async function validateUrlWithDNS( * on their private network (e.g. a Docker/Swarm service name that resolves to an * internal IP). The opt-in only bypasses the private/reserved/loopback block; DNS * is still resolved so the caller can pin the connection to the resolved IP. The - * bypass is never honored on the hosted platform (see {@link allowPrivateDatabaseHosts}). + * bypass is never honored on the hosted platform (see {@link isPrivateDatabaseHostsAllowed}). * * @param host - The database hostname to validate * @param paramName - Name of the parameter for error messages @@ -174,18 +174,22 @@ export async function validateDatabaseHost( const cleanHost = lowerHost.startsWith('[') && lowerHost.endsWith(']') ? lowerHost.slice(1, -1) : lowerHost - if (cleanHost === 'localhost' && !allowPrivateDatabaseHosts) { + if (cleanHost === 'localhost' && !isPrivateDatabaseHostsAllowed) { return { isValid: false, error: `${paramName} cannot be localhost` } } - if (ipaddr.isValid(cleanHost) && isPrivateOrReservedIP(cleanHost) && !allowPrivateDatabaseHosts) { + if ( + ipaddr.isValid(cleanHost) && + isPrivateOrReservedIP(cleanHost) && + !isPrivateDatabaseHostsAllowed + ) { return { isValid: false, error: `${paramName} cannot be a private IP address` } } try { const { address } = await dns.lookup(cleanHost, { verbatim: true }) - if (isPrivateOrReservedIP(address) && !allowPrivateDatabaseHosts) { + if (isPrivateOrReservedIP(address) && !isPrivateDatabaseHostsAllowed) { logger.warn('Database host resolves to blocked IP address', { paramName, hostname: host, diff --git a/apps/sim/lib/core/security/input-validation.test.ts b/apps/sim/lib/core/security/input-validation.test.ts index 10bf732db44..e1fbf1f7171 100644 --- a/apps/sim/lib/core/security/input-validation.test.ts +++ b/apps/sim/lib/core/security/input-validation.test.ts @@ -765,7 +765,7 @@ describe('validateUrlWithDNS', () => { describe('validateDatabaseHost', () => { afterEach(() => { - envFlagsMock.allowPrivateDatabaseHosts = false + envFlagsMock.isPrivateDatabaseHostsAllowed = false }) describe('default (SSRF guard on)', () => { @@ -808,7 +808,7 @@ describe('validateDatabaseHost', () => { describe('self-host opt-in (ALLOW_PRIVATE_DATABASE_HOSTS)', () => { beforeEach(() => { - envFlagsMock.allowPrivateDatabaseHosts = true + envFlagsMock.isPrivateDatabaseHostsAllowed = true }) it('allows localhost and still resolves an IP to pin', async () => { diff --git a/packages/testing/src/mocks/env-flags.mock.ts b/packages/testing/src/mocks/env-flags.mock.ts index 2dcbe178c75..597d572090a 100644 --- a/packages/testing/src/mocks/env-flags.mock.ts +++ b/packages/testing/src/mocks/env-flags.mock.ts @@ -17,7 +17,7 @@ export const envFlagsMock = { isBillingEnabled: false, isEmailVerificationEnabled: false, isAuthDisabled: false, - allowPrivateDatabaseHosts: false, + isPrivateDatabaseHostsAllowed: false, isRegistrationDisabled: false, isEmailPasswordEnabled: false, isTriggerDevEnabled: false,