From 9d348ca893fee04e437529e09b7533b51d4ff2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Fri, 18 Sep 2026 12:18:43 -0300 Subject: [PATCH] fix: support arbitrary production database passwords --- docker-compose.yml | 10 ++++++++-- local/bootstrap.py | 14 +++++++++++++- local/db.py | 12 +++++++++++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 06f74b4..bb4d54c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,10 @@ version: "3.8" x-app-environment: &app-environment APP_ENV: production - DATABASE_URL: postgresql://dtf_app:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/dtf + DATABASE_HOST: db + DATABASE_NAME: dtf + DATABASE_USER: dtf_app + DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD} S3_ENDPOINT: ${R2_ENDPOINT:?set R2_ENDPOINT} S3_PUBLIC_ENDPOINT: ${R2_ENDPOINT:?set R2_ENDPOINT} S3_BUCKET: ${R2_BUCKET:?set R2_BUCKET} @@ -51,7 +54,10 @@ services: image: ${API_IMAGE:-gitea.blyzer.com.br/blyzer/dtf-api}:${IMAGE_TAG:-latest} command: python -m local.bootstrap environment: - DATABASE_ADMIN_URL: postgresql://dtf_admin:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/dtf + DATABASE_ADMIN_HOST: db + DATABASE_ADMIN_NAME: dtf + DATABASE_ADMIN_USER: dtf_admin + DATABASE_ADMIN_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD} APP_DB_USER: dtf_app APP_DB_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD} networks: [backend] diff --git a/local/bootstrap.py b/local/bootstrap.py index f62de26..30fcf8e 100644 --- a/local/bootstrap.py +++ b/local/bootstrap.py @@ -4,9 +4,21 @@ from pathlib import Path import psycopg from psycopg import sql + +def admin_connect(): + if os.environ.get('DATABASE_ADMIN_HOST'): + return psycopg.connect( + host=os.environ['DATABASE_ADMIN_HOST'], + dbname=os.environ['DATABASE_ADMIN_NAME'], + user=os.environ['DATABASE_ADMIN_USER'], + password=os.environ['DATABASE_ADMIN_PASSWORD'], + ) + return psycopg.connect(os.environ['DATABASE_ADMIN_URL']) + + def main(): role = os.environ['APP_DB_USER'] - with psycopg.connect(os.environ['DATABASE_ADMIN_URL']) as c: + with admin_connect() as c: admin, database = c.execute('SELECT current_user,current_database()').fetchone() if role == admin: raise RuntimeError('Application and database administrator must differ') diff --git a/local/db.py b/local/db.py index d16df74..529f176 100644 --- a/local/db.py +++ b/local/db.py @@ -4,9 +4,19 @@ import psycopg from psycopg.rows import dict_row def connect(): + # Production passes credentials as discrete libpq fields. This avoids + # treating characters in a generated password as URL syntax. Local and + # test environments retain DATABASE_URL compatibility. + if os.environ.get('DATABASE_HOST'): + return psycopg.connect( + host=os.environ['DATABASE_HOST'], + dbname=os.environ['DATABASE_NAME'], + user=os.environ['DATABASE_USER'], + password=os.environ['DATABASE_PASSWORD'], + row_factory=dict_row, + ) return psycopg.connect(os.environ['DATABASE_URL'], row_factory=dict_row) def initialize(): with connect() as c: c.execute(Path(__file__).with_name('schema.sql').read_text()) -