fix(wake): #942 harden WAKE_SNAPSHOT_TS_FUTURE_SLACK — validate shape AND force base-10
The slack knob was interpolated raw into $((...)) under set -u: a malformed value was FATAL to the poll, falsifying the poll-never-fails invariant, and a negative value inverted the guard to deny-all. Shape validation alone was insufficient — bash reads a leading zero as octal, so 08/09 passed the regex yet were fatal and 0300 silently meant 192. Now validated ^[0-9]{1,9}$ with a loud fallback to 300, then forced to base-10 via 10# so the knob means what the operator wrote.
Authored-by: pepper
Reviewed-by: mos-dt (independent, found both the original defect and the radix residual)
Merged-by: Mos
Co-authored-by: mos-dt-0 <[email protected]>
This commit was merged in pull request #942.
This commit is contained in:
@@ -588,6 +588,92 @@ EOF
|
||||
[ "$(det_seq)" = "3" ] || fail_msg "D12: all three real deltas must still have enqueued, got seq $(det_seq)"
|
||||
) && ok
|
||||
|
||||
echo "== D13: WAKE_SNAPSHOT_TS_FUTURE_SLACK is operator input — a malformed knob must fall back to 300 loudly, never kill the poll or invert the guard =="
|
||||
(
|
||||
WAKE_STATE_HOME="$(fresh_state d13)"
|
||||
export WAKE_STATE_HOME
|
||||
unset WAKE_AGENT
|
||||
stub="$TMP_ROOT/d13stub"
|
||||
mkdir -p "$stub"
|
||||
cat >"$stub/adapter.sh" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
kind="\$1"; id="\$2"
|
||||
base="$stub/\${kind}_\${id}"
|
||||
[ -f "\$base" ] && cat "\$base"
|
||||
[ -f "\$base.meta" ] && { cat "\$base.meta" >&3; } 2>/dev/null
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$stub/adapter.sh"
|
||||
export WAKE_DETECTOR_SOURCE_CMD="$stub/adapter.sh"
|
||||
wl="$TMP_ROOT/d13.json"
|
||||
write_watchlist "$wl" 1
|
||||
export WAKE_WATCH_LIST="$wl"
|
||||
printf 'SHA-AAA\n' >"$stub/repo_r1"
|
||||
printf '## LANE-X\ndecision: hold\n' >"$stub/board_file_b1"
|
||||
"$DET" poll-once >/dev/null 2>&1 || fail_msg "D13: baseline pass failed"
|
||||
goodsha="0123abc4567890def0123abc4567890def012345"
|
||||
# Every sub-case ships a VALID sha + CURRENT ts: the metadata itself is good,
|
||||
# only the operator's knob is broken, so the correct outcome is fallback-and-keep.
|
||||
# (a) '300s' — the natural duration-suffix mistake. Under set -u this used to be
|
||||
# FATAL inside \$((...)): rc=1, wake never fires. Now: loud fallback, ts kept.
|
||||
printf '{"snapshot_sha":"%s","snapshot_ts":%s}\n' "$goodsha" "$(date +%s)" >"$stub/repo_r1.meta"
|
||||
printf 'SHA-BBB\n' >"$stub/repo_r1"
|
||||
err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='300s' "$DET" poll-once 2>&1 >/dev/null)"; rc=$?
|
||||
[ "$rc" -eq 0 ] || fail_msg "D13: SLACK='300s' must NEVER fail the poll (rc=$rc)"
|
||||
echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: malformed slack must be LOUD on stderr [$err]"
|
||||
entry="$("$STORE" drain | tail -1)"
|
||||
echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \
|
||||
|| fail_msg "D13: valid metadata must SURVIVE a malformed knob (fallback, not drop) [$entry]"
|
||||
# (b) 'abc' — bare word: under set -u, arithmetic dies on 'abc: unbound variable'.
|
||||
printf '{"snapshot_sha":"%s","snapshot_ts":%s}\n' "$goodsha" "$(date +%s)" >"$stub/repo_r1.meta"
|
||||
printf 'SHA-CCC\n' >"$stub/repo_r1"
|
||||
err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='abc' "$DET" poll-once 2>&1 >/dev/null)"; rc=$?
|
||||
[ "$rc" -eq 0 ] || fail_msg "D13: SLACK='abc' must NEVER fail the poll (rc=$rc)"
|
||||
echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: non-numeric slack must be LOUD on stderr [$err]"
|
||||
entry="$("$STORE" drain | tail -1)"
|
||||
echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \
|
||||
|| fail_msg "D13: valid metadata must SURVIVE a non-numeric knob [$entry]"
|
||||
# (c) negative slack — arithmetic would ACCEPT it and silently invert the guard
|
||||
# into deny-all (a CURRENT ts reads as 'future'). Must fall back and keep the ts.
|
||||
printf '{"snapshot_sha":"%s","snapshot_ts":%s}\n' "$goodsha" "$(date +%s)" >"$stub/repo_r1.meta"
|
||||
printf 'SHA-DDD\n' >"$stub/repo_r1"
|
||||
err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='-99999999' "$DET" poll-once 2>&1 >/dev/null)"; rc=$?
|
||||
[ "$rc" -eq 0 ] || fail_msg "D13: negative SLACK must NEVER fail the poll (rc=$rc)"
|
||||
echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: negative slack must be LOUD on stderr [$err]"
|
||||
entry="$("$STORE" drain | tail -1)"
|
||||
echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \
|
||||
|| fail_msg "D13: negative slack must NOT invert the guard into deny-all [$entry]"
|
||||
# (d2-pre) ZERO-PADDED knobs — shape-valid, radix-hostile. '08' passes the
|
||||
# regex but is fatal octal in \$((...)) without the 10# normalization; '0300'
|
||||
# silently means 192 (octal), so a ts +250s ahead would be WRONGLY dropped.
|
||||
# With 10#: '08' means 8 and survives; '0300' means 300 and the +250s ts is KEPT.
|
||||
printf '{"snapshot_sha":"%s","snapshot_ts":%s}\n' "$goodsha" "$(date +%s)" >"$stub/repo_r1.meta"
|
||||
printf 'SHA-DD2\n' >"$stub/repo_r1"
|
||||
err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='08' "$DET" poll-once 2>&1 >/dev/null)"; rc=$?
|
||||
[ "$rc" -eq 0 ] || fail_msg "D13: SLACK='08' (octal-fatal without 10#) must NEVER fail the poll (rc=$rc) [$err]"
|
||||
entry="$("$STORE" drain | tail -1)"
|
||||
echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \
|
||||
|| fail_msg "D13: SLACK='08' with a current ts must keep the metadata [$entry]"
|
||||
printf '{"snapshot_sha":"%s","snapshot_ts":%s}\n' "$goodsha" "$(( $(date +%s) + 250 ))" >"$stub/repo_r1.meta"
|
||||
printf 'SHA-DD3\n' >"$stub/repo_r1"
|
||||
err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='0300' "$DET" poll-once 2>&1 >/dev/null)"; rc=$?
|
||||
[ "$rc" -eq 0 ] || fail_msg "D13: SLACK='0300' must not fail the poll (rc=$rc)"
|
||||
entry="$("$STORE" drain | tail -1)"
|
||||
echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \
|
||||
|| fail_msg "D13: SLACK='0300' must mean 300 (decimal), so a +250s ts is KEPT — octal 192 would have dropped it [$entry]"
|
||||
# (d) a VALID knob is still honored: slack=0 with a ts 60s ahead -> future-skew drop.
|
||||
printf '{"snapshot_sha":"%s","snapshot_ts":%s}\n' "$goodsha" "$(( $(date +%s) + 60 ))" >"$stub/repo_r1.meta"
|
||||
printf 'SHA-EEE\n' >"$stub/repo_r1"
|
||||
err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='0' "$DET" poll-once 2>&1 >/dev/null)"; rc=$?
|
||||
[ "$rc" -eq 0 ] || fail_msg "D13: valid SLACK=0 must not fail the poll (rc=$rc)"
|
||||
echo "$err" | grep -qi 'future-skew' || fail_msg "D13: a valid tightened slack must still reject a future ts [$err]"
|
||||
entry="$("$STORE" drain | tail -1)"
|
||||
echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts") | not' >/dev/null 2>&1 \
|
||||
|| fail_msg "D13: valid SLACK=0 must drop the future ts but keep the sha [$entry]"
|
||||
[ "$(det_seq)" = "6" ] || fail_msg "D13: all six real deltas must still have enqueued, got seq $(det_seq)"
|
||||
) && ok
|
||||
|
||||
echo
|
||||
if [ -s "$FAILFILE" ]; then
|
||||
echo "wake detector harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2
|
||||
|
||||
Reference in New Issue
Block a user