Skip to content

Conversation

@brandur
Copy link
Contributor

@brandur brandur commented Dec 24, 2024

This one's related to #676, in which it was reported that database URLs
work somewhat suboptimally when dealing with passwords that contain
characters that traditionally require encoding in URLs (e.g. various
types of brackets).

I was originally going down a path wherein we'd offer an alternative
that'd involve adding additional CLI parameters that could work as an
alternative to --database-url based on these ones from psql:

Connection options:
  -h, --host=HOSTNAME      database server host or socket directory (default: "local socket")
  -p, --port=PORT          database server port (default: "5432")
  -U, --username=USERNAME  database user name (default: "brandur")
  -w, --no-password        never prompt for password
  -W, --password           force password prompt (should happen automatically)

However, as I implemented it, I found that pgx somewhat surprisingly
doesn't allow you to instantiate your own config struct. If not parsed
from a URL, it requires you to assemble a more traditional connection
string like user=XX pass=YY database=ZZ and parse that, which
introduces its own special character encoding challenges when using
something like a space, equal, or quotation mark.

Digging further I realized that pgx automatically supports the whole
set of PG* environmental variables like PGHOST, PGPORT, PGUSER,
and supporting these would add a solid way of using the River CLI
without a database URL using a common interface that's also supported
by psql and a variety of other pieces of related software.

Even better, since we expect most people to be using a database URL most
of the time, env vars give us a way to provide an alternative, but one
which doesn't add any complication to the existing CLI interface. In
general fewer parameters is better because it keeps the help docs easy
to understand.

Another advantage is that this will technically let us support more
complex connection setups involving things like TLS certificates. All of
these vars are supported, and none of which had a great answer with a
database URL:

  • PGSSLCERT
  • PGSSLKEY
  • PGSSLROOTCERT
  • PGSSLPASSWORD

Fixes #676.

@brandur brandur force-pushed the brandur-pg-env-vars branch 10 times, most recently from e473535 to 4c7a74b Compare December 24, 2024 06:16
@brandur brandur requested a review from bgentry December 24, 2024 06:19
@brandur brandur force-pushed the brandur-pg-env-vars branch 4 times, most recently from afce487 to 64837de Compare December 24, 2024 18:32
brandur added a commit to riverqueue/riverui that referenced this pull request Dec 24, 2024
Accept the standard set of `PG*` env vars as an alternative to database
configuration (e.g. `PGHOST`, `PGDATABASE`, etc.). This is mostly driven
by having done something similar for the CLI in [1], but was also
requested in #249. This turns out to be quite easy to do because pgx
does all the heavy lifting.

As noted in [1], a bonus of this is that it adds some additional
configuration options that aren't very easily doable right now, for
example around the use of an SSL certificate to connect to Postgres. We
get automatic support for these vars:

* `PGSSLCERT`
* `PGSSLKEY`
* `PGSSLROOTCERT`
* `PGSSLPASSWORD`

As part of this I also ended up rearranging some things in `main.go`.
Not strongly married to this design, but the idea is to get it into a
place where we can write tests for it, which previously wasn't possible.

[1] riverqueue/river#702
brandur added a commit to riverqueue/riverui that referenced this pull request Dec 24, 2024
Accept the standard set of `PG*` env vars as an alternative to database
configuration (e.g. `PGHOST`, `PGDATABASE`, etc.). This is mostly driven
by having done something similar for the CLI in [1], but was also
requested in #249. This turns out to be quite easy to do because pgx
does all the heavy lifting.

As noted in [1], a bonus of this is that it adds some additional
configuration options that aren't very easily doable right now, for
example around the use of an SSL certificate to connect to Postgres. We
get automatic support for these vars:

* `PGSSLCERT`
* `PGSSLKEY`
* `PGSSLROOTCERT`
* `PGSSLPASSWORD`

As part of this I also ended up rearranging some things in `main.go`.
Not strongly married to this design, but the idea is to get it into a
place where we can write tests for it, which previously wasn't possible.

Fixes #249.

[1] riverqueue/river#702
brandur added a commit to riverqueue/riverui that referenced this pull request Dec 24, 2024
Accept the standard set of `PG*` env vars as an alternative to database
configuration (e.g. `PGHOST`, `PGDATABASE`, etc.). This is mostly driven
by having done something similar for the CLI in [1], but was also
requested in #249. This turns out to be quite easy to do because pgx
does all the heavy lifting.

As noted in [1], a bonus of this is that it adds some additional
configuration options that aren't very easily doable right now, for
example around the use of an SSL certificate to connect to Postgres. We
get automatic support for these vars:

* `PGSSLCERT`
* `PGSSLKEY`
* `PGSSLROOTCERT`
* `PGSSLPASSWORD`

As part of this I also ended up rearranging some things in `main.go`.
Not strongly married to this design, but the idea is to get it into a
place where we can write tests for it, which previously wasn't possible.

Fixes #249.

[1] riverqueue/river#702
brandur added a commit to riverqueue/riverui that referenced this pull request Dec 24, 2024
Accept the standard set of `PG*` env vars as an alternative to database
configuration (e.g. `PGHOST`, `PGDATABASE`, etc.). This is mostly driven
by having done something similar for the CLI in [1], but was also
requested in #249. This turns out to be quite easy to do because pgx
does all the heavy lifting.

