From 20d280f1dd9904ef284c6d4b5fc4d0332c71de71 Mon Sep 17 00:00:00 2001 From: Krystie Date: Sun, 5 Jul 2026 21:49:39 -0700 Subject: [PATCH] DC-033: fix getLocalVersion __dirname resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SelfUpdater's getLocalVersion() used __dirname to find package.json and VERSION, but server.js loads the module via './src/docker/self-updater' so __dirname resolves to /app/src/docker inside the container — which has no package.json. Result: /api/v1/system/version silently returned {version: '0.0.0', commit: null} and checkForUpdate() always thought we were outdated. Walk a candidate list of paths (api root first, __dirname second) so the function works regardless of where the module is required from. Log to stderr on total failure instead of swallowing silently. Verified on DNS2: /api/v1/system/version now returns {"name":"DashCaddy","version":"1.14.8","commit":"fef7e07"} (v1.14.8 with the security fixes DC-020..032). --- dashcaddy-api/src/docker/self-updater.js | 27 +++++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/dashcaddy-api/src/docker/self-updater.js b/dashcaddy-api/src/docker/self-updater.js index b328ec1..0da2101 100644 --- a/dashcaddy-api/src/docker/self-updater.js +++ b/dashcaddy-api/src/docker/self-updater.js @@ -105,16 +105,27 @@ class SelfUpdater extends EventEmitter { // ── Version / Identity Info ── getLocalVersion() { - try { - const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')); - let commit = null; + // Resolve package.json/VERSION relative to the api root, not __dirname. + // This module is loaded via `./src/docker/self-updater` so __dirname is + // `/app/src/docker` inside the container, which has no package.json. + // Fall back to __dirname (matches the legacy root-copy contract) so + // existing callers and future restructurings keep working. + const candidates = [ + path.join(__dirname, '..', '..', 'package.json'), + path.join(__dirname, 'package.json'), + ]; + for (const pkgPath of candidates) { try { - commit = fs.readFileSync(path.join(__dirname, 'VERSION'), 'utf8').trim(); - } catch { /* ignore */ } - return { version: pkg.version, commit }; - } catch (e) { - return { version: '0.0.0', commit: null }; + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + let commit = null; + try { + commit = fs.readFileSync(pkgPath.replace(/package\.json$/, 'VERSION'), 'utf8').trim(); + } catch { /* ignore */ } + return { version: pkg.version, commit }; + } catch { /* try next candidate */ } } + console.error('[SelfUpdater] getLocalVersion failed: no candidate package.json found'); + return { version: '0.0.0', commit: null }; } getInstanceInfo() {