Skip to content

fix(telegram): stop auto-linking destinations in /policy show#32

Merged
nnemirovsky merged 2 commits intomainfrom
fix-telegram-policy-no-autolinks
Apr 13, 2026
Merged

fix(telegram): stop auto-linking destinations in /policy show#32
nnemirovsky merged 2 commits intomainfrom
fix-telegram-policy-no-autolinks

Conversation

@nnemirovsky
Copy link
Copy Markdown
Owner

@nnemirovsky nnemirovsky commented Apr 13, 2026

Summary

Destinations across Telegram surfaces (/policy show, approval prompts, /policy allow|deny confirmations) rendered as clickable blue links because Telegram auto-detects URL patterns in plain-text messages.

Fix: wrap destinations and request URLs in <code>...</code> and send with HTML parse mode. Inside <code> Telegram does not auto-link URLs, and text still flows and wraps naturally at spaces (unlike a full <pre> block, which forced mid-identifier wrapping on long lines).

Changes

  • internal/telegram/commands.go:
    • htmlCode helper wraps a string in <code>...</code> after HTML-escaping.
    • policyShow and policyShowFromStore wrap destination, tool, pattern, replacement, protocols, default verdict in <code>. Section headers (ALLOW, DENY, ASK, REDACT) go through <b>.
    • policyAllow / policyDeny confirmation messages wrap the destination in <code> on both the store and in-memory paths.
  • internal/telegram/bot.go FormatApprovalMessage:
    • host:port in the connection line, the full request URL, and the MCP tool name all go through <code>.
  • internal/telegram/approval.go: the reply sender enables HTML parse mode (with web-page preview off) when the response contains <code> or <b>. Plain-text replies are unchanged because HTML-escaping prevents those tags from appearing in non-HTML output.
  • Removed the duplicate htmlEscapeText from commands.go; everything now uses the existing htmlEscape in bot.go.
  • Tests: TestPolicyShowEscapesHTML, tag-presence checks in TestPolicyShowIncludesAllFields, and updated TestFormatApprovalMessage expectations.

Test plan

  • go test ./... passes
  • go build ./... clean
  • gofumpt clean
  • Manual: /policy renders destinations as inline monospace, no blue links
  • Manual: approval prompts render host:port and request URLs as monospace
  • Manual: /policy allow <dest> confirmation shows <dest> as monospace

Telegram was rendering every destination string in /policy show output
as a clickable blue link (example.com, api.github.com, etc.) because
the message was sent in plain text mode and Telegram auto-detects URL
patterns.

Wrap the output in <pre>...</pre> and send with ParseMode=HTML +
DisableWebPagePreview. Inside a preformatted block Telegram leaves URL
patterns alone, and the monospace rendering also aligns the columns
better.

- commands.go: htmlPreOpen/htmlPreClose constants, htmlEscapeText
  helper, wrap both policyShow (engine fallback) and
  policyShowFromStore in <pre>. Escape destination, tool, pattern,
  replacement, name, source, default verdict, and protocols.
- approval.go: sendReply path sniffs the <pre> prefix and switches to
  HTML parse mode with web-page preview disabled. Other replies are
  still plain text.
- Tests: TestPolicyShowEscapesHTML and a wrapping check in
  TestPolicyShowIncludesAllFields.
@nnemirovsky nnemirovsky force-pushed the fix-telegram-policy-no-autolinks branch from 56f3500 to 6b3946f Compare April 13, 2026 05:55
Extends the /policy show fix to the other Telegram surfaces that
render destinations or URLs: approval prompts and policy mutation
confirmations (allow/deny). Without this, Telegram auto-links the
destination in strings like 'HTTPS api.github.com:443' or 'Added
allow rule: example.com' as a clickable blue URL.

- bot.go FormatApprovalMessage: wrap dest:port and the rendered
  request URL in <code>. MCP tool name also in <code>.
- commands.go policyAllow / policyDeny: wrap dest in <code> on both
  store and in-memory paths.
- Consolidate the duplicated htmlEscape helpers: commands.go now uses
  the existing htmlEscape from bot.go, local wrapper removed.
- Update bot_test.go expectations to match the <code>-wrapped output.
@nnemirovsky nnemirovsky merged commit 6f673c4 into main Apr 13, 2026
6 checks passed
@nnemirovsky nnemirovsky deleted the fix-telegram-policy-no-autolinks branch April 13, 2026 06:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant