[grade=A urn:ump:seyasvbntxsjibq5jiaqmfowc6xgchwe4jvcc54jd6355ujgm75q] DC-122: self-updater hardening + auto-update on + docker disk discipline (v1.16.0)
CI / Test & Lint (push) Canceled after 0s
CI / Security audit (push) Canceled after 0s

- _isNewer: same-version releases are never 'newer' (commit labels are
  opaque stamps) — kills the same-version auto-apply regression loop
- _autoCheckAndApply: identical version@sha256 never re-applied
- dashcaddy-update.sh: truthful rollback verdicts (failed rebuild/health
  = exit 1 + failure result), exact frontend snapshot/restore (incl.
  update-introduced owned subtrees), contents-copy cp fallbacks with
  manifest reconciliation, JSON-encoded results/meta/stamp, prune on
  every exit path
- self-updater: frontend-only Linux releases fail loudly (no more silent
  no-op success stuck in 'applying')
- start.sh: DASHCADDY_UPDATE_ENABLED=true (Sami 2026-09-13), json-file
  log caps 10M x3, source->webroot sync via update-stamp contract
- tests: _isNewer regression suite, functional cycle + json/escape suites
  (scripts/test-frontend-cycle.sh, scripts/test-json-escape.sh)

15 judge rounds: C,C,D,D,C,C,D,C,C,C,D,C,A
This commit is contained in:
DashCaddy Polish Loop
2026-09-13 05:32:14 -07:00
parent 939fdbb68b
commit 70e252c8a5
7 changed files with 631 additions and 46 deletions
+25 -13
View File
@@ -149,26 +149,38 @@ fi
echo "[start.sh] Creating container with full config..."
# Sync the freshly-built dashboard bundle into the static directory Caddy
# serves. The Docker image bakes dist/ from the source tree at build time,
# but DNS2 also serves /var/www/dashcaddy-status/dist/ (the original
# Windows installer mirror path). If we don't sync after every build, the
# served bundle keeps the OLD hash while the API responds with new code,
# which shows up in the dashboard as "version unavailable" + "no data"
# widgets because the new API surface doesn't match the old widget code.
# This step is idempotent and ~50ms — always safe to run.
echo "[start.sh] Syncing dashboard bundle into static dir..."
# serves — decided by VERSION METADATA, not file mtimes (mtimes are not
# reliable: scp/tar/cp can preserve or shuffle them). DC-122 contract:
# - The self-updater writes a STAMP (update-stamp.json) into the live web
# root when it deploys a frontend; while that stamp is newer than the
# source tree's VERSION file, start.sh must NOT touch the live bundle.
# - Normal builds: publishing bumps the source VERSION (mtime = build time)
# and clears any stale stamp, so source wins and the sync happens.
echo "[start.sh] Syncing dashboard bundle into static dir (metadata-driven)..."
mkdir -p /var/www/dashcaddy-status/dist
if [ -d /opt/dashcaddy/status/dist ]; then
cp /opt/dashcaddy/status/dist/*.js /var/www/dashcaddy-status/dist/ 2>/dev/null || true
cp /opt/dashcaddy/status/sw.js /var/www/dashcaddy-status/ 2>/dev/null || true
cp /opt/dashcaddy/status/index.html /var/www/dashcaddy-status/ 2>/dev/null || true
echo "[start.sh] Bundle synced ($(ls /opt/dashcaddy/status/dist/*.js 2>/dev/null | wc -l) bundle files + sw.js + index.html)."
NEEDS_SYNC=1
STAMP=/var/www/dashcaddy-status/update-stamp.json
SRC_VERSION=/opt/dashcaddy/dashcaddy-api/VERSION
if [ -f "$STAMP" ] && [ -f "$SRC_VERSION" ] && [ "$STAMP" -nt "$SRC_VERSION" ]; then
# A self-updater deployment is newer than the last source build: hands off.
echo "[start.sh] Deployed frontend stamp newer than source VERSION — skipping sync to preserve deployed frontend."
NEEDS_SYNC=0
fi
if [ "$NEEDS_SYNC" = "1" ]; then
cp /opt/dashcaddy/status/dist/*.js /var/www/dashcaddy-status/dist/ 2>/dev/null || true
cp /opt/dashcaddy/status/sw.js /var/www/dashcaddy-status/ 2>/dev/null || true
cp /opt/dashcaddy/status/index.html /var/www/dashcaddy-status/ 2>/dev/null || true
rm -f "$STAMP"
echo "[start.sh] Bundle synced ($(ls /opt/dashcaddy/status/dist/*.js 2>/dev/null | wc -l) bundle files + sw.js + index.html)."
fi
else
echo "[start.sh] WARN: /opt/dashcaddy/status/dist missing — skipping sync (frontend will be stale)."
fi
docker run -d --restart unless-stopped --name ${CONTAINER_NAME} \
--memory=1g --memory-swap=2g --cpus=2 \
--log-driver json-file --log-opt max-size=10m --log-opt max-file=3 \
--add-host=get.dashcaddy.net:194.233.88.206 \
--add-host=get2.dashcaddy.net:194.233.88.206 \
--dns ${DNS_PRIMARY} \
@@ -204,6 +216,6 @@ docker run -d --restart unless-stopped --name ${CONTAINER_NAME} \
-e DASHCADDY_SELF_IPS="${SELF_IPS}" \
-e ASSETS_DIR=/app/assets \
-e DASHCADDY_API_SOURCE_DIR=/opt/dashcaddy/dashcaddy-api \
-e DASHCADDY_UPDATE_ENABLED=false \
-e DASHCADDY_UPDATE_ENABLED=true \
-e CA_CERT_PATH=/etc/ssl/sami-ca/root.crt \
${IMAGE}