From bb65ecd43cff4a83a0dbf60d6af20a93cd5ae97c Mon Sep 17 00:00:00 2001 From: David Dyer Date: Sun, 25 Oct 2026 16:49:43 -0400 Subject: [PATCH] Refactor configuration handling: implement dynamic loading of config and cache paths for improved security and flexibility in Docker environments --- docker-compose.yaml | 21 +++++++++++++++++---- inc/google-reviews.php | 7 +++++-- inc/load-config.php | 11 +++++++++++ index.php | 2 +- menu.php | 2 +- scripts/build-dist.js | 12 ++++++++---- scripts/dev-router.php | 10 ++++++++++ 7 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 inc/load-config.php diff --git a/docker-compose.yaml b/docker-compose.yaml index a50ded5..6be7add 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -5,10 +5,13 @@ # docker-compose.yaml (this file) # .env (optional, see PROXY_NETWORK below) # www/ (contents of `npm run dist`) -# data/ (fitz.sqlite — never inside www/) +# config/config.php (live secrets — never inside www/, never in dist/) +# data/ (fitz.sqlite + cache/ — never inside www/) # -# First run: create data/ and `chown 33:33 data` (www-data in the image), -# then create the first admin with bin/create-user.php (see its header). +# First run: create data/ and `chown 33:33 data` (www-data in the image). +# Copy config.example.php to config/config.php, fill it in, and make it +# readable by www-data (`chown root:33` + `chmod 640`). Then create the +# first admin with bin/create-user.php (see its header). # # The CasaOS dev host keeps its own copy of this file in the CasaOS app # settings, with CasaOS paths and its x-casaos block. @@ -43,13 +46,23 @@ services: - type: bind source: ./www target: /var/www/html - # Database lives outside the web root so Apache can't serve it. + # Database and cache live outside the web root so Apache can't serve + # them and deploys to www/ never touch them. - type: bind source: ./data target: /var/www/data + # Config is mounted as a directory, not a single file: a single-file + # bind mount pins the inode, so an editor that saves by replacing the + # file leaves the container reading the old copy until a restart. + - type: bind + source: ./config + target: /var/www/config + read_only: true environment: - TZ=America/Indiana/Indianapolis - FITZ_DB_PATH=/var/www/data/fitz.sqlite + - FITZ_CACHE_DIR=/var/www/data/cache + - FITZ_CONFIG_PATH=/var/www/config/config.php # Cap container logs so PHP's error log can't slowly fill the disk. logging: driver: json-file diff --git a/inc/google-reviews.php b/inc/google-reviews.php index 83fafe4..a3ff8ad 100644 --- a/inc/google-reviews.php +++ b/inc/google-reviews.php @@ -20,7 +20,11 @@ function fritz_google_reviews(): array { return $fallback; } - $cacheFile = __DIR__ . '/../cache/google-reviews.json'; + // In Docker, FITZ_CACHE_DIR points into the writable data/ mount, outside + // the web root, so deploys don't wipe it and www/ can stay read-only to + // www-data. Local dev falls back to cache/ in the project root. + $cacheDir = getenv('FITZ_CACHE_DIR') ?: __DIR__ . '/../cache'; + $cacheFile = $cacheDir . '/google-reviews.json'; if (is_file($cacheFile)) { $cached = json_decode((string) file_get_contents($cacheFile), true); @@ -33,7 +37,6 @@ function fritz_google_reviews(): array { $fresh = fritz_fetch_google_reviews($fallback); $fresh['fetched_at'] = time(); - $cacheDir = dirname($cacheFile); if (!is_dir($cacheDir)) { @mkdir($cacheDir, 0775, true); } diff --git a/inc/load-config.php b/inc/load-config.php new file mode 100644 index 0000000..ed268f1 --- /dev/null +++ b/inc/load-config.php @@ -0,0 +1,11 @@ +