From 947e8b24e0ea76094ca582c1ed5008538f7e49a5 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 9 Sep 2026 02:47:44 +0000 Subject: [PATCH] fix(zulip-monitor): stream alert body now carries real content, plain & params, WARN on delivery failure The #agent-hub / zulip-health stream post in notify() encoded content with python quote(str()) (always empty), so every stream alert posted empty content and Zulip rejected it silently behind '|| true'. The merged body also used backslash-escaped ampersands inside double quotes, which curl transmits literally (type=stream\ -> Zulip 400 'Invalid type'). Stream post now percent-encodes the real message text by piping it through the encoder (locale-proof: quote_from_bytes on stdin.buffer), uses plain & separators, and on failure appends one WARN line to the monitor log with the curl exit status instead of silently swallowing it. Delivery failure stays non-fatal and unretried. DM path, probes, alive rule, exit codes and log format unchanged. --- scripts/zulip-monitor.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/zulip-monitor.sh b/scripts/zulip-monitor.sh index e0c815c..d24f960 100755 --- a/scripts/zulip-monitor.sh +++ b/scripts/zulip-monitor.sh @@ -29,8 +29,9 @@ notify() { local stream_content="${severity} Zulip Monitor: ${msg}" curl -sf -X POST "${ZULIP_SITE}/api/v1/messages" \ -u "${ZULIP_EMAIL}:${ZULIP_KEY}" \ - -d "type=stream\&to=%5B7%5D\&topic=zulip-health\&content=$(python3 -c "import urllib.parse; print(urllib.parse.quote(str()))")" \ - > /dev/null 2>&1 || true + -d "type=stream&to=%5B7%5D&topic=zulip-health&content=$(printf '%s' "${stream_content}" | python3 -c "import sys,urllib.parse; print(urllib.parse.quote_from_bytes(sys.stdin.buffer.read()))")" \ + > /dev/null 2>&1 \ + || echo " WARN: stream alert to #agent-hub (zulip-health) delivery failed (curl exit $?)" >> "$LOG" } # ── Global: Zulip Server ──