[object Object]

← back to Homesonspec

prune: fail-open per-builder (|| true vs pipefail abort) + SNAP_DIR anchor guard + 30d manifest retention (verifier findings) — TK-10236

53ff55422c2e78e19b9f955509a503295670d47e · 2026-08-05 08:15:43 -0700 · Steve Abrams

Files touched

Diff

commit 53ff55422c2e78e19b9f955509a503295670d47e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Aug 5 08:15:43 2026 -0700

    prune: fail-open per-builder (|| true vs pipefail abort) + SNAP_DIR anchor guard + 30d manifest retention (verifier findings) — TK-10236
---
 ops/prune-snapshot-cache.sh | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/ops/prune-snapshot-cache.sh b/ops/prune-snapshot-cache.sh
index f05a8cf9..e932e1d8 100755
--- a/ops/prune-snapshot-cache.sh
+++ b/ops/prune-snapshot-cache.sh
@@ -24,6 +24,12 @@ RETAIN_MIN=$((RETAIN_DAYS*1440))
 gb(){ awk -v b="${1:-0}" 'BEGIN{printf "%.2f", b/1073741824}'; }
 
 [ -d "$SNAP" ] || { echo "ERROR: snapshot dir not found: $SNAP"; exit 1; }
+# Destructive-script anchor: refuse to run outside the expected snapshots tree so a mis-set
+# SNAP_DIR (e.g. "/") can never turn the glob + find-delete loose on the wider filesystem.
+case "$SNAP" in
+  */homesonspec/var/snapshots|*/homesonspec/var/snapshots/) : ;;
+  *) echo "ERROR: SNAP_DIR '$SNAP' is outside the homesonspec snapshots tree — refusing to run"; exit 1 ;;
+esac
 MANIFEST="$SNAP/../prune-manifest-$(date +%Y%m%d-%H%M%S).log"
 now_mode=$([ $APPLY -eq 1 ] && echo PRUNE || echo DRY-RUN)
 echo "== homesonspec snapshot-cache retention ($now_mode) =="
@@ -45,11 +51,16 @@ for d in "$SNAP"/*/; do
   total_files=$((total_files+cnt)); total_bytes=$((total_bytes+bytes))
   if [ $APPLY -eq 1 ]; then
     find "$d" -type f -mmin +"$RETAIN_MIN" -printf '%p\n' 2>/dev/null >> "$MANIFEST"
-    find "$d" -type f -mmin +"$RETAIN_MIN" -delete 2>/dev/null
+    # || true: a live crawler deleting/replacing a file between enumerate and delete makes
+    # find exit 1; under `set -uo pipefail` that would silently abort the loop, leaving the
+    # remaining builders unpruned while cron reports success. Fail-open per builder instead.
+    find "$d" -type f -mmin +"$RETAIN_MIN" -delete 2>/dev/null || true
   fi
 done
 echo ""
 printf "%s TOTAL: %d files, %sG\n" "$now_mode" "$total_files" "$(gb "$total_bytes")"
 [ -n "$skipped" ] && echo "skipped (active crawl, <${LIVE_MIN}m writes):$skipped"
 [ $APPLY -eq 1 ] && echo "deleted-path manifest: $MANIFEST"
+# retain manifests 30 days so /var doesn't accumulate them (apply-mode only; dry-run writes nothing)
+[ $APPLY -eq 1 ] && find "$SNAP/.." -maxdepth 1 -name 'prune-manifest-*.log' -mtime +30 -delete 2>/dev/null || true
 [ $APPLY -eq 0 ] && echo "(dry-run — nothing deleted. Re-run with --apply to prune.)"

← 5c1b5c47 ops: minute-precision retention (find -mtime +N truncates to  ·  back to Homesonspec  ·  workers: exp_backoff_restart_delay to cap PG-outage restart 033d4dbb →