Security & Reliability Fixes (commit bab38c4)

Three hardening fixes applied to the outbound relay in telegram-connector-overview. All work is in /Users/levander/coding/pmv2/telegram_connector-outbound on branch feat/outbound-relay.

Fix A — Bot Token Leak in Network Error Logs

Root Cause

reqwest::Error’s Display impl embeds the full request URL, which contains /bot<TOKEN>/. Any tracing log call on a raw reqwest::Error leaks the secret bot token.

Resolution:

  • Call .without_url() on any reqwest::Error before passing it to a tracing macro.
  • .without_url() consumes self, so the rebind pattern is required in match arms:
    Err(e) => {
        let e = e.without_url();
        tracing::warn!("network error: {e}");
    }
  • Extracted classify_getme(status: u16, body: &str) -> bool — pure function, trivially unit-testable.
  • Added TelegramClient::verify_token() -> anyhow::Result<bool> — GETs /bot{token}/getMe, delegates classification to classify_getme, strips URL from any network error.

Gotcha — Move Semantics

without_url() consumes self. Do NOT write Err(ref e) or try to borrow after calling it. The let e = e.without_url(); rebind pattern is the correct idiom.

Fix B — Required Config Fields

Problem

TELEGRAM_CHAT_ID and NATS_TELEGRAM_NKEY_SEED were optional-with-default. Missing values failed silently at runtime rather than failing loudly at startup.

Resolution:

  • Both fields promoted to required.
  • Missing or empty value → ConfigOutcome::Dormant returned at startup.
  • Service goes dormant immediately rather than running until the first message triggers a failure.

Fix C — Startup Token Preflight

After constructing TelegramClient and before entering the relay loop, verify_token() is called:

ResultBehaviour
Ok(true)Token valid — proceed
Ok(false)Hard bail — token known invalid upfront
Err(_)Warn and continue — network may not be ready at boot

This catches typos and revoked tokens before any JetStream messages are consumed.

Test Coverage

34 tests total (up from 26). 8 new tests:

  • Transient outcome on network error in verify_token
  • Token sanitization assertion (URL not present in logged error string)
  • classify_getme branches (ok/unauthorized/other status codes)
  • ConfigOutcome::Dormant on missing TELEGRAM_CHAT_ID
  • ConfigOutcome::Dormant on missing NATS_TELEGRAM_NKEY_SEED