# telegram-gateway Telegram **webhook gateway** for the Arcodange home lab. Replaces polling-based bots (e.g. those scheduled in Cowork) with direct webhook delivery from Telegram, routed to per-bot handlers running on the k3s cluster. > Phase 1 (MVP): single sync `echo` handler, end-to-end flow validated. > Phase 2 (planned): `http` forward handler + Postgres-backed durable queue. > Phase 3 (planned): async `shell` / `script` / `ollama` handlers. See the design doc at `~/.claude/plans/pour-les-notifications-on-inherited-seal.md`. ## Architecture (current) ``` Telegram → Cloudflare Tunnel (tg.arcodange.fr) → Service telegram-gateway:8080 → /bot/ → secret_token check → handler dispatch → Bot API sendMessage ``` ## Routes | Method | Path | Description | |--------|------------------|--------------------------------------------| | GET | `/healthz` | Liveness probe | | GET | `/readyz` | Readiness probe | | POST | `/bot/{slug}` | Telegram webhook entry (validates secret) | ## Local dev Pour le dev local complet (Redis pour l'auth + Postgres pour la queue) : ```bash make compose-up # docker compose up -d --wait : redis + postgres export REDIS_URL=redis://localhost:6379/0 export DATABASE_URL=postgres://gateway:gateway@localhost:5432/gateway?sslmode=disable export AUTH_SECRET=$(openssl rand -hex 16) export ALLOWED_USERS= export BOT_FACTORY_TOKEN='8737289837:…' # from @BotFather export BOT_FACTORY_SECRET=$(openssl rand -hex 32) make run # uses bots.example.yaml ``` Smoke d'un webhook (sans Telegram cloud) : ```bash curl -X POST -H "X-Telegram-Bot-Api-Secret-Token: $BOT_FACTORY_SECRET" \ -H 'Content-Type: application/json' \ -d '{"update_id":1,"message":{"message_id":1,"from":{"id":},"chat":{"id":},"text":"hi"}}' \ http://localhost:8080/bot/factory ``` ## Tests ```bash make test # unit + integration (in-process miniredis + httptest mock Telegram) make test-race # avec race detector make vet ``` 43 tests couvrent : allowlist parsing, secret comparison, auth flow (login/logout/whoami/replay-defense), echo handler (plain/slash/empty), http handler (forward/timeout/non-2xx/empty), webhook dispatch (bad secret 401, unknown bot 404, allowlist drop, gated bot prompt, full /auth → echo flow). Pour des smokes locaux contre une vraie API Telegram, voir la section "Local dev" ci-dessus. ## Set / delete webhook ```bash # Once the gateway is reachable at https://tg.arcodange.fr: export BOT_FACTORY_TOKEN=… export BOT_FACTORY_SECRET=… make setwebhook SLUG=factory BASE_URL=https://tg.arcodange.fr make deletewebhook SLUG=factory ``` ## Configuration - **Routing** (non-secret): YAML at `$CONFIG_PATH` (default `/etc/telegram-gateway/bots.yaml`, mounted from a ConfigMap in cluster). - **Secrets**: per-bot env vars `BOT__TOKEN`, `BOT__SECRET`. Sourced from Vault path `kvv2/telegram-gateway/config` via Vault Secrets Operator. ## Cluster deploy - Image: `gitea.arcodange.lab/arcodange/telegram-gateway:` - Helm chart: `chart/` - ArgoCD app: `telegram-gateway` (in `factory/argocd/values.yaml`) - Public URL: `https://tg.arcodange.fr` (Cloudflare déjà configuré pour router `*.arcodange.fr` vers le home lab → Traefik route par Host) - Secrets Phase 1 : `kubectl create secret generic telegram-gateway-bots …` (sans Vault). Migration vers Vault Secrets Operator en Phase 2+ via `vault.enabled: true` dans `chart/values.yaml`. Voir `DEPLOY.md` pour la procédure end-to-end. ## Layout ``` . ├── main.go # bootstrap, subcommand dispatch ├── server.go # HTTP routes ├── middleware.go # secret validation, recover, access log ├── handlers.go # Handler interface + Registry ├── handler_echo.go # echo handler ├── telegram.go # Telegram Bot API client ├── telegram_types.go # Update / Message structs ├── config.go # YAML routing config + per-bot env merge ├── setwebhook.go # CLI subcommands (setwebhook / deletewebhook) ├── chart/ # Helm chart └── .gitea/workflows/ # CI: docker build → gitea registry ```