(config: PostgresConnectionConfig)
| 3 | import type { PostgresConnectionConfig } from '@/tools/postgresql/types' |
| 4 | |
| 5 | export async function createPostgresConnection(config: PostgresConnectionConfig) { |
| 6 | const hostValidation = await validateDatabaseHost(config.host, 'host') |
| 7 | if (!hostValidation.isValid) { |
| 8 | throw new Error(hostValidation.error) |
| 9 | } |
| 10 | |
| 11 | const resolvedHost = hostValidation.resolvedIP ?? config.host |
| 12 | |
| 13 | const sslConfig: boolean | 'prefer' | { rejectUnauthorized: boolean; servername?: string } = |
| 14 | config.ssl === 'disabled' |
| 15 | ? false |
| 16 | : config.ssl === 'preferred' |
| 17 | ? 'prefer' |
| 18 | : { rejectUnauthorized: false, servername: config.host } |
| 19 | |
| 20 | const sql = postgres({ |
| 21 | // Pin the validated IP (never the hostname) to prevent DNS rebinding; SNI stays the hostname above. |
| 22 | host: resolvedHost, |
| 23 | port: config.port, |
| 24 | database: config.database, |
| 25 | username: config.username, |
| 26 | password: config.password, |
| 27 | ssl: sslConfig, |
| 28 | connect_timeout: 10, // 10 seconds |
| 29 | idle_timeout: 20, // 20 seconds |
| 30 | max_lifetime: 60 * 30, // 30 minutes |
| 31 | max: 1, // Single connection for tool usage |
| 32 | }) |
| 33 | |
| 34 | return sql |
| 35 | } |
| 36 | |
| 37 | export async function executeQuery( |
| 38 | sql: any, |
no test coverage detected