refactor(secrets): slot-number every generated config key

Makes the convention uniform: if a config key holds a generated value, its name
ends in a slot number. 42 keys across the catalog, up from the 9 database ones
done previously — admin passwords, app keys, tokens, HMAC and auth secrets,
generated usernames and database names. An app needing a second credential of a
kind now just adds _2; nothing is registered anywhere, since the tag name is
derived from the key by tags_processor_app_config_values.

Keys holding an operator-chosen value (CFG_NEXTCLOUD_ADMIN_USER=admin) keep their
names — the slot number is what marks a value as generated.

The rename would have silently cost seven keys their WebUI field mapping. The
frontend resolver matches a mapping key against a config key by equality, _suffix
or prefix_ (apps-manager.js findMatchingCFGKey), so the generic "ADMIN_PASSWORD"
entry stops matching CFG_GITEA_ADMIN_PASSWORD_1 — it neither ends with
_ADMIN_PASSWORD nor starts with ADMIN_PASSWORD_. Rather than loosen the matcher
(PORT_1 relies on its numeric suffix being part of the name), add explicit
entries. Did the same for eight keys that were already unmapped before this
change, so all 42 now render with a label and, where appropriate, masked: the
only one typed as text is Mastodon's VAPID public key, which is public by design.

Verified by simulating the resolver against every app config, and by running each
app in the catalog through fill -> hook -> templating: every secret tag
substitutes, no RANDOMIZED placeholder survives, every compose still parses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
librelad 2026-08-18 19:51:27 +01:00
parent 65167463f9
commit a1541ace23
2 changed files with 111 additions and 7 deletions

View File

@ -156,13 +156,23 @@ initialised with. That is the same desync the old mechanism caused on every
reinstall; the difference is that it now happens at most once, because the values
are preserved from then on.
### Database password keys are now numbered slots
### Every generated secret is now a numbered slot
`CFG_<APP>_DB_PASSWORD` became `CFG_<APP>_DB_PASSWORD_1`, and
`CFG_<APP>_DB_ROOT_PASSWORD` became `CFG_<APP>_DB_ROOT_PASSWORD_1`, so a database
credential is always a numbered slot and an app that needs a second one just adds
`_2`. This also touches **nextcloud** and **bookstack**, which were otherwise
unaffected by the change above.
The convention is now uniform: **if a config key holds a generated value, its name
ends in a slot number.** `CFG_<APP>_DB_PASSWORD` became
`CFG_<APP>_DB_PASSWORD_1`, `CFG_TRAEFIK_ADMIN_PASSWORD` became
`CFG_TRAEFIK_ADMIN_PASSWORD_1`, and so on — 42 keys across the catalog. An app
that needs a second credential of the same kind just adds `_2`; nothing has to be
registered, because the tag name is derived from the key.
Keys holding a value you chose rather than one the installer generated (say
`CFG_NEXTCLOUD_ADMIN_USER=admin`) are unchanged — the slot number is what marks a
value as generated.
This reaches apps that had nothing to do with the compose-side generator problem
above, including **adguard, authelia, bookstack, gitea, gluetun, headscale,
invidious, moneyapp, nextcloud, pihole, speedtest, stalwart, traefik, vaultwarden**
and **wireguard**.
A rename is a delete plus an add as far as config reconciliation is concerned: the
old key is dropped and the new one arrives holding its `RANDOMIZED*` placeholder,
@ -172,10 +182,14 @@ reinstalling — reconciliation leaves the previous file as a hidden
`.<app>.config.bak` sibling, so the old value is still there:
```bash
grep DB_PASSWORD <containers-dir>/<app>/.<app>.config.bak
grep -E '=RANDOMIZED|PASSWORD|SECRET|TOKEN|KEY' <containers-dir>/<app>/.<app>.config.bak
```
Paste each value into the matching `_1` key in `<containers-dir>/<app>/<app>.config`.
For a Nextcloud install that means `CFG_NEXTCLOUD_ADMIN_PASSWORD_1`,
`CFG_NEXTCLOUD_DB_PASSWORD_1` and `CFG_NEXTCLOUD_DB_ROOT_PASSWORD_1` — the two
database ones are the pair that matters, because MariaDB will keep rejecting a
regenerated password.
### Mastodon web push

View File

@ -462,6 +462,96 @@ PORTEOF
"tooltip": "Object store root password (auto-generated), shared by MinIO and the bucket-creation job.",
"advanced": true
},
"ADGUARD_ADMIN_PASSWORD_1": {
"category": "general",
"label": "AdGuard Admin Password",
"type": "password",
"tooltip": "Password for the AdGuard Home admin account (auto-generated; persists across reinstalls)"
},
"GITEA_ADMIN_PASSWORD_1": {
"category": "general",
"label": "Gitea Admin Password",
"type": "password",
"tooltip": "Password for the Gitea administrator account (auto-generated; persists across reinstalls)"
},
"GITEA_METRICS_TOKEN_1": {
"category": "advanced",
"label": "Metrics Token",
"type": "password",
"tooltip": "Bearer token Prometheus uses to scrape Gitea's metrics endpoint (auto-generated)",
"advanced": true
},
"HEADSCALE_BASIC_AUTH_PASS_1": {
"category": "general",
"label": "Basic Auth Password",
"type": "password",
"tooltip": "Password protecting the Headscale endpoint (auto-generated; persists across reinstalls)"
},
"INVIDIOUS_ADMIN_PASSWORD_1": {
"category": "general",
"label": "Invidious Admin Password",
"type": "password",
"tooltip": "Password for the Invidious administrator account (auto-generated; persists across reinstalls)"
},
"INVIDIOUS_HMAC_KEY_1": {
"category": "advanced",
"label": "HMAC Key",
"type": "password",
"tooltip": "Signs Invidious session tokens (auto-generated). Changing it logs every user out.",
"advanced": true
},
"MATRIX_ADMIN_PASSWORD_1": {
"category": "general",
"label": "Matrix Admin Password",
"type": "password",
"tooltip": "Password for the first Synapse admin account, created on install (auto-generated)"
},
"MONEYAPP_AUTH_SECRET_1": {
"category": "advanced",
"label": "Auth Secret",
"type": "password",
"tooltip": "Signs session tokens (auto-generated). Changing it logs every user out.",
"advanced": true
},
"STALWART_ADMIN_PASSWORD_1": {
"category": "general",
"label": "Stalwart Admin Password",
"type": "password",
"tooltip": "Password for the Stalwart administrator account (auto-generated; persists across reinstalls)"
},
"STALWART_FIRST_MAILBOX_PASSWORD_1": {
"category": "general",
"label": "First Mailbox Password",
"type": "password",
"tooltip": "Password for the mailbox created on install (auto-generated; persists across reinstalls)"
},
"TRAEFIK_ADMIN_PASSWORD_1": {
"category": "general",
"label": "Traefik Admin Password",
"type": "password",
"tooltip": "Password for the Traefik dashboard account (auto-generated; persists across reinstalls)"
},
"BOOKSTACK_APP_KEY_1": {
"category": "advanced",
"label": "Application Key",
"type": "password",
"tooltip": "Laravel APP_KEY — encrypts session data (auto-generated). Changing it invalidates existing sessions.",
"advanced": true
},
"BOOKSTACK_DB_PASSWORD_1": {
"category": "advanced",
"label": "Database Password",
"type": "password",
"tooltip": "MariaDB password for the BookStack user (auto-generated; persists across reinstalls)",
"advanced": true
},
"BOOKSTACK_DB_ROOT_PASSWORD_1": {
"category": "advanced",
"label": "Database Root Password",
"type": "password",
"tooltip": "MariaDB root password (auto-generated; kept separate from the app user password)",
"advanced": true
},
"VAULTWARDEN_ADMIN_TOKEN_1": {
"category": "general",
"label": "Vaultwarden Admin Token",