As noted in [1], a bonus of this is that it adds some additional
configuration options that aren't very easily doable right now, for
example around the use of an SSL certificate to connect to Postgres. We
get automatic support for these vars:

* `PGSSLCERT`
* `PGSSLKEY`
* `PGSSLROOTCERT`
* `PGSSLPASSWORD`

As part of this I also ended up rearranging some things in `main.go`.
Not strongly married to this design, but the idea is to get it into a
place where we can write tests for it, which previously wasn't possible.

Fixes #249.

[1] riverqueue/river#702
Copy link
Contributor

@bgentry bgentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! :shipit: aside from the one commented code nit

Comment on lines 179 to 184
func pgEnvConfigured() bool {
// Consider these two vars the bare minimum for an env-based configuration.
// return os.Getenv("PGHOST") != "" && os.Getenv("PGDATABASE") != ""
return os.Getenv("PGDATABASE") != ""
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some commented code in here and a comment which only lines up with the commented variant (not the active one)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch. I changed my mind on this one. PGHOST defaults nicely to localhost so it seems okay to assume that PGDATABASE could be considered a bare minimum viable configuration.

@bgentry
Copy link
Contributor

bgentry commented Dec 24, 2024

Oh, needs changelog too 🙏

@brandur brandur force-pushed the brandur-pg-env-vars branch from 64837de to 03b64d4 Compare December 24, 2024 22:25
This one's related to #676, in which it was reported that database URLs
work somewhat suboptimally when dealing with passwords that contain
characters that traditionally require encoding in URLs (e.g. various
types of brackets).

I was originally going down a path wherein we'd offer an alternative
that'd involve adding additional CLI parameters that could work as an
alternative to `--database-url` based on these ones from psql:

    Connection options:
      -h, --host=HOSTNAME      database server host or socket directory (default: "local socket")
      -p, --port=PORT          database server port (default: "5432")
      -U, --username=USERNAME  database user name (default: "brandur")
      -w, --no-password        never prompt for password
      -W, --password           force password prompt (should happen automatically)

However, as I implemented it, I found that pgx somewhat surprisingly
doesn't allow you to instantiate your own config struct. If not parsed
from a URL, it requires you to assemble a more traditional connection
string like `user=XX pass=YY database=ZZ` and parse that, which
introduces its own special character encoding challenges when using
something like a space, equal, or quotation mark.

Digging further I realized that pgx automatically supports the whole
set of PG* environmental variables like `PGHOST`, `PGPORT`, `PGUSER`,
and supporting these would add a solid way of using the River CLI
without a database URL using a common interface that's also supported
by psql and a variety of other pieces of related software.

Even better, since we expect most people to be using a database URL most
of the time, env vars give us a way to provide an alternative, but one
which doesn't add any complication to the existing CLI interface. In
general fewer parameters is better because it keeps the help docs easy
to understand.

Another advantage is that this will technically let us support more
complex connection setups involving things like TLS certificates. All of
these vars are supported, and none of which had a great answer with a
database URL:

* `PGSSLCERT`
* `PGSSLKEY`
* `PGSSLROOTCERT`
* `PGSSLPASSWORD`

Fixes #676.
@brandur brandur force-pushed the brandur-pg-env-vars branch from 03b64d4 to 5b34e1c Compare December 24, 2024 22:28
@brandur
Copy link
Contributor Author

brandur commented Dec 24, 2024

Added changelog.

@brandur brandur merged commit d73c280 into master Dec 24, 2024
10 checks passed
@brandur brandur deleted the brandur-pg-env-vars branch December 24, 2024 22:31
brandur added a commit to riverqueue/riverui that referenced this pull request Jan 4, 2025
Accept the standard set of `PG*` env vars as an alternative to database
configuration (e.g. `PGHOST`, `PGDATABASE`, etc.). This is mostly driven
by having done something similar for the CLI in [1], but was also
requested in #249. This turns out to be quite easy to do because pgx
does all the heavy lifting.

As noted in [1], a bonus of this is that it adds some additional
configuration options that aren't very easily doable right now, for
example around the use of an SSL certificate to connect to Postgres. We
get automatic support for these vars:

* `PGSSLCERT`
* `PGSSLKEY`
* `PGSSLROOTCERT`
* `PGSSLPASSWORD`

As part of this I also ended up rearranging some things in `main.go`.
Not strongly married to this design, but the idea is to get it into a
place where we can write tests for it, which previously wasn't possible.

Fixes #249.

[1] riverqueue/river#702
brandur added a commit to riverqueue/riverui that referenced this pull request Jan 4, 2025
Accept the standard set of `PG*` env vars as an alternative to database
configuration (e.g. `PGHOST`, `PGDATABASE`, etc.). This is mostly driven
by having done something similar for the CLI in [1], but was also
requested in #249. This turns out to be quite easy to do because pgx
does all the heavy lifting.

As noted in [1], a bonus of this is that it adds some additional
configuration options that aren't very easily doable right now, for
example around the use of an SSL certificate to connect to Postgres. We
get automatic support for these vars:

* `PGSSLCERT`
* `PGSSLKEY`
* `PGSSLROOTCERT`
* `PGSSLPASSWORD`

As part of this I also ended up rearranging some things in `main.go`.
Not strongly married to this design, but the idea is to get it into a
place where we can write tests for it, which previously wasn't possible.

Fixes #249.

[1] riverqueue/river#702
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.

Password in database URL should url encode special characters

3 participants