From 207cdb0ef5a152d6c348ed7ffbef4f169fa2a228 Mon Sep 17 00:00:00 2001 From: Jacob Nelson Date: Sun, 23 Aug 2026 16:58:30 -0500 Subject: [PATCH] fix(agent): quote DSN values and drop deprecated testcontainers import --- agent/src/agent/db.py | 10 +++++++--- agent/tests/conftest.py | 2 +- agent/tests/test_db.py | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/agent/src/agent/db.py b/agent/src/agent/db.py index 9d500b4..e90e254 100644 --- a/agent/src/agent/db.py +++ b/agent/src/agent/db.py @@ -12,9 +12,13 @@ _MIGRATIONS_DIR = Path(__file__).parent / "migrations" def _dsn(cfg: AgentConfig, dbname: str) -> str: - return ( - f"host={cfg.db_host} port={cfg.db_port} dbname={dbname} " - f"user={cfg.db_user} password={cfg.db_password}" + from psycopg import conninfo + return conninfo.make_conninfo( + host=cfg.db_host, + port=cfg.db_port, + dbname=dbname, + user=cfg.db_user, + password=cfg.db_password, ) diff --git a/agent/tests/conftest.py b/agent/tests/conftest.py index 2661a90..39b39a3 100644 --- a/agent/tests/conftest.py +++ b/agent/tests/conftest.py @@ -1,7 +1,7 @@ import itertools import pytest -from testcontainers.postgres import PostgresContainer +from testcontainers.community.postgres import PostgresContainer from agent.config import AgentConfig diff --git a/agent/tests/test_db.py b/agent/tests/test_db.py index 82414db..af46528 100644 --- a/agent/tests/test_db.py +++ b/agent/tests/test_db.py @@ -37,3 +37,25 @@ def test_sync_runs_rejects_bad_status(cfg): "INSERT INTO sync_runs (connector, started_at, status)" " VALUES ('x', now(), 'bogus')" ) + + +def test_agent_dsn_escapes_password_with_space_and_quote(): + import psycopg + from agent.config import AgentConfig + from agent.db import agent_dsn + + cfg = AgentConfig( + db_host="localhost", + db_port=5432, + db_user="testuser", + db_password="pa ss'word", # password with space and single quote + agent_db_name="testdb", + firefly_url="http://firefly.test", + firefly_token="test-token", + heartbeat_interval_minutes=60, + ) + + dsn = agent_dsn(cfg) + # Parse DSN and verify password is preserved correctly + parsed = psycopg.conninfo.conninfo_to_dict(dsn) + assert parsed["password"] == "pa ss'word"