From 1e7772ad290111c803f3f5f60dc3e2e888f60af6 Mon Sep 17 00:00:00 2001 From: "Warre (hal-developer)" Date: Thu, 9 Jul 2026 19:46:14 +0200 Subject: [PATCH] fix(db): grant app user permissions on players and games tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PostgreSQL 15+ revokes CREATE from non-superusers in public schema by default. Child 1's migration created the tables as postgres superuser, leaving the txt_game_scores app user with no privileges — causing "permission denied" on every request in production. Adds a numbered provision migration to GRANT SELECT/INSERT/UPDATE on players and games, plus USAGE/SELECT on games_id_seq, to the app user. Task: d1c49d59-57bd-4eba-9e22-f25a04157ad4 --- .../postgres/001-grant-permissions.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 migrations/provision/postgres/001-grant-permissions.ts diff --git a/migrations/provision/postgres/001-grant-permissions.ts b/migrations/provision/postgres/001-grant-permissions.ts new file mode 100644 index 0000000..4d889cc --- /dev/null +++ b/migrations/provision/postgres/001-grant-permissions.ts @@ -0,0 +1,29 @@ +import pg from "pg"; + +const client = new pg.Client({ + host: process.env.PROVISION_HOST, + port: parseInt(process.env.PROVISION_PORT ?? "5432"), + user: process.env.PROVISION_USER, + password: process.env.PROVISION_PASSWORD, + database: process.env.PROVISION_DATABASE, +}); + +await client.connect(); + +try { + // The HAL postgres provisioner names the app user identically to the database. + // PROVISION_DATABASE = "txt_game_scores" = the app user that server.mjs connects as. + const appUser = process.env.PROVISION_DATABASE as string; + + await client.query( + `GRANT SELECT, INSERT, UPDATE ON TABLE players, games TO "${appUser}"` + ); + + await client.query( + `GRANT USAGE, SELECT ON SEQUENCE games_id_seq TO "${appUser}"` + ); + + console.log(`[txt-game migration-001] permissions granted to ${appUser}`); +} finally { + await client.end(); +}