Redbot GitHub Forwarder
Discord webhook ingestion engine and developer notification bridge
Architecture overview
The Redbot GitHub Forwarder is an asynchronous Python cog built for Red Discord Bot to provide real-time development observability.
It exposes an embedded aiohttp HTTP endpoint to receive GitHub repository webhooks, verifies incoming payload authenticity using HMAC-SHA256 signatures, and transforms raw event payloads into structured Discord embeds across team channels.
Event processing pipeline
The cog processes repository events through four distinct stages:
| Stage | Process | Action |
|---|---|---|
| 1. Ingress and auth | aiohttp HTTP server |
Receives POST request and validates HMAC-SHA256 signature against secret token |
| 2. Event parser | Payload normalizer | Parses JSON payload into structured Python dataclasses (PushEvent, PullRequestEvent, WorkflowRunEvent) |
| 3. Channel router | Rules engine | Maps repository name and event type to configured destination Discord channel IDs |
| 4. Dispatcher | discord.py embedder |
Formats color-coded status embeds and sends messages asynchronously |
Key technical implementations
1. Ingress and cryptographic HMAC-SHA256 verification
GitHub delivers webhook payloads via HTTPS POST requests with the signature stored in the X-Hub-Signature-256 header. The cog calculates the payload’s HMAC-SHA256 digest and performs constant-time comparison to prevent timing attacks:
View Python implementation: handle_github_webhook
import hashlib
import hmac
from aiohttp import web
async def handle_github_webhook(request: web.Request, secret_token: str) -> web.Response:
signature_header = request.headers.get("X-Hub-Signature-256")
if not signature_header or not signature_header.startswith("sha256="):
return web.Response(status=401, text="Missing or invalid signature header.")
body = await request.read()
expected_signature = "sha256=" + hmac.new(
key=secret_token.encode("utf-8"),
msg=body,
digestmod=hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature_header, expected_signature):
return web.Response(status=403, text="HMAC signature verification failed.")
payload = await request.json()
event_type = request.headers.get("X-GitHub-Event", "ping")
await dispatch_event(event_type, payload)
return web.Response(status=200, text="Webhook received.")
2. Event normalization and Discord embed construction
The dispatcher converts GitHub Actions CI/CD runs, Pull Requests, and commits into clean Discord embeds:
View Python implementation: build_workflow_run_embed
import discord
def build_workflow_run_embed(payload: dict) -> discord.Embed:
workflow = payload.get("workflow_run", {})
conclusion = workflow.get("conclusion")
status = workflow.get("status")
repo_name = payload.get("repository", {}).get("full_name", "")
commit_msg = workflow.get("head_commit", {}).get("message", "").split("\n")[0]
# Map conclusion to Discord color
color_map = {
"success": discord.Color.green(),
"failure": discord.Color.red(),
"cancelled": discord.Color.dark_grey(),
"timed_out": discord.Color.orange()
}
color = color_map.get(conclusion, discord.Color.blurple())
embed = discord.Embed(
title=f"CI Workflow: {workflow.get('name')} #{workflow.get('run_number')}",
url=workflow.get("html_url", ""),
description=f"**Status:** `{conclusion or status}`\n**Commit:** {commit_msg}",
color=color
)
embed.set_author(name=repo_name, url=payload.get("repository", {}).get("html_url", ""))
embed.set_footer(text=f"Triggered by {workflow.get('actor', {}).get('login')}")
return embed
3. Configurable channel routing and filters
Server administrators configure channel destinations per repository or per event category using Redbot slash commands. This routes high-frequency commit logs to activity feeds while directing release announcements and build failures to dedicated alerts channels.