fix(wger): read PowerSync settings from the config.yaml file too

Review of #3125 pointed out that the CONFIG_LOCATION config.yaml file -
the mechanism this add-on documents for extra environment variables - does
not reach 89-powersync.sh. Confirmed by reading .templates/01-config_yaml.sh:
it writes every assignment to /.env and injects it into /entrypoint.sh,
/etc/services.d/*/*run* and /etc/cont-init.d/*run*, and 89-powersync.sh
matches none of those globs. 90-run.sh does, which is why Django saw those
values and this script did not.

So a user who configured PS_DATABASE_URI that way got a refusal to start
PowerSync, and file-configured JWT keys were ignored and then overridden by
a freshly generated pair, because the generated keys are appended to /.env
after the file's own lines and the last assignment wins.

The six settings are now read from /.env, which both mechanisms write.
/.env takes precedence over the environment deliberately: that is the
precedence 90-run.sh produces for Django, and this script has to validate
the values Django will actually use.

Also correct the README's PostgreSQL privileges. CREATE SCHEMA ...
AUTHORIZATION requires the creator to be able to SET ROLE to the owner, and
on PostgreSQL 16 and later a CREATEROLE user only receives ADMIN OPTION on
roles it creates because createrole_self_grant defaults to empty - so the
documented non-superuser recipe could not have worked against the Postgres
17 add-on. And warn that both URIs carry a password which the shared
startup code prints to the add-on log unmasked, since neither variable name
matches its secret-name pattern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
BirdNET-Go Addon Builder
2026-10-17 10:59:32 +02:00
parent bca7952e22
commit f4643c020d
3 changed files with 62 additions and 3 deletions

View File

@@ -3,6 +3,7 @@
- Add optional PowerSync support, so the official wger mobile app (2.0.3 and newer) can sync offline (#2950). Set the new `POWERSYNC_ENABLED` option to start a PowerSync service inside the add-on, reached at `<SITE_URL>/ps/` through the add-on's own nginx, exactly as upstream's docker deployment serves it.
- ⚠ PowerSync cannot replicate from SQLite. Enabling it therefore means pointing wger at a Postgres database (for example the Postgres 17 add-on) with `PS_DATABASE_URI`, and **the add-on provides no migration for an existing SQLite database — the Postgres database starts empty, and your current workouts, weight and nutrition data and your user accounts do not follow.** The SQLite file is left untouched, so removing the setting puts you back on it. Read the PowerSync section of the add-on documentation before switching.
- PowerSync settings can be supplied either through the add-on's `env_vars` option or through the `CONFIG_LOCATION` config.yaml file; both are read.
- With `POWERSYNC_ENABLED` unset, nothing changes: the option defaults to off, the nginx configuration is unchanged, no new process runs and the SQLite database stays the default. The PowerSync files ship in the image either way, which makes it about 90 MB larger to download.
## 2.8.0-dev.1 (2026-10-10)

View File

@@ -103,9 +103,28 @@ that you are starting over.
GRANT CREATE ON DATABASE wger TO wger;
```
On PostgreSQL 16 and later — which includes the Postgres 17 add-on — that is not
quite enough. Creating the schema runs `CREATE SCHEMA ... AUTHORIZATION
powersync_storage`, and
[the documentation](https://www.postgresql.org/docs/17/sql-createschema.html) requires
that you "must be able to SET ROLE to that role". A `CREATEROLE` user is only given
`ADMIN OPTION` on the roles it creates, not `SET`, because
[`createrole_self_grant`](https://www.postgresql.org/docs/17/runtime-config-client.html#GUC-CREATEROLE-SELF-GRANT)
defaults to empty. Grant it for the roles wger is about to create:
```sql
ALTER ROLE wger SET createrole_self_grant = 'set, inherit';
```
If the storage role already exists from an earlier attempt, grant it directly instead:
```sql
GRANT powersync_storage TO wger WITH ADMIN OPTION, SET TRUE;
```
The role also needs `REPLICATION` for PowerSync to read the logical WAL. The Postgres
superuser has all of this, which is why pointing at it works, but a role with just
these three grants is the better choice.
superuser has all of this, which is why pointing at it works and is the quickest way
to get going, but a role with just these grants is the better choice.
3. The URL your phone uses to reach wger, in `SITE_URL`. The app is handed
`<SITE_URL>/ps/` as its sync endpoint, so a LAN-only address will not work from
outside your network.
@@ -113,7 +132,7 @@ that you are starting over.
### Add-on configuration
Set `POWERSYNC_ENABLED` to `true` and add the following through the add-on's `env_vars`
option:
option (the `CONFIG_LOCATION` config.yaml file documented above works for these too):
```yaml
env_vars:
@@ -134,6 +153,13 @@ env_vars:
add-on creates. It must be set, it has no useful default.
- `SITE_URL` must be an absolute `http://` or `https://` URL with no path.
> **The two URIs contain passwords, and the add-on prints every variable it loads to its
> log at startup.** The shared startup code masks values whose variable name looks like a
> secret, and these two names do not, so both PostgreSQL passwords appear in the add-on
> log in full — including when the value comes from `!secret`. Treat the add-on log as
> sensitive, and prefer a dedicated wger role with a password you are willing to see
> there over reusing credentials from elsewhere.
The add-on generates the RS256 JWT keypair the app and PowerSync need on first start and
keeps it at `/data/powersync/jwt.env`, so app sessions survive restarts. If you would
rather manage it yourself, generate one with

View File

@@ -34,6 +34,38 @@ DJANGO_WAIT_LOG_EVERY=60
RESTART_DELAY_MIN=5
RESTART_DELAY_MAX=60
#########################
# Settings from the config.yaml file
#########################
# Two mechanisms feed settings in, and only one of them reaches this script on its own.
# 00-global_var.sh injects add-on options and env_vars into every /etc/cont-init.d/*.sh,
# but 01-config_yaml.sh - the CONFIG_LOCATION file this add-on documents for extra
# variables - only writes to /.env and injects into /etc/cont-init.d/*run* , which this
# script is deliberately not named. So read /.env, which both of them write.
#
# /.env wins over the environment on purpose: that is the precedence 90-run.sh produces
# for Django further down, and this script has to validate the values Django will use.
# It is sourced in a subshell because the quoting in there is the shell's own, and the
# same content is already sourced by the upstream entrypoint by way of /data/env.sh.
env_file_value() {
local name="$1"
[ -f "$ENV_FILE" ] || return 0
(
set +u
# shellcheck source=/dev/null
. "$ENV_FILE" > /dev/null 2>&1 || true
printf '%s' "${!name}"
)
}
for _setting in POWERSYNC_ENABLED PS_DATABASE_URI PS_STORAGE_PG_URI SITE_URL \
JWT_PUBLIC_KEY JWT_PRIVATE_KEY; do
_value="$(env_file_value "$_setting")"
[ -n "$_value" ] && export "$_setting=$_value"
done
unset _setting _value
# The Supervisor destroys and recreates the container on every add-on start, so this
# file is normally absent already. An out-of-band restart (docker restart, Portainer)
# does reuse the writable layer, and then a route left over from a previous run would