feat(wake): W7 (vi) fold in W6 monitor-integration hardening in beacon.sh
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
Separate, clearly-labeled commit for observation set (vi) from the #910 review. The HMAC-verify half is a non-trivial blast radius (emit must sign, record must verify-and-bind), so it is isolated here rather than expanding the installer diff. Both changes are additive and backward-compatible (the legacy unsigned path and emit_ts fallback are preserved when no key is configured). (vi-a) Monitor-side ingested_ts: `record` stamps the monitor's own receive-time, and `check` computes staleness from ingested_ts (falling back to emit_ts only for a legacy record). A host shipping a far-future emit_ts to defer its own staleness can no longer fool the off-host dead-man clock. (vi-b) Beacon HMAC-verify at record: when a key name is configured (WAKE_BEACON_HMAC_KEY_NAME / WAKE_HMAC_KEY_NAME), `emit` signs the beacon core via the existing sign.sh sign-digest path and `record` verifies via sign.sh verify AND binds the envelope to this beacon (content_hash == sha256(core), seq/emit_ts match). A spoofed or unsigned beacon is REJECTED fail-loud and never advances the received clock. Key is by-name only — beacon.sh inlines no key material. test-wake-beacon.sh extended with B11 (ingested_ts staleness) and B12 (HMAC-verify + spoof/unsigned rejection); test-wake-install.sh gains I7/I8 for the same invariants. Both harnesses shown red-first under targeted mutation, then green. Part of #892 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
This commit is contained in:
@@ -271,6 +271,66 @@ echo "== B10: fresh beacon within SLO -> ALIVE (exit 0, no alarm) =="
|
||||
[ ! -s "$ALARM_OUT" ] || fail_msg "B10: a fresh beacon must NOT fire an alarm"
|
||||
) && ok
|
||||
|
||||
# ── W7 monitor-integration hardening (folded-in W6 observations, #910 review) ──
|
||||
|
||||
echo "== B11: staleness from monitor ingested_ts -> a far-future emit_ts STILL goes stale =="
|
||||
(
|
||||
H="$(fresh_home b11)"
|
||||
export ALARM_OUT="$H/alarm.json"
|
||||
export WAKE_BEACON_RECEIVED="$H/received.json"
|
||||
export WAKE_ALARM_SINK_CMD="$CAPTURE_ALARM"
|
||||
now="$(date +%s)"
|
||||
# A host ships a FAR-FUTURE emit_ts (now + 100000s) to try to defer staleness.
|
||||
# record stamps the monitor's own ingested_ts; check must use THAT, not emit_ts.
|
||||
jq -cn --argjson ts "$((now + 100000))" \
|
||||
'{kind:"wake-beacon", beacon_seq:9, emit_ts:$ts, host_id:"h", independence:"off-host", degraded:false}' \
|
||||
| "$BEACON" record
|
||||
# Simulate the monitor having received it 100s ago (ingested_ts backdated) while
|
||||
# the host's emit_ts stays far in the future. Under emit_ts-based staleness this
|
||||
# would read as ALIVE (age hugely negative); under receive-time it is STALE.
|
||||
jq -c --argjson ing "$((now - 100))" '.ingested_ts = $ing' "$WAKE_BEACON_RECEIVED" >"$H/tmp" && mv "$H/tmp" "$WAKE_BEACON_RECEIVED"
|
||||
out="$("$BEACON" check --slo-seconds 5 2>&1)"; rc=$?
|
||||
[ "$rc" -eq 1 ] || fail_msg "B11: a far-future emit_ts must NOT defer staleness — receive-time governs (expected absence exit 1); got $rc [$out]"
|
||||
echo "$out" | grep -qi 'ALARM FIRED' || fail_msg "B11: the receive-time-stale beacon must fire the absence alarm [$out]"
|
||||
jq -e '.age_seconds >= 100' "$ALARM_OUT" >/dev/null 2>&1 || fail_msg "B11: staleness age must be measured from ingested_ts (>=100s), not emit_ts [$(cat "$ALARM_OUT" 2>/dev/null)]"
|
||||
) && ok
|
||||
|
||||
echo "== B12: HMAC-verify at record -> a spoofed (bad-sig) beacon is REJECTED =="
|
||||
(
|
||||
H="$(fresh_home b12)"
|
||||
export WAKE_STATE_HOME="$H"
|
||||
export MOSAIC_CREDENTIALS_FILE="$H/credentials.json"
|
||||
export WAKE_BEACON_HMAC_KEY_NAME="beacon"
|
||||
jq -cn --arg k "test-beacon-hmac-key-do-not-echo" '{wake:{hmac_keys:{"beacon":$k}}}' >"$MOSAIC_CREDENTIALS_FILE"
|
||||
export WAKE_BEACON_INDEPENDENCE="off-host"
|
||||
# A capturing sink that keeps the exact shipped (signed) beacon record.
|
||||
SHIPPED="$H/shipped.json"
|
||||
SINK="$H/sink.sh"; printf '#!/usr/bin/env bash\ncat >"%s"\n' "$SHIPPED" >"$SINK"; chmod +x "$SINK"
|
||||
export WAKE_BEACON_SINK_CMD="$SINK"
|
||||
export WAKE_BEACON_RECEIVED="$H/received.json"
|
||||
"$BEACON" emit >/dev/null 2>&1 || fail_msg "B12: a signed emit must succeed with a by-name key"
|
||||
jq -e '.beacon_envelope' "$SHIPPED" >/dev/null 2>&1 || fail_msg "B12: a configured key must produce a signed beacon_envelope [$(cat "$SHIPPED" 2>/dev/null)]"
|
||||
# (a) the authentic signed beacon is ACCEPTED at record.
|
||||
"$BEACON" record <"$SHIPPED" >/dev/null 2>&1 || fail_msg "B12: an authentic signed beacon must be accepted at record"
|
||||
[ -s "$WAKE_BEACON_RECEIVED" ] || fail_msg "B12: the authentic beacon must be stored"
|
||||
# (b) a SPOOFED beacon (fields altered, envelope lifted) is REJECTED.
|
||||
rm -f "$WAKE_BEACON_RECEIVED"
|
||||
spoof="$H/spoof.json"
|
||||
jq -c '.beacon_seq = 99999 | .host_id = "attacker"' "$SHIPPED" >"$spoof"
|
||||
out="$("$BEACON" record <"$spoof" 2>&1)"; rc=$?
|
||||
[ "$rc" -ne 0 ] || fail_msg "B12: a spoofed beacon (altered fields) must be REJECTED at record; got rc=$rc [$out]"
|
||||
echo "$out" | grep -qi 'spoofed beacon' || fail_msg "B12: the rejection must name the spoof [$out]"
|
||||
[ ! -s "$WAKE_BEACON_RECEIVED" ] || fail_msg "B12: a rejected spoof must NOT be stored (dead-man clock not advanced)"
|
||||
# (c) an UNSIGNED beacon is rejected when signing is configured.
|
||||
unsigned="$H/unsigned.json"
|
||||
jq -c 'del(.beacon_envelope)' "$SHIPPED" >"$unsigned"
|
||||
out2="$("$BEACON" record <"$unsigned" 2>&1)"; rc2=$?
|
||||
[ "$rc2" -ne 0 ] || fail_msg "B12: an unsigned beacon must be REJECTED when signing is configured; got rc=$rc2 [$out2]"
|
||||
# beacon.sh must not inline the key material.
|
||||
grep -qF "test-beacon-hmac-key-do-not-echo" "$BEACON" && fail_msg "B12: beacon.sh must NOT inline the HMAC key"
|
||||
true
|
||||
) && ok
|
||||
|
||||
echo
|
||||
if [ -s "$FAILFILE" ]; then
|
||||
echo "wake beacon harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2
|
||||
|
||||
Reference in New Issue
Block a user