From 0c52905f4bb2b0f6451076ddeb04abf2729f2d9b Mon Sep 17 00:00:00 2001 From: Petrus Pennanen Date: Sat, 4 Jul 2026 18:03:43 +0200 Subject: [PATCH] fix(poller): treat 401/403 as loud auth failures + hot-reload the key A rotated key returned a 401 error BODY with curl exit 0, which parsed as an empty room and silently muted the poller for 16h (Jul 3). The fetch now captures the HTTP status; on 401/403 it logs AUTH FAIL and re-reads poller.api_key from config so a rotation self-heals in one cycle. Co-Authored-By: Claude Opus 4.8 --- scripts/claudemb-poll.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/scripts/claudemb-poll.sh b/scripts/claudemb-poll.sh index 826f0d2..86cd49c 100755 --- a/scripts/claudemb-poll.sh +++ b/scripts/claudemb-poll.sh @@ -123,17 +123,44 @@ echo "" while true; do response=$(curl -sS --connect-timeout "$HTTP_CONNECT_TIMEOUT_SEC" --max-time "$HTTP_TIMEOUT_SEC" -H "X-API-Key: $API_KEY" \ + --write-out '\n%{http_code}' \ "$BASE_URL/rooms/$ROOM/messages?limit=$FETCH_LIMIT" 2>&1) || { echo "[$(date +%H:%M:%S)] fetch error: $response" sleep "$POLL_INTERVAL" continue } + # Split off the trailing HTTP status appended by --write-out. + http_code="${response##*$'\n'}" + response="${response%$'\n'*}" + # 2026-07-03 fix: a rotated/dead key returns 401 with an error BODY, and + # curl (no --fail) exits 0, so the old code parsed it as an empty room and + # went silent for 16h. Treat auth failure as a hard, VISIBLE error and + # hot-reload the key from config so a rotation self-heals without a manual + # restart. + if [[ "$http_code" == "401" || "$http_code" == "403" ]]; then + echo "[$(date +%H:%M:%S)] AUTH FAIL (HTTP $http_code): ${response:0:120}" + reloaded="$(read_json_value 'poller.api_key')" + if [[ -n "$reloaded" && "$reloaded" != "$API_KEY" ]]; then + API_KEY="$reloaded" + echo "[$(date +%H:%M:%S)] reloaded api_key from config; retrying next cycle" + else + echo "[$(date +%H:%M:%S)] config key unchanged/empty; needs rotation in config" + fi + sleep "$POLL_INTERVAL" + continue + fi new_count=0 while IFS=$'\t' read -r msg_id msg_from msg_body; do [[ -z "$msg_id" ]] && continue if ! grep -qF -- "$msg_id" "$SEEN_IDS_FILE"; then echo "$msg_id" >> "$SEEN_IDS_FILE" + # Skip our OWN posts so they never wake us (the echo loop petrus + # asked to kill, 2026-07-02). Marked seen above so we don't + # reconsider; just don't notify/wake on self-authored messages. + case "$(printf '%s' "$msg_from" | tr '[:upper:]' '[:lower:]')" in + @claudemb|claudemb) continue ;; + esac new_count=$((new_count + 1)) body_preview="${msg_body:0:120}" echo "[$(date +%H:%M:%S)] NEW ${msg_from}: ${body_preview}"