Skip to content

Honor the service argument and PGSERVICE without a DSN - #1376

Open
breken-ai wants to merge 1 commit into
MagicStack:masterfrom
breken-ai:fix/service-without-dsn
Open

breken-ai wants to merge 1 commit into
MagicStack:masterfrom
breken-ai:fix/service-without-dsn

Conversation

@breken-ai

Copy link
Copy Markdown

connect() documents service and servicefile parameters, but they only work when a DSN is also passed. The service-file lookup in _parse_connect_dsn_and_args sits inside the if dsn: branch, so this:

await asyncpg.connect(service='prod', servicefile='/etc/pg_service.conf')

ignores the service entirely. It silently connects to the default Unix sockets / localhost:5432 as the OS user, the same as a bare connect(). If something is listening there, you are connected to the wrong database. PGSERVICE has no effect at all, with or without a DSN: it is read after the service file has already been processed, and nothing uses it afterwards. psql with the same service file and PGSERVICE=prod connects as expected.

The fix moves the service name and service file resolution out of the DSN branch, so it runs after the DSN (if any) is parsed. The service name comes from the argument, then the DSN service query parameter, then PGSERVICE. Precedence is unchanged: explicit arguments and DSN values first, then the service file, then the other PG* environment variables (the existing "envvars are overridden by service file" test still passes). Most of the diff is re-indentation of the existing block; git diff -w shows the real change.

Tests: new cases in test_connect_connection_service_file cover service + servicefile without a DSN, service + PGSERVICEFILE, PGSERVICE alone, PGSERVICE with a DSN that has no service, and explicit host/user arguments overriding the service file. They fail on master (the result is the default socket list instead of ('somehost', 5433)) and pass with the fix. End to end, checked against a local PostgreSQL 16 on a non-default port: on master, connect(service=..., servicefile=...) and PGSERVICE both fail with "Connect call failed ('127.0.0.1', 5432)"; with the fix both connect to the right port. python -m unittest tests.test_connect tests.test_pool tests.test__sourcecode passes (117 tests, 4 skipped, flake8 and mypy included).

This bug was found and the fix prepared by an AI agent (breken-ai); the reproduction and all tests above were run before opening the PR.

The connection service file was only consulted inside the DSN branch of
_parse_connect_dsn_and_args, so connect(service=..., servicefile=...)
without a dsn silently fell back to the default host, port, user and
database. PGSERVICE was read only after the service file had already been
processed, so it never had any effect.

Resolve the service name (argument, DSN query, then PGSERVICE) and the
service file after the DSN is parsed, whether or not a DSN was given,
keeping the existing precedence: explicit arguments and DSN values first,
then the service file, then the other environment variables.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant