- _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
68 lines
2.8 KiB
Bash
Executable File
68 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Functional test of json_escape + restore guard (DC-122 verification)
|
|
set -euo pipefail
|
|
# Updater script path: $1 overrides; default = adjacent to this test file
|
|
# (numbered worktree prefixes included), falling back to installed location.
|
|
SCRIPT="${1:-}"
|
|
if [[ -z "$SCRIPT" ]]; then
|
|
local_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
for cand in "$local_dir/dashcaddy-update.sh" \
|
|
"$local_dir"/*dashcaddy-update.sh \
|
|
/opt/dashcaddy/scripts/dashcaddy-update.sh; do
|
|
[[ -f "$cand" ]] && SCRIPT="$cand" && break
|
|
done
|
|
fi
|
|
[[ -f "$SCRIPT" ]] || { echo "updater script not found"; exit 1; }
|
|
# Exactly ONE validated, trap-covered workspace for ALL temp artifacts.
|
|
WORK=$(mktemp -d) || { echo "mktemp failed"; exit 1; }
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
source <(sed -n '/^json_escape()/,/^}/p' "$SCRIPT")
|
|
|
|
# Test 1: quotes + backslash + newline + tab round-trip through python json
|
|
r=$(json_escape 'a"b\c
|
|
d e')
|
|
python3 - "$r" <<'PY'
|
|
import json, sys
|
|
v = json.loads('"' + sys.argv[1] + '"')
|
|
assert v == 'a"b\\c\nd\te', f"round-trip mismatch: {v!r}"
|
|
print("TEST1 OK: quotes/backslash/newline/tab round-trip valid JSON")
|
|
PY
|
|
|
|
# Test 2: control chars (backspace, form feed, x01) become \uXXXX short forms
|
|
r2=$(json_escape "$(printf 'x\by\fz\001w')")
|
|
python3 - "$r2" <<'PY'
|
|
import json, sys
|
|
v = json.loads('"' + sys.argv[1] + '"')
|
|
assert v == "x\by\fz\x01w", f"control round-trip mismatch: {v!r}"
|
|
print("TEST2 OK: control bytes escaped and parse back")
|
|
PY
|
|
|
|
# Test 3: restore_frontend_dir must REFUSE an invalid recorded target —
|
|
# invoke it for real and assert (a) nonzero return, (b) zero mutations.
|
|
sed -n '/^validate_frontend_target()/,/^}/p' "$SCRIPT" > "$WORK/rfd-parts.sh"
|
|
sed -n '/^restore_frontend_dir()/,/^}/p' "$SCRIPT" >> "$WORK/rfd-parts.sh"
|
|
log() { echo "[t] $*"; }
|
|
source "$WORK/rfd-parts.sh"
|
|
|
|
WORK2="$WORK/fixtures"
|
|
mkdir -p "$WORK2/victim/dist" "$WORK2/backup/frontend"
|
|
echo keep > "$WORK2/victim/dist/keep.js"
|
|
cat > "$WORK2/backup/frontend.meta" <<EOF
|
|
{"target":"relative/not-absolute","indexExisted":true,"swExisted":true}
|
|
EOF
|
|
( cd "$WORK2/backup/frontend" && find . -type f -printf '%P\n' | sort ) > "$WORK2/backup/frontend.manifest"
|
|
|
|
# Full-tree fingerprint BEFORE any restore attempt: prove ZERO mutations
|
|
# anywhere in the victim tree across the refused restore.
|
|
fp_before=$(find "$WORK2/victim" -type f -exec sha256sum {} + | sort)
|
|
rc=0
|
|
restore_frontend_dir "$WORK2/backup" 2>/dev/null || rc=$?
|
|
fp_after=$(find "$WORK2/victim" -type f -exec sha256sum {} + | sort)
|
|
if [[ $rc -ne 0 ]]; then echo "TEST3a OK: restore returned nonzero ($rc) for invalid target"; else echo "TEST3 FAIL: restore returned 0"; exit 1; fi
|
|
if [[ "$fp_before" == "$fp_after" ]]; then
|
|
echo "TEST3b OK: victim untouched (fingerprint identical across refused restore)"
|
|
else
|
|
echo "TEST3 FAIL: victim modified"; exit 1
|
|
fi
|
|
echo "ALL JSON/GUARD TESTS DONE"
|