#!/bin/bash # notify-telegram.sh — send a message to the configured Telegram chat. # Sources credentials from $ALEMBIC_CONFIG_DIR/pipeline/telegram/notify.env (chmod 600). # # Usage: # echo "single line message" | notify-telegram.sh # notify-telegram.sh "single line message" # notify-telegram.sh --html < ${ALEMBIC_CONFIG_DIR:-/config}/logs/STATUS.log # # --html sends with parse_mode=HTML for messages authored as Telegram-HTML # (pipeline-status.sh's digest: ///
/
). The # CALLER is responsible for escaping &, <, > in any free text; this script # only guarantees the truncation below can't cut a tag in half. Without the # flag, messages go as plain text exactly as before. # # Telegram messages are capped at 4096 chars. Anything longer is truncated; # in HTML mode the cut lands on a line boundary and re-closes an open
# so the truncated message still parses (a mid-tag cut, or a bare "<" in the
# tail marker, makes the Bot API reject the ENTIRE message with a 400).
# Returns exit 0 on send-OK, non-zero otherwise.

set -euo pipefail
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

PARSE_MODE=""
if [[ "${1:-}" == "--html" ]]; then
  PARSE_MODE="HTML"
  shift
fi

CONFIG="${ALEMBIC_CONFIG_DIR:-/config}/pipeline/telegram/notify.env"
if [[ ! -f "$CONFIG" ]]; then
  echo "[notify-telegram] no config at $CONFIG" >&2
  exit 1
fi
# shellcheck disable=SC1090
source "$CONFIG"
: "${TG_BOT_TOKEN:?TG_BOT_TOKEN missing}"
: "${TG_CHAT_ID:?TG_CHAT_ID missing}"

# Read message from arg or stdin
if [[ $# -ge 1 ]]; then
  MSG="$*"
else
  MSG=$(cat)
fi

# Telegram caps at 4096 chars. Trim conservatively at 3900. Use python for
# proper UTF-8 length handling. Plain mode appends a literal marker; HTML
# mode cuts at the last newline inside the budget (our tags never span
# lines except 
 blocks) and re-closes an unbalanced 
.
MSG=$(python3 -c "
import sys
s = sys.argv[1]
html = sys.argv[2] == 'HTML'
if len(s) > 3900:
    s = s[:3900]
    if html:
        cut = s.rfind('\n')
        if cut > 0:
            s = s[:cut]
        if s.count('
') > s.count('
'): s += '
' s += '\n… truncated' else: s += '\n...(truncated)' print(s, end='') " "$MSG" "${PARSE_MODE:-plain}") # Send via Bot API. Preview disabled; parse_mode only when requested so log # content with special chars can't be misread as markup in plain sends. # `|| true`: a curl timeout/network error must fall through to the explicit # ok-check below (which reports "send failed" and exits 2), not abort here. resp=$(curl -s --max-time 15 -X POST \ "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \ --data-urlencode "chat_id=${TG_CHAT_ID}" \ --data-urlencode "text=${MSG}" \ ${PARSE_MODE:+--data-urlencode "parse_mode=${PARSE_MODE}"} \ --data-urlencode "disable_web_page_preview=true" || true) ok=$(echo "$resp" | python3 -c "import sys,json;print(json.load(sys.stdin).get('ok',False))" 2>/dev/null || echo False) if [[ "$ok" != "True" ]]; then echo "[notify-telegram] send failed: $resp" >&2 exit 2 fi exit 0