/** * El SSL de una cadena de conexión de Postgres: qué hará el driver con ella, * y cómo escribir el modo que se elija. * * ## Por qué vive aquí (2026-09-24) * * Ariel conectó un Postgres de Railway eligiendo «Require» y el panel del nodo * dijo `self-signed certificate in certificate chain`. Medido: el servidor * enseña un certificado `CN=localhost` firmado por su propio `root-ca`, y * «Require» escribía `sslmode=require`, que para `pg` 8 es VERIFICAR el * certificado. Y pidió que, si la cadena ya trae el SSL, el panel lo lea y lo * deje fijo; y si no lo trae, que se elija a mano. * * Para fijarlo, el panel tiene que saber lo que hará EL DRIVER, no lo que * parece que dice la cadena — y el driver tiene reglas que no se adivinan: * `sslmode=prefer` también verifica, `ssl=false` ENCIENDE el SSL (queda como * el texto `"false"`, que es verdadero), y `uselibpqcompat=true` le da la * vuelta a `require`. El panel sólo conocía `require` y `no-verify`; lo demás * lo pintaba como «Off». * * Una sola función para el dashboard y para los servicios, y el api la compara * caso a caso con el `pg` que de verdad corre (`el-ssl-de-postgres-es-el-del- * driver.spec.ts`): si una actualización de `pg` cambia sus reglas, ese spec * se pone rojo antes de que el panel enseñe una cosa y el driver haga otra. * * ## Las reglas, copiadas de `pg-connection-string` 2.12 y `pg` 8.20 * * 1. Los parámetros salen de `new URL(cadena, 'postgres://base')` (con el * mismo arreglo de espacios y el mismo host de relleno para `@/`); si una * clave se repite, gana la ÚLTIMA. Las claves distinguen mayúsculas: * `SSLMODE` no existe para el driver. * 2. `ssl=true`/`ssl=1` → sí; `ssl=0` → no; cualquier otro texto se queda * como texto (`ssl=false` → `"false"` → ENCENDIDO). * 3. Si hay `sslmode` (no vacío) o un fichero (`sslcert`, `sslkey`, * `sslrootcert`), el SSL pasa a ser un objeto y `ssl=` deja de contar. * 4. `sslmode`: `disable` → no; `no-verify` → cifrar sin comprobar; todo lo * demás (`prefer`, `require`, `verify-ca`, `verify-full`, y cualquier * valor raro) → cifrar Y comprobar el certificado. * 5. Con `uselibpqcompat=true`, las de libpq: `prefer` y `require` → sin * comprobar; `verify-full` → comprobando; `verify-ca` sin `sslrootcert` * → el driver se NIEGA; `no-verify` no existe en libpq → comprobando. * 6. Sin nada de eso, `pg` mira `PGSSLMODE` del entorno; en los servicios no * está puesta (medido el 2026-09-24), así que es SIN SSL. * * ## Los ficheros (`sslcert`, `sslkey`, `sslrootcert`) * * El driver los LEE DEL DISCO de quien conecta — nuestro servidor, no la * máquina de quien pegó la cadena. Nunca pueden valer: aquí salen como * `problema` y el panel no deja guardarlos. */ /** Los tres modos del selector. `require` es «cifrar y comprobar el * certificado» — lo que `pg` 8 hace con `sslmode=require`. */ export type ModoSslPostgres = 'off' | 'require' | 'no-verify'; export type SslDeLaCadenaPostgres = /** La cadena no dice nada de SSL: se elige a mano. */ { dice: false; } /** La cadena lo decide. `por` es el parámetro que manda (`sslmode=require`). */ | { dice: true; modo: ModoSslPostgres; por: string; } /** La cadena dice algo que no puede funcionar desde nuestros servidores. */ | { dice: true; modo: null; por: string; problema: string; }; /** * Los parámetros que `pg-connection-string` LEE DEL DISCO con * `fs.readFileSync()` al construir el cliente (2.12 y 2.14, medido * el 2026-09-24). El api y hw-nodes comprueban contra el fuente del driver * que no lee ninguno más (`ninguna-conexion-postgres-lee-ficheros.spec.ts`). */ export declare const FICHEROS_DE_POSTGRES: readonly ["sslcert", "sslkey", "sslrootcert"]; /** * Los parámetros de la cadena EXACTAMENTE como los lee `pg-connection-string` * —mismo arreglo de espacios, mismo host de relleno para `@/`, claves * decodificadas, la última repetida gana—. `null` si el driver no llega a * leer parámetros: un socket (`/ruta` o `socket:`) o una cadena que ni él * puede leer. * * ⚠️ SIN recortar: la usa una guarda de seguridad * (`asegurarPostgresSinFicheros` en node-sdk). Con `" /x?sslrootcert=…"`, un * recorte vería un socket y dejaría pasar lo que el driver sí lee. */ export declare function parametrosDeCadenaPostgres(cadena: string): Record | null; /** * Qué hará el driver con el SSL de esta cadena. * * `{ dice: false }` cuando la cadena no dice nada: ni `ssl`, ni `sslmode`, ni * ficheros (un `sslmode=` o `ssl=` vacío tampoco dicen nada: el driver los * ignora). */ export declare function leerSslPostgres(cadena: string): SslDeLaCadenaPostgres; /** * Escribe el modo elegido en la cadena, quitando antes `ssl` y `sslmode` (en * una cadena que «no dice nada», los que hubiera están vacíos). No toca el * resto de parámetros, ni los recodifica. * * Lo que escribe, y por qué: * - `off` → `sslmode=disable`, explícito: la cadena guardada dice lo * que hace sin depender de `PGSSLMODE`. * - `require` → `sslmode=verify-full`, no `require`: para `pg` 8 es lo * mismo, pero `require` avisa en cada conexión de que en la * versión 9 pasará a NO comprobar. `verify-full` significa * lo mismo en las dos. * - `no-verify` → `sslmode=no-verify`; con `uselibpqcompat=true`, que no lo * conoce, `sslmode=require` (lo mismo en libpq). * * Una cadena vacía se devuelve tal cual. */ export declare function ponerSslPostgres(cadena: string, modo: ModoSslPostgres): string; /** * La frase que le falta a un error de conexión de SSL: qué cambiar. `null` si * el error no es de SSL. * * Los tres casos que se ven al conectar: * - el certificado no se puede comprobar (autofirmado, CA privada, nombre * que no casa): Railway (`CN=localhost` de su `root-ca`) y Supabase (su * `Supabase Root 2021 CA`) —medidos los dos el 2026-09-24—, Heroku y * RDS. Neon sí se comprueba (Let's Encrypt); * - el servidor no acepta SSL; * - el servidor exige SSL y se conectó sin él. */ export declare function pistaDeSslPostgres(mensaje: string): string | null; /** * Los casos con los que se comprueba `ficherosEnCadenaPostgres` contra el * driver de verdad (el api y hw-nodes espían `fs.readFileSync` mientras * `pg-connection-string` lee cada cadena): `lee` es si el DRIVER abre un * fichero. Incluye los dos rodeos medidos el 2026-09-24 —un espacio delante * de `/` (el driver no lo toma por socket y lee) y una clave codificada * (`ssl%72ootcert`)— y lo que no lee (mayúsculas, sockets, valor vacío). * Las rutas empiezan por `/nope` para que el espía las reconozca. */ export declare const CASOS_DE_FICHEROS_POSTGRES: ReadonlyArray<{ cadena: string; lee: boolean; }>; /** * Los parámetros de la cadena que el driver leería como FICHEROS del disco de * quien conecta —nuestros servidores—. Vacío si no hay ninguno. Devuelve los * NOMBRES, nunca los valores: una ruta no se repite en un mensaje. */ export declare function ficherosEnCadenaPostgres(cadena: string): string[]; /** El mensaje con su pista, si la tiene. Lo que devuelven los servicios. Si el * error ya pasó por aquí (dos capas que lo envuelven), no la repite. */ export declare function conPistaDeSslPostgres(mensaje: string): string; /** * Los casos con los que se comprueba la regla — aquí y contra el driver de * verdad en el api (`el-ssl-de-postgres-es-el-del-driver.spec.ts`). Uno nuevo * se añade AQUÍ y lo miran los dos. * * `esperado`: el modo, `'nada'` si la cadena no dice nada, `'problema'` si no * puede funcionar. */ export declare const CASOS_DE_SSL_POSTGRES: ReadonlyArray<{ cadena: string; esperado: ModoSslPostgres | 'nada' | 'problema'; }>;