fix(refresh): refuse to promote an empty capture over a good snapshot
ssh exiting 0 is not proof the capture is usable — the inspect script can emit nothing and both refresh scripts would mv that over a good system-details.txt and report 'ok (0 bytes)'. Every reader tests the snapshot with -s, so the writer was producing an artifact its own readers call invalid: a guard whose test disagrees with its writer's contract has quietly stopped guarding. Prompted by brokkr-smithy-dev hitting the same shape from the other side (a -s test against a sentinel written with touch, a precondition that could never pass). - empty capture -> refused, previous snapshot kept, host counted as failed (exit 1) - capture under 1/4 of the previous -> promoted but flagged, since a host can legitimately shed services and the script should not guess - header + CLAUDE.md contract lines corrected to say what is actually guaranteed - verified red (empty inspect -> FAIL, snapshot intact, rc=1) then green (real host -> ok 6727 bytes)
This commit is contained in:
@@ -13,7 +13,9 @@
|
||||
# For each host:
|
||||
# 1. Run scripts/server_inspect.sh on the remote via `ssh <target> 'bash -s'`.
|
||||
# 2. Write output atomically to `servers/<host>/system-details.txt`.
|
||||
# A failed SSH/run never clobbers the previous good snapshot.
|
||||
# A failed SSH/run never clobbers the previous good snapshot — and neither
|
||||
# does a SUCCEEDED run that produced nothing (ssh exit 0 is not proof of a
|
||||
# usable capture; an empty one is refused and counted as a failure).
|
||||
#
|
||||
# Exit status is non-zero if any host failed.
|
||||
#
|
||||
@@ -241,10 +243,35 @@ for host in "${HOSTS[@]}"; do
|
||||
mkdir -p "$SERVERS_DIR/$host"
|
||||
|
||||
if ssh -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$target" 'bash -s' < "$INSPECT" > "$tmp" 2> "$tmp.err"; then
|
||||
# ⚠ ssh exiting 0 is NOT proof the capture is usable. The inspect script can
|
||||
# emit nothing (a shell that dies before its first write, output swallowed by
|
||||
# a remote wrapper) and this would then promote an EMPTY file over a good
|
||||
# snapshot and report "ok (0 bytes)" — the readers below all test the
|
||||
# snapshot with `-s`, so the writer must not produce something they consider
|
||||
# invalid. A guard whose test disagrees with its writer's contract has
|
||||
# quietly stopped guarding. Refuse the promotion, keep the old snapshot,
|
||||
# and count it as a failure so the exit code carries it.
|
||||
new_bytes=$(wc -c < "$tmp" 2>/dev/null || echo 0)
|
||||
if [ "$new_bytes" -eq 0 ]; then
|
||||
rm -f "$tmp" "$tmp.err"
|
||||
printf 'FAIL (empty capture — previous snapshot kept)\n'
|
||||
failed+=("$host")
|
||||
[ "${#warnings[@]}" -gt 0 ] && print_warnings " " "${warnings[@]}"
|
||||
continue
|
||||
fi
|
||||
# A capture that collapses to a fraction of the previous one is suspicious
|
||||
# but not provably wrong (a host really can shed services), so this WARNS and
|
||||
# still promotes — the operator sees it rather than the script guessing.
|
||||
shrink=""
|
||||
if [ -s "$out" ]; then
|
||||
old_bytes=$(wc -c < "$out")
|
||||
if [ "$old_bytes" -gt 0 ] && [ $((new_bytes * 4)) -lt "$old_bytes" ]; then
|
||||
shrink=" ⚠ shrank from ${old_bytes}B — check before trusting"
|
||||
fi
|
||||
fi
|
||||
mv "$tmp" "$out"
|
||||
rm -f "$tmp.err"
|
||||
bytes=$(wc -c < "$out")
|
||||
printf 'ok (%s bytes)\n' "$bytes"
|
||||
printf 'ok (%s bytes)%s\n' "$new_bytes" "$shrink"
|
||||
else
|
||||
rc=$?
|
||||
rm -f "$tmp"
|
||||
|
||||
Reference in New Issue
Block a user