DC-050 harden dataDir + add image-layer migration
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled

Three-part fix for the silent data-loss failure mode that survives DC-039:
If SERVICES_FILE env was unset, platformPaths.dataDir resolved to /etc/dashcaddy
(image-layer path), and audit/license/error logs would silently land there and
vanish on every container recreate.

1. platform-paths.assertSafe({mode:'production'}) — throws FATAL on forbidden
   zones (/app/src,routes,scripts,utils,managers,security + /etc/* + /usr + /var).
   Bypassed with SKIP_DATA_DIR_GUARD=1.
2. server.js calls assertSafe() before any runtime work.
3. start.sh one-time migration: scans 6 known image-layer zombie paths,
   copies non-empty content to bind mount with 'migrated-' prefix,
   gated by sentinel file. Survives set -e per-file failures.

19/19 platform-paths tests + 5/5 shell migration tests.
Suite: 1066/1067 (1 pre-existing public-routes-drift failure from in-flight
auth refactor, untouched by this commit).

Verified live on DNS2: live audit log at /app/data/audit-log.json (315KB,
active) is unaffected; vestigial 2-byte /app/src/security/audit-log.json +
140KB /app/src/utils/error.log (pre-DC-039 era) will be recovered on next
container recreate.
This commit is contained in:
Hermes Agent
2026-07-20 00:53:05 -07:00
parent 09efce2891
commit 894e091335
7 changed files with 465 additions and 0 deletions
+7
View File
@@ -33,6 +33,13 @@ process.on('uncaughtException', (error) => {
const SERVICES_FILE = process.env.SERVICES_FILE || platformPaths.servicesFile;
const CONFIG_FILE = process.env.CONFIG_FILE || platformPaths.servicesFile.replace('services.json', 'config.json');
// dataDir safety guard — DC-046 follow-up to DC-039. Refuse to boot in
// production if dataDir resolved into the Docker image layer (audit-log,
// license keys, error logs etc. would silently land there and vanish on
// the next container recreate). Throws → no crash-loop, just a clear
// fatal error message before any runtime state can be written.
platformPaths.assertSafe({ mode: process.env.NODE_ENV === 'production' ? 'production' : 'development' });
// Validate startup configuration
const { validateStartupConfig } = require('./src/utilities/startup-validator');
await validateStartupConfig({