Gabriel Radureau abe77f5873
All checks were successful
CI/CD / test (push) Successful in 20s
CI/CD / build-and-push-image (push) Successful in 58s
Phase 2d — gateway_jobs retention (Janitor goroutine)
Periodic cleanup goroutine, started alongside the worker when DATABASE_URL
is set. Three concerns :

- DELETE rows with status='done' older than QUEUE_DONE_RETENTION (default
  168h / 7 days). Past success rows have no value beyond debug runway.
- UPDATE rows stuck in status='running' for more than QUEUE_STUCK_TIMEOUT
  (default 30m) back to 'pending' so a worker can retry. Handles the
  case of a pod crashing mid-job (without this, jobs stay orphaned forever).
- 'dead' rows are NEVER auto-purged (volume negligible, kept for forensics).

Configurable via env :
- QUEUE_DONE_RETENTION (default 168h)
- QUEUE_STUCK_TIMEOUT  (default 30m)
- QUEUE_JANITOR_INTERVAL (default 1h)

The janitor runs once immediately at startup (recovers anything orphaned
by the previous pod before opening for new traffic), then ticks on the
interval.

Queue interface gains PurgeDone + RecoverStuck — both use Postgres'
make_interval(secs) for safe parameterization.

4 new unit tests via fakeQueue mock (47 total, race clean).
2026-05-09 16:06:54 +02:00
2026-05-09 12:23:59 +02:00
2026-05-09 12:23:59 +02:00
2026-05-09 12:23:59 +02:00

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/<slug> → 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) :

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=<your-tg-user-id>
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) :

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":<tg-id>},"chat":{"id":<tg-id>},"text":"hi"}}' \
     http://localhost:8080/bot/factory

Tests

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

# 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_<UPPER_SLUG>_TOKEN, BOT_<UPPER_SLUG>_SECRET. Sourced from Vault path kvv2/telegram-gateway/config via Vault Secrets Operator.

Cluster deploy

  • Image: gitea.arcodange.lab/arcodange/telegram-gateway:<tag>
  • 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
Description
No description provided
Readme 167 KiB
Languages
Go 96.2%
Smarty 1.9%
Makefile 1.4%
Dockerfile 0.5%