diff --git a/backend/db_setup.py b/backend/db_setup.py index c57371e..0de1b07 100644 --- a/backend/db_setup.py +++ b/backend/db_setup.py @@ -76,7 +76,7 @@ class Settings(BaseSettings): return value def url(self, *, async_driver: bool = True) -> URL: - """DSN with the driver forced; `sslmode` is mapped to asyncpg's `ssl` mode name.""" + """DSN with the driver forced; `sslmode` is translated to asyncpg's `ssl`.""" url = ( make_url(self.database_url) if self.database_url @@ -92,9 +92,10 @@ class Settings(BaseSettings): query = dict(url.query) if self.db_sslmode: query.setdefault("sslmode", self.db_sslmode) - # asyncpg accepts ssl as an SSLMode name (require, verify-full, …), not "true". - if async_driver and (mode := query.pop("sslmode", None)) is not None: - query["ssl"] = mode + # asyncpg rejects ssl=true (it treats the string as an sslmode). Keep + # libpq sslmode on the sync DSN; pass SSL via connect_args for asyncpg. + if async_driver: + query.pop("sslmode", None) driver = "asyncpg" if async_driver else "psycopg2" return url.set(drivername=f"postgresql+{driver}", query=query) @@ -137,6 +138,23 @@ _engine: AsyncEngine | None = None _sessionmaker: async_sessionmaker[AsyncSession] | None = None +def _connect_args(settings: Settings) -> dict: + """UTC session + SSL for RDS. `require` encrypts without verifying the CA.""" + import ssl as ssl_mod + + args: dict = { + "server_settings": {"timezone": "UTC", "application_name": settings.app_name} + } + mode = (settings.db_sslmode or "").strip().lower() + if mode and mode not in ("disable", "allow", "prefer"): + ctx = ssl_mod.create_default_context() + if mode == "require": + ctx.check_hostname = False + ctx.verify_mode = ssl_mod.CERT_NONE + args["ssl"] = ctx + return args + + def get_engine() -> AsyncEngine: """The process-wide AsyncEngine, created on first use.""" global _engine @@ -149,9 +167,7 @@ def get_engine() -> AsyncEngine: pool_size=s.db_pool_size, max_overflow=s.db_max_overflow, pool_recycle=s.db_pool_recycle, - connect_args={ - "server_settings": {"timezone": "UTC", "application_name": s.app_name} - }, + connect_args=_connect_args(s), ) return _engine