Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ Newest first. `Unreleased` is what is on `main` and not yet tagged.

## Unreleased

### A `DATABASE_URL` with a port of zero is refused at start-up

`postgres://…:0/…` parsed and booted, and every query then failed against a port nothing listens
on. Ports outside 1-65535 are refused with a sentence naming `DATABASE_URL` before a socket is
ever opened.

### `bun run dev` no longer starts a routines worker that cannot start

`bun run dev` fanned out across every workspace, and one of them is the routines worker. That worker
Expand Down
20 changes: 19 additions & 1 deletion server/src/db/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,28 @@ function addressOf(databaseUrl: string) {
*/
const connection = Object.fromEntries(url.searchParams);

/*
* A port that is not a port is refused before a socket is ever opened.
*
* `new URL` already rejects `:65536` and above, but `:0` parses to `"0"` and would travel
* into `new SQL({ port: 0 })` as `0`. Boot then succeeds and every query fails against a port
* nothing listens on, instead of the start-up refusal every other malformed address here gets.
* Postgres ports are 1-65535, the same range the server's own `PORT`/`SERVER_PORT` enforces.
*/
let port = 5432;
if (url.port !== "") {
port = Number(url.port);
if (!Number.isInteger(port) || port < 1 || port > 65535) {
throw new TypeError(
"DATABASE_URL names a port that is not between 1 and 65535.",
);
}
}

return {
adapter: "postgres" as const,
hostname: url.hostname,
port: url.port === "" ? 5432 : Number(url.port),
port,
username: decodePart(url.username, "username"),
password: decodePart(url.password, "password"),
database,
Expand Down
11 changes: 11 additions & 0 deletions server/tests/db-client-address.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ describe("the database address", () => {
).toThrow(/names no database/);
});

test("refuses a port of zero instead of connecting nowhere", () => {
/*
* `new URL` accepts `:0` and reports the port as `"0"`, so without this check boot succeeds
* and every query fails against a port nothing listens on. A refusal here names the variable
* and the range, the way every other malformed address does.
*/
expect(() =>
createDatabase("postgres://openbot:openbot@127.0.0.1:0/openbot"),
).toThrow(/DATABASE_URL names a port that is not between 1 and 65535/);
});

test("refuses a password holding a percent that starts no escape, naming the part", () => {
/*
* `new URL` accepts this and `decodeURIComponent` does not, so the refusal used to be a bare
Expand Down