Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion notify/telegram/telegram.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (n *Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, err
ParseMode: n.conf.ParseMode,
})
if err != nil {
return true, err
return true, notify.RedactURL(err)
}
logger.Debug("Telegram message successfully published", "message_id", message.ID, "chat_id", message.Chat.ID)

Expand Down
73 changes: 73 additions & 0 deletions notify/telegram/telegram_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,76 @@ func TestTelegramNotify(t *testing.T) {
})
}
}

// TestTelegramNotifyRedactURL verifies that notify.RedactURL is applied to the
// error returned by client.Send, so the bot token is never exposed in logs.
func TestTelegramNotifyRedactURL(t *testing.T) {
token := "secret"

t.Run("transport error redacts URL", func(t *testing.T) {
// Point at a closed server so telebot returns a *url.Error with the full URL.
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
u, _ := url.Parse(srv.URL)
srv.Close() // closed immediately — next dial will fail

notifier, err := New(
&config.TelegramConfig{
HTTPConfig: &commoncfg.HTTPClientConfig{},
APIUrl: &amcommoncfg.URL{URL: u},
BotToken: commoncfg.Secret(token),
},
test.CreateTmpl(t),
promslog.NewNopLogger(),
)
require.NoError(t, err)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ctx = notify.WithGroupKey(ctx, "1")

retry, err := notifier.Notify(ctx, &types.Alert{
Alert: model.Alert{Labels: model.LabelSet{"alertname": "test"}},
})
require.True(t, retry)
require.Error(t, err)
// The token must not appear in the error string.
require.NotContains(t, err.Error(), token, "bot token leaked in transport error")
// The URL should be redacted.
require.Contains(t, err.Error(), "<redacted>")
})

t.Run("Telegram API error passes through without token", func(t *testing.T) {
// Return a Telegram API error response — telebot wraps this as its own
// error type (not *url.Error), so RedactURL is a no-op, but the token
// is not in the error string either.
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"ok":false,"description":"Bad Request: chat not found","error_code":400}`))
}))
defer srv.Close()
u, _ := url.Parse(srv.URL)

notifier, err := New(
&config.TelegramConfig{
HTTPConfig: &commoncfg.HTTPClientConfig{},
APIUrl: &amcommoncfg.URL{URL: u},
BotToken: commoncfg.Secret(token),
},
test.CreateTmpl(t),
promslog.NewNopLogger(),
)
require.NoError(t, err)

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ctx = notify.WithGroupKey(ctx, "1")

retry, err := notifier.Notify(ctx, &types.Alert{
Alert: model.Alert{Labels: model.LabelSet{"alertname": "test"}},
})
require.True(t, retry)
require.Error(t, err)
require.NotContains(t, err.Error(), token, "bot token leaked in API error")
})
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
from pathlib import Path

path = Path("notify/telegram/telegram_test.go")
src = path.read_text()

i = 0
line = 1
stack = 0
state = "code"

while i < len(src):
    c = src[i]
    n = src[i + 1] if i + 1 < len(src) else ""

    if state == "code":
        if c == "/" and n == "/":
            state = "line_comment"; i += 1
        elif c == "/" and n == "*":
            state = "block_comment"; i += 1
        elif c == '"':
            state = "double_quote"
        elif c == "'":
            state = "single_quote"
        elif c == "`":
            state = "raw_quote"
        elif c == "{":
            stack += 1
        elif c == "}":
            stack -= 1
            if stack < 0:
                print(f"unmatched closing brace near line {line}")
                break

    elif state == "line_comment":
        if c == "\n":
            state = "code"

    elif state == "block_comment":
        if c == "*" and n == "/":
            state = "code"; i += 1

    elif state == "double_quote":
        if c == "\\":
            i += 1
        elif c == '"':
            state = "code"

    elif state == "single_quote":
        if c == "\\":
            i += 1
        elif c == "'":
            state = "code"

    elif state == "raw_quote":
        if c == "`":
            state = "code"

    if c == "\n":
        line += 1
    i += 1
else:
    print(f"brace_balance={stack}")
PY

Repository: prometheus/alertmanager

Length of output: 105


Remove the stray closing brace at Line 288 in notify/telegram/telegram_test.go

The file contains an unmatched }, so it will fail to parse/compile.

💡 Proposed fix
@@
-}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@notify/telegram/telegram_test.go` at line 288, There is an unmatched closing
brace in notify/telegram/telegram_test.go (a stray "}" at the end of the file)
that prevents the tests from compiling; remove that extra brace so the file's
braces properly match and the surrounding test functions (e.g., the test
function blocks in this file) close correctly.