Skip to content

Expand environment variables in DSN aliases#1914

Merged
rolandwalker merged 2 commits into
dbcli:mainfrom
n8himmel:expand-env-vars-in-dsn-aliases
Jun 20, 2026
Merged

Expand environment variables in DSN aliases#1914
rolandwalker merged 2 commits into
dbcli:mainfrom
n8himmel:expand-env-vars-in-dsn-aliases

Conversation

@n8himmel

@n8himmel n8himmel commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Description

Expand configured [alias_dsn] values with os.path.expandvars after alias lookup and before URL parsing. This allows aliases to keep DSN components such as credentials, hosts, ports, or database names in environment variables.

This adds coverage for both --dsn <alias> and positional alias usage, and documents $VAR / ${VAR} support in the sample config.

Checklist

  • I added this contribution to the changelog.md file.
  • I added my name to the AUTHORS file (or it's already there).
  • To lint and format the code, I ran
    uv run --extra dev -- ruff check
    uv run --extra dev -- ruff format
    uv run --extra dev -- mypy --install-types --non-interactive .

Additional focused test run:

PYTHONPATH=. uv run --extra dev -- pytest -q test/pytests/test_main.py -k test_dsn

@rolandwalker

Copy link
Copy Markdown
Contributor

Hi! This is an interesting idea but I have many thoughts and questions!

  1. Why isn't it sufficient currently to override the DSN elements with CLI arguments? Is that not working right? In other words we should be able to already do:
mycli --dsn named_dsn --host=$HOSTNAME
  1. Doesn't this implementation mean that $ becomes an illegal character in passwords?

  2. Doesn't this implementation mean that keys in the DSN get substituted as well as values?

  3. Doesn't this implementation mean that DSN substitution is inconsistent between Windows and Unixlikes?

  4. Could the fundamental problem also be addressed by ~/.myclirc sections like [connection.hostname] which contain overrides? (That is a dream of mine.)

It seems to me that if 1 isn't satisfactory, then we'd need 2-4 to be addressed. It's probably a requirement that DSN substitution be opt-in by an option in ~/.myclirc. Then I'd suggest that os.path.expandvars() be avoided because of the Windows issue.

Instead we should break down the DSN first, only applying variable substitution to values, not keys. Also it would be better to substitute only complete values rather than partial values. Also it would be better to limit to the ${VAR} syntax with brackets.

Are you up for it?

@rolandwalker rolandwalker self-assigned this Jun 8, 2026
@n8himmel n8himmel force-pushed the expand-env-vars-in-dsn-aliases branch from f43aacf to 03af290 Compare June 20, 2026 10:32
@n8himmel

Copy link
Copy Markdown
Contributor Author

Thanks for your comments. I really didn't give enough thought about the side effects you mentioned. Now I'm not even sure if my most recent update is the right way to do it. Probably the expansion helper should live somewhere more focused that in cli_runner.py

  1. Why isn't it sufficient currently to override the DSN elements with CLI arguments? Is that not working right? In other words we should be able to already do:
mycli --dsn named_dsn --host=$HOSTNAME

Right. You would leave the env expansion to the shell. That's what I'm currently doing in my wrapper script. And honestly, I could live with it. The reason why this came up is that I recently switched to having all keys and passwords in sops encrypted files that are injected into the environment using mise. After years of fiddling around this almost feels like magic. Now by using env vars for everything I have the absolute same connect string on every host for the same database. One single source of truth and it just works.

  1. Could the fundamental problem also be addressed by ~/.myclirc sections like [connection.hostname] which contain overrides? (That is a dream of mine.)

I might miss sth here, but no ... when there's no env expansion I would have to spread passwords all over the place again.

As I said, I'm hesitant about this PR but at least there would be

  • Default-off, no compatibility issue.
  • No os.path.expandvars()
  • Only ${VAR} is recognized.
  • Only whole value fields expand, which keeps $ usable in normal passwords/values.
  • Query keys are not expanded.
  • Missing variables fail before any connection attempt.

Thanks

@rolandwalker

rolandwalker commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

@n8himmel thanks for your responsiveness! mise is more and more popular. I would welcome more direct integration with mise. "feels like magic" is also good!

Yes, we could organize things a little differently. For instance using dataclasses instead of tuples — but it looks good. Let's ship it.

I did a release just as you were working and introduced a conflict in changelog.md. Can you fix the conflict? You could go ahead and show the new feature under a new release 1.76.0 which I'll do today. Edit: done.

@rolandwalker rolandwalker merged commit ac68fbd into dbcli:main Jun 20, 2026
11 checks passed
@rolandwalker

Copy link
Copy Markdown
Contributor

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.

2 participants