Compare commits

..

3 Commits

Author SHA1 Message Date
mealie-commit-bot[bot]
e24187fefb chore: bump version to v3.19.2 2026-05-29 04:11:50 +00:00
Michael Genson
396fcd5ee4 fix: Ensure secret key is not empty (#7701) 2026-05-28 23:09:31 -05:00
renovate[bot]
5a3d202879 chore(deps): lock file maintenance (#7697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-27 20:09:07 +00:00
9 changed files with 143 additions and 97 deletions

View File

@@ -31,7 +31,7 @@ To deploy mealie on your local network, it is highly recommended to use Docker t
We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do: We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do:
1. Take a backup just in case! 1. Take a backup just in case!
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.19.1` 2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.19.2`
3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access. 3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access.
4. Restart the container 4. Restart the container

View File

@@ -10,7 +10,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In
```yaml ```yaml
services: services:
mealie: mealie:
image: ghcr.io/mealie-recipes/mealie:v3.19.1 # (3) image: ghcr.io/mealie-recipes/mealie:v3.19.2 # (3)
container_name: mealie container_name: mealie
restart: always restart: always
ports: ports:

View File

@@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th
```yaml ```yaml
services: services:
mealie: mealie:
image: ghcr.io/mealie-recipes/mealie:v3.19.1 # (3) image: ghcr.io/mealie-recipes/mealie:v3.19.2 # (3)
container_name: mealie container_name: mealie
restart: always restart: always
ports: ports:

View File

@@ -1,6 +1,6 @@
{ {
"name": "mealie", "name": "mealie",
"version": "3.19.1", "version": "3.19.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "nuxt dev", "dev": "nuxt dev",

View File

@@ -3278,9 +3278,9 @@
integrity sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA== integrity sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA==
"@swc/helpers@^0.5.12": "@swc/helpers@^0.5.12":
version "0.5.22" version "0.5.23"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.22.tgz#914130a189205cef611b75948c93b95adf6cf11b" resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.23.tgz#19287d0d86d962b111376039a50c792902c9a86a"
integrity sha512-/e2Ly3Docn9kYByap6TV4oquJ3wQuz3c+kC74riqtkwU9CwTMeuj6t2rW+bRr4pyOx/CYQM4wr0RgaKQwGEz0A== integrity sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==
dependencies: dependencies:
tslib "^2.8.0" tslib "^2.8.0"
@@ -3745,47 +3745,47 @@
"@babel/parser" "^7.28.4" "@babel/parser" "^7.28.4"
"@vue/compiler-sfc" "^3.5.22" "@vue/compiler-sfc" "^3.5.22"
"@vue/compiler-core@3.5.34": "@vue/compiler-core@3.5.35":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.34.tgz#6d84a46b7fdf1162cf8225aa2be42918a76ab827" resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.35.tgz#e789c89b0fee47683e5300c715bb9243c07a6bbd"
integrity sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw== integrity sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==
dependencies: dependencies:
"@babel/parser" "^7.29.3" "@babel/parser" "^7.29.3"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
entities "^7.0.1" entities "^7.0.1"
estree-walker "^2.0.2" estree-walker "^2.0.2"
source-map-js "^1.2.1" source-map-js "^1.2.1"
"@vue/compiler-dom@3.5.34", "@vue/compiler-dom@^3.2.45": "@vue/compiler-dom@3.5.35", "@vue/compiler-dom@^3.2.45":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.34.tgz#6b943e8106822868e74d66c615432bbba6a589be" resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz#523a42dcc49af499588c51e3db52e672b9491325"
integrity sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw== integrity sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==
dependencies: dependencies:
"@vue/compiler-core" "3.5.34" "@vue/compiler-core" "3.5.35"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
"@vue/compiler-sfc@3.5.34", "@vue/compiler-sfc@^3.5.13", "@vue/compiler-sfc@^3.5.22": "@vue/compiler-sfc@3.5.35", "@vue/compiler-sfc@^3.5.13", "@vue/compiler-sfc@^3.5.22":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.34.tgz#93b6aeb3393cd7b3c71ff07f28879558f72e5f1d" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz#e0310f48a37cf326b5c926ef0006d75c87e34d33"
integrity sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg== integrity sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==
dependencies: dependencies:
"@babel/parser" "^7.29.3" "@babel/parser" "^7.29.3"
"@vue/compiler-core" "3.5.34" "@vue/compiler-core" "3.5.35"
"@vue/compiler-dom" "3.5.34" "@vue/compiler-dom" "3.5.35"
"@vue/compiler-ssr" "3.5.34" "@vue/compiler-ssr" "3.5.35"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
estree-walker "^2.0.2" estree-walker "^2.0.2"
magic-string "^0.30.21" magic-string "^0.30.21"
postcss "^8.5.14" postcss "^8.5.15"
source-map-js "^1.2.1" source-map-js "^1.2.1"
"@vue/compiler-ssr@3.5.34": "@vue/compiler-ssr@3.5.35":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.34.tgz#0561ae3f9b81564929a8544769eee9cc92a76c42" resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz#206cfc3d741c43d605ef0629509c00166022783b"
integrity sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ== integrity sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==
dependencies: dependencies:
"@vue/compiler-dom" "3.5.34" "@vue/compiler-dom" "3.5.35"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
"@vue/devtools-api@^6.5.0", "@vue/devtools-api@^6.6.4": "@vue/devtools-api@^6.5.0", "@vue/devtools-api@^6.6.4":
version "6.6.4" version "6.6.4"
@@ -3822,43 +3822,43 @@
resolved "https://registry.yarnpkg.com/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz#1399660db04b7426a873b5985a548a6a7397fddd" resolved "https://registry.yarnpkg.com/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz#1399660db04b7426a873b5985a548a6a7397fddd"
integrity sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw== integrity sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==
"@vue/reactivity@3.5.34": "@vue/reactivity@3.5.35":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.34.tgz#d41355f7e8b1784078ea498ec7d974e4e26d4b74" resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.35.tgz#45b9794ca77ff5ade2eee74bcdeacbc00ae8e7a2"
integrity sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ== integrity sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==
dependencies: dependencies:
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
"@vue/runtime-core@3.5.34": "@vue/runtime-core@3.5.35":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.34.tgz#1b4ce2ebf94d670acbd8f22d92e45908e2a2c96a" resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.35.tgz#6f16679bc95ffe38af38c5d0bc1414ed4277458e"
integrity sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw== integrity sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==
dependencies: dependencies:
"@vue/reactivity" "3.5.34" "@vue/reactivity" "3.5.35"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
"@vue/runtime-dom@3.5.34": "@vue/runtime-dom@3.5.35":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.34.tgz#1b4e5c009fe9d6ce682cfc2372da4abd40614d29" resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz#473f0fbf97b82652780ac9e6bb5873f7c0dde7e7"
integrity sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg== integrity sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==
dependencies: dependencies:
"@vue/reactivity" "3.5.34" "@vue/reactivity" "3.5.35"
"@vue/runtime-core" "3.5.34" "@vue/runtime-core" "3.5.35"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
csstype "^3.2.3" csstype "^3.2.3"
"@vue/server-renderer@3.5.34": "@vue/server-renderer@3.5.35":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.34.tgz#e0776f839312b4111fb5bd742a70f435298a3e21" resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.35.tgz#31c7b473de1000472444a0c0a336d1e799b209c3"
integrity sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew== integrity sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==
dependencies: dependencies:
"@vue/compiler-ssr" "3.5.34" "@vue/compiler-ssr" "3.5.35"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
"@vue/shared@3.5.34", "@vue/shared@^3.5.22", "@vue/shared@^3.5.34": "@vue/shared@3.5.35", "@vue/shared@^3.5.22", "@vue/shared@^3.5.34":
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.34.tgz#665f2b2fd600f6c180668423909a6fde64cbfccd" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.35.tgz#192eb3d720c40715db79313454c4937432a4e86d"
integrity sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA== integrity sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==
"@vuetify/loader-shared@^2.1.2": "@vuetify/loader-shared@^2.1.2":
version "2.1.2" version "2.1.2"
@@ -5027,9 +5027,9 @@ domhandler@^5.0.2, domhandler@^5.0.3:
domelementtype "^2.3.0" domelementtype "^2.3.0"
dompurify@^3.4.5: dompurify@^3.4.5:
version "3.4.6" version "3.4.7"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.4.6.tgz#8f73010d14a46cd9781bbd3630f3bcef025a2111" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.4.7.tgz#e2702ea4fd5d83467f1baef62309466ce7d44a82"
integrity sha512-+7gzEI8trIIQkVCvQ3ucGtNfH3nOmDgVTzc62rAAOlMxLth78pwpPoZCPc7CyRzAQF89MqcfPdEWkDwnjgqktg== integrity sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==
optionalDependencies: optionalDependencies:
"@types/trusted-types" "^2.0.7" "@types/trusted-types" "^2.0.7"
@@ -7157,9 +7157,9 @@ lru-cache@^10.2.0:
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
lru-cache@^11.0.0, lru-cache@^11.2.7, lru-cache@^11.3.5: lru-cache@^11.0.0, lru-cache@^11.2.7, lru-cache@^11.3.5:
version "11.5.0" version "11.5.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.0.tgz#14117229fd25bc9c67936e32de90ca047488c97a" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.1.tgz#f3daa3540847b9737ebc02499ddb36765e54db4a"
integrity sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA== integrity sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==
lru-cache@^5.1.1: lru-cache@^5.1.1:
version "5.1.1" version "5.1.1"
@@ -8281,7 +8281,7 @@ postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@^8.5.14, postcss@^8.5.6: postcss@^8.5.14, postcss@^8.5.15, postcss@^8.5.6:
version "8.5.15" version "8.5.15"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.15.tgz#d1eaf677a324e9ec02196da2d3fecf4a0b9a735c" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.15.tgz#d1eaf677a324e9ec02196da2d3fecf4a0b9a735c"
integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A== integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==
@@ -9514,9 +9514,9 @@ tinybench@^2.9.0:
integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==
tinyclip@^0.1.12: tinyclip@^0.1.12:
version "0.1.12" version "0.1.13"
resolved "https://registry.yarnpkg.com/tinyclip/-/tinyclip-0.1.12.tgz#f3e91243f50c1a336103539b941782b417b9f1c0" resolved "https://registry.yarnpkg.com/tinyclip/-/tinyclip-0.1.13.tgz#aafa818c5378f65fd375b9d3981eadd6c784b919"
integrity sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA== integrity sha512-8OqlXQ35euK9+e7L68u8UwcODxkHoIkjbGsgXuARKNyQ5G6xt8nw1YPeMbxMLgCPFkToU+UEK5j05t2t8edKpQ==
tinyexec@^0.3.2: tinyexec@^0.3.2:
version "0.3.2" version "0.3.2"
@@ -10387,15 +10387,15 @@ vue-router@^5.0.7:
yaml "^2.8.2" yaml "^2.8.2"
vue@^3.4, vue@^3.5.13, vue@^3.5.34: vue@^3.4, vue@^3.5.13, vue@^3.5.34:
version "3.5.34" version "3.5.35"
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.34.tgz#3b256eb30964416af6406a795fcfd7a5773a93c5" resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.35.tgz#ba502479bd781825514c8af0f40744eeeb6223d6"
integrity sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA== integrity sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==
dependencies: dependencies:
"@vue/compiler-dom" "3.5.34" "@vue/compiler-dom" "3.5.35"
"@vue/compiler-sfc" "3.5.34" "@vue/compiler-sfc" "3.5.35"
"@vue/runtime-dom" "3.5.34" "@vue/runtime-dom" "3.5.35"
"@vue/server-renderer" "3.5.34" "@vue/server-renderer" "3.5.35"
"@vue/shared" "3.5.34" "@vue/shared" "3.5.35"
vuetify-nuxt-module@^0.19.5: vuetify-nuxt-module@^0.19.5:
version "0.19.5" version "0.19.5"

View File

@@ -50,13 +50,19 @@ def determine_secrets(data_dir: Path, secret: str, production: bool) -> str:
secrets_file = data_dir.joinpath(secret) secrets_file = data_dir.joinpath(secret)
if secrets_file.is_file(): if secrets_file.is_file():
with open(secrets_file) as f: with open(secrets_file) as f:
return f.read() existing_secret = f.read().strip()
else: if existing_secret:
data_dir.mkdir(parents=True, exist_ok=True) return existing_secret
with open(secrets_file, "w") as f:
new_secret = secrets.token_hex(32) data_dir.mkdir(parents=True, exist_ok=True)
f.write(new_secret) new_secret = secrets.token_hex(32)
return new_secret tmp_file = secrets_file.with_suffix(".tmp")
with open(tmp_file, "w") as f:
f.write(new_secret)
f.flush()
os.fsync(f.fileno())
tmp_file.replace(secrets_file)
return new_secret
def get_secrets_dir() -> str | None: def get_secrets_dir() -> str | None:

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "mealie" name = "mealie"
version = "3.19.1" version = "3.19.2"
description = "A Recipe Manager" description = "A Recipe Manager"
authors = [{ name = "Hayden", email = "hay-kot@pm.me" }] authors = [{ name = "Hayden", email = "hay-kot@pm.me" }]
license = "AGPL-3.0-only" license = "AGPL-3.0-only"
@@ -71,7 +71,7 @@ dev = [
"pre-commit==4.6.0", "pre-commit==4.6.0",
"pylint==4.0.5", "pylint==4.0.5",
"pytest==9.0.3", "pytest==9.0.3",
"pytest-asyncio==1.4.0", "pytest-asyncio==1.3.0",
"rich==15.0.0", "rich==15.0.0",
"ruff==0.15.14", "ruff==0.15.14",
"types-PyYAML==6.0.12.20260518", "types-PyYAML==6.0.12.20260518",

View File

@@ -1,12 +1,13 @@
import json import json
import re import re
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path
from typing import Any from typing import Any
import pytest import pytest
from mealie.core.config import get_app_settings from mealie.core.config import get_app_settings
from mealie.core.settings.settings import AppSettings from mealie.core.settings.settings import AppSettings, determine_secrets
def test_non_default_settings(monkeypatch): def test_non_default_settings(monkeypatch):
@@ -367,3 +368,42 @@ def test_sensitive_settings_mask(monkeypatch: pytest.MonkeyPatch):
for setting in sensitive_settings: for setting in sensitive_settings:
assert settings[setting] == "*****" assert settings[setting] == "*****"
assert settings_json[setting] == "*****" assert settings_json[setting] == "*****"
class DetermineSecretsTests:
def test_non_production_returns_fixed_key(self, tmp_path: Path):
result = determine_secrets(tmp_path, ".secret", production=False)
assert result == "shh-secret-test-key"
def test_generates_secret_when_file_missing(self, tmp_path: Path):
result = determine_secrets(tmp_path, ".secret", production=True)
assert result
assert (tmp_path / ".secret").read_text() == result
def test_reuses_existing_secret(self, tmp_path: Path):
(tmp_path / ".secret").write_text("existing-secret")
result = determine_secrets(tmp_path, ".secret", production=True)
assert result == "existing-secret"
def test_regenerates_when_file_is_empty(self, tmp_path: Path):
(tmp_path / ".secret").write_text("")
result = determine_secrets(tmp_path, ".secret", production=True)
assert result
assert (tmp_path / ".secret").read_text() == result
def test_regenerates_when_file_is_whitespace_only(self, tmp_path: Path):
(tmp_path / ".secret").write_text(" \n ")
result = determine_secrets(tmp_path, ".secret", production=True)
assert result
assert (tmp_path / ".secret").read_text() == result
def test_generates_unique_secrets(self, tmp_path: Path):
dir_a = tmp_path / "a"
dir_b = tmp_path / "b"
result_a = determine_secrets(dir_a, ".secret", production=True)
result_b = determine_secrets(dir_b, ".secret", production=True)
assert result_a != result_b
def test_no_tmp_file_left_after_write(self, tmp_path: Path):
determine_secrets(tmp_path, ".secret", production=True)
assert not (tmp_path / ".tmp").exists()

16
uv.lock generated
View File

@@ -750,14 +750,14 @@ wheels = [
[[package]] [[package]]
name = "joserfc" name = "joserfc"
version = "1.6.7" version = "1.6.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "cryptography" }, { name = "cryptography" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/1b/cb/52e479f20804904f5df20ac4539d292dcecd1287aaa33cba1d1def1d9d8e/joserfc-1.6.7.tar.gz", hash = "sha256:6999fe89457069ecacd8cc797c88a805f83054dd883333fa0409f74b46479fd7", size = 232158, upload-time = "2026-05-23T01:46:44.069Z" } sdist = { url = "https://files.pythonhosted.org/packages/5d/ac/d4fd5b30f82900eac60d765f179f0ba005825ac462cc8ced6e13ec685ab3/joserfc-1.6.8.tar.gz", hash = "sha256:878620c553a6ebdd76ccdc356782fee3f735f21a356d079a546b42a4670ace5f", size = 232930, upload-time = "2026-05-27T03:22:37.819Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/c5/e4/bcf6718b5662894c6831f46296b73cd4b1a2e90c20b6d437e20c4997388c/joserfc-1.6.7-py3-none-any.whl", hash = "sha256:9e51e4a64840aa1734a058258e80a4480e2ff2d5686e480e7c92c954a92fbe05", size = 70603, upload-time = "2026-05-23T01:46:42.129Z" }, { url = "https://files.pythonhosted.org/packages/98/8c/5cdce2cf3ce8155849baf9a5e2ce77e89dc87ec3bdb38259e5d85fbc45bd/joserfc-1.6.8-py3-none-any.whl", hash = "sha256:22fb31a69094a5e6f44632002a9df2c30c941fc6c8ce1b037e92c03de954cf9f", size = 70927, upload-time = "2026-05-27T03:22:35.796Z" },
] ]
[[package]] [[package]]
@@ -897,7 +897,7 @@ wheels = [
[[package]] [[package]]
name = "mealie" name = "mealie"
version = "3.19.1" version = "3.19.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiofiles" }, { name = "aiofiles" },
@@ -1034,7 +1034,7 @@ dev = [
{ name = "pydantic-to-typescript2", specifier = "==1.0.6" }, { name = "pydantic-to-typescript2", specifier = "==1.0.6" },
{ name = "pylint", specifier = "==4.0.5" }, { name = "pylint", specifier = "==4.0.5" },
{ name = "pytest", specifier = "==9.0.3" }, { name = "pytest", specifier = "==9.0.3" },
{ name = "pytest-asyncio", specifier = "==1.4.0" }, { name = "pytest-asyncio", specifier = "==1.3.0" },
{ name = "rich", specifier = "==15.0.0" }, { name = "rich", specifier = "==15.0.0" },
{ name = "ruff", specifier = "==0.15.14" }, { name = "ruff", specifier = "==0.15.14" },
{ name = "types-python-dateutil", specifier = "==2.9.0.20260518" }, { name = "types-python-dateutil", specifier = "==2.9.0.20260518" },
@@ -1601,15 +1601,15 @@ wheels = [
[[package]] [[package]]
name = "pytest-asyncio" name = "pytest-asyncio"
version = "1.4.0" version = "1.3.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pytest" }, { name = "pytest" },
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" },
] ]
[[package]] [[package]]