From c7ff22ab00bfbacdad0b0ec53efdf2b17757a2a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Tue, 3 Nov 2026 20:37:48 +0100 Subject: [PATCH] chore(env): whitelist DB_APP_ROLE and document it beside the database settings --- .env.example | 6 ++++++ .env.production.example | 8 ++++++++ docker-compose.yml | 5 +++++ scripts/env-manifest.json | 5 +++++ 4 files changed, 24 insertions(+) diff --git a/.env.example b/.env.example index c0efd6658..61a0289df 100644 --- a/.env.example +++ b/.env.example @@ -38,6 +38,12 @@ # echo "POSTGRES_PASSWORD=$(openssl rand -hex 32)" >> .env # Left commented here so that append does not create a duplicate key. Uncomment # and set it directly instead if you prefer to edit the file by hand. + +# The container runs the app as `healthlog_app`, a database role it creates on +# every start that reads and writes rows but cannot change the schema. The +# migrations keep the DATABASE_URL user. "off" keeps the app on that user, if +# you manage database roles yourself (docs/self-hosting/database-role.md). +# DB_APP_ROLE="off" # POSTGRES_PASSWORD="generate-with-openssl-rand-hex-32" diff --git a/.env.production.example b/.env.production.example index b82aae357..9c6ad5dbe 100644 --- a/.env.production.example +++ b/.env.production.example @@ -526,6 +526,14 @@ API_TOKEN_HMAC_KEY="" # Behind such a pooler, set this to 1, true or yes to send no session # settings at all; the pooler's or the database's own defaults then apply. # DATABASE_SESSION_OPTIONS_DISABLED="1" +# +# The app runs as `healthlog_app`, a database role the container creates on +# every start: it reads and writes rows but cannot alter or drop tables or +# create roles. Migrations and restores still use the user in DATABASE_URL. +# Where that user may not create roles (a managed database), the start log +# says so and the app uses DATABASE_URL as given. Set "off" if you manage +# the database roles yourself. See docs/self-hosting/database-role.md. +# DB_APP_ROLE="off" # ----------------------------------------------------------------------------- diff --git a/docker-compose.yml b/docker-compose.yml index b7e7faef3..f10142dc2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -81,6 +81,11 @@ x-healthlog-env: &healthlog_env # 1 sends neither of the two settings above (they ride the libpq `options` # startup parameter, which PgBouncer refuses by default). DATABASE_SESSION_OPTIONS_DISABLED: "${DATABASE_SESSION_OPTIONS_DISABLED:-}" + # The app connects as `healthlog_app`, a role the entrypoint creates that + # reads and writes rows but cannot change the schema; the migrations keep + # the owner above. off keeps the app on the owner (for an operator who + # manages database roles). See docs/self-hosting/database-role.md. + DB_APP_ROLE: "${DB_APP_ROLE:-}" WITHINGS_WEBHOOK_SECRET: "${WITHINGS_WEBHOOK_SECRET:-}" # Overrides the derived `${NEXT_PUBLIC_APP_URL}/api/withings/callback`; # set it when the URL registered with Withings differs from the app's own diff --git a/scripts/env-manifest.json b/scripts/env-manifest.json index 70546fd43..977a50755 100644 --- a/scripts/env-manifest.json +++ b/scripts/env-manifest.json @@ -225,6 +225,11 @@ { "name": "DATABASE_SESSION_OPTIONS_DISABLED", "purpose": "Set to 1, true or yes to send no session settings (statement timeout, work_mem) as the libpq options startup parameter. Needed behind PgBouncer, which refuses that parameter unless it is in ignore_startup_parameters." + }, + { + "name": "DB_APP_ROLE", + "purpose": "auto (default) or off. Auto: after the migrations the entrypoint creates the role healthlog_app, which may read and write rows and run the queue but not change the schema, and starts the app with it in place of the DATABASE_URL user. Off keeps the app on the DATABASE_URL user, for an operator who manages database roles.", + "example": "off" } ] },