- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The sync account feeds the forge from GitHub without firing pull_request or release webhooks, so releases were only ever surfaced in the digest and reviews not at all. Poll for both and fold the outcome into the messages already kept. - reviews: the PR poller reads each open pull request's reviews and shows who approved or requested changes on the same message, latest decisive review per reviewer, behind REVIEWS_ENABLED - weekly digest: scheduled summary of merged pull requests, commits and releases over the last seven days, also on demand with /digest - release polling: read releases on an interval and post a new one with its files and checksums, dedup shared with the webhook path so nothing posts twice - health: /healthz serves per-task liveness JSON and answers 503 once a poller stalls, /status and a new /repos report it in the group, and a poller failing repeatedly alerts the admin chat |
||
| .github | ||
| deploy | ||
| docs | ||
| gitbot | ||
| media | ||
| tests | ||
| tools | ||
| .env.example | ||
| .gitignore | ||
| CHANGELOG.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
nonos-gitbot
Posts commits, pull requests and releases from git.nonos.software into the Telegram group. It reads a Forgejo organisation webhook, verifies every delivery, filters the noise, and links to our own forge, never to GitHub.
The full design, event fields and forge-side setup are in the team brief on the maintainers' side. This README is how to run it.
What it posts
- Commits pushed to a repository's default branch, showing the commit
authors rather than the
nonos-syncaccount that carries them across. - Pull requests: opened as a new message, then edited in place as they are updated, closed or merged, so each PR is one line that changes state.
- Releases when published.
Each event is posted as a banner image with the message as its caption. A pull request is one message whose image and caption are swapped together as it opens, merges or closes.
Everything else (other branches, branch create and delete, draft PRs, private repos, duplicate deliveries) is dropped.
Run it
python3 -m pip install -r requirements.txt
cp .env.example .env # fill BOT_TOKEN, CHAT_ID, WEBHOOK_SECRET
python3 -m gitbot
It listens on 127.0.0.1:3191/forgejo by default and answers /healthz.
The forge admin points the organisation webhook at that address with the
shared secret.
Security
- Every delivery's HMAC-SHA256 is checked over the raw body before the JSON is parsed, in constant time. A bad signature gets a 401 and the payload is never logged.
- The bot token and webhook secret load from files or a systemd credential, never from the process environment, and are redacted from logs.
- It listens on loopback only and talks outbound to
api.telegram.organd the forge.
Deploy
deploy/gitbot.service runs it as its own user with ProtectSystem=strict,
no capabilities, private tmp, and secrets via LoadCredential. Put the two
secret files under /etc/nonos-gitbot/, install the unit, and enable it.
Tests
python3 -m unittest discover -s tests -t .
37 tests, no network: HMAC verification, event parsing, the noise filters, message rendering, author recovery, dedup and the PR edit-in-place flow.
Layout
gitbot/config.py environment, validated at start
gitbot/webhook.py receiver: verify, dedup, fast 202, dispatch
gitbot/events.py parse Forgejo payloads into model objects
gitbot/models.py the data shapes and their derived properties
gitbot/filters.py what to post, edit or drop
gitbot/authors.py recover the real author of a synced PR
gitbot/render.py message shapes (HTML)
gitbot/banners.py which banner image goes with which event
gitbot/telegram.py Bot API client with a serialising, rate-limited worker
gitbot/handler.py events to Telegram jobs
gitbot/state.py dedup ring and PR message map, atomic 0600
gitbot/app.py wiring and shutdown