All projects

Technical Report · Docker & DevOps

GitHub Webhook Deploy Listener

Lightweight deployment listener that validates GitHub webhook signatures, filters push events/branches, maps repositories to deployment scripts and runs deployments under systemd.

AUTHOR  Gaurav Verma CATEGORY  Docker & DevOps SOURCE  https://github.com/GAURAV-321/github-webhook-deploy-listener DATE  Apr 2026 STATUS  published
View Source Python Deployment GitHub Webhooks HMAC Shell systemd

Abstract

A small Python HTTP service that receives authenticated GitHub push webhooks, validates X-Hub-Signature-256 HMAC signatures, filters by branch, and dispatches repository-specific shell deployment scripts under systemd. The design keeps the listener generic while making all deployment routing explicit in configuration.

1. What This Is

A focused CI/CD building block, not a full pipeline platform. The listener exposes a single HTTP endpoint for GitHub push and ping events, authenticates each request via HMAC, and hands off to a pre-configured shell script for the matched repository. It runs as a long-lived systemd service on a Linux host, so there is no external CI runner or container orchestrator in the loop.

2. How It Works

# Stage Input Tool Output
01 Receive webhook GitHub push / ping event Python HTTP service Parsed request
02 Verify signature X-Hub-Signature-256 header + shared secret HMAC-SHA256 Accept or reject
03 Filter event Repository name, branch Config mapping Matched script path or ignore
04 Run deployment Resolved shell script Shell (background) Deployment logs
05 Stay alive systemd unit file systemd Persistent listener process

3. Implementation Notes

3.1 HMAC gate

Every request is checked against the configured shared secret using X-Hub-Signature-256 before any event parsing or script resolution happens. Unsigned or mismatched requests are dropped immediately, which matters because the endpoint can trigger arbitrary server-side scripts.

3.2 Repository-to-script mapping

Deployment behavior lives in a configuration file that maps repository names and allowed branches to explicit shell script paths. The listener itself contains no deployment logic, so adding a new repo means adding one config entry and one script rather than touching the listener code.

3.3 systemd service

The listener ships with a systemd unit file so it runs as a supervised, auto-restarting process on the target host. Deployment work is dispatched in the background so the HTTP response returns quickly and the listener stays available for the next push.

4. Constraints

  • Single-host, single process

    One systemd unit on one machine. No load balancing, no horizontal scale, no queue. A second push while the first script is still running will overlap.

  • Shell scripts as the deployment unit

    No container orchestration, no rollback step, no built-in retry. If a script fails mid-run, the operator must intervene manually.

  • No rate limiting or concurrency guard

    Rapid successive pushes to the same branch can spawn multiple background scripts simultaneously. There is no lock or queue to serialize them.

  • No health-check or metrics endpoint

    Operational visibility is limited to log files. There is no /healthz probe or structured metrics for monitoring dashboards.

5. Next

  1. a. Add a file-based lock or in-process semaphore so concurrent pushes to the same repo are serialized.
  2. b. Expose a /healthz endpoint and structured JSON logs so the service can be monitored by systemd or an external probe.
  3. c. Wrap the shell scripts in a thin retry/rollback layer that snapshots state before deploy and reverts on non-zero exit.

— end of report —