Skip to content

patrickramp/rusty-hook

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Rusty-Hook

A secure, high-performance webhook server built in Rust for processing Git server webhooks (Forgejo, Gitea, GitHub) with flexible routing strategies. Perfect for automating deployments, builds, and other CI/CD tasks.

Features

  • πŸ›‘οΈ Security First: HMAC-SHA256 signature verification with constant-time comparison
  • πŸš€ High Performance: Built with Actix Web for excellent performance and memory safety
  • πŸ”€ Flexible Routing: Multiple routing strategies (path-based, repository-based, event-based, single)
  • πŸ“¦ Container Ready: Designed for containerized deployments with Docker/Podman
  • πŸ” Rich Context: Passes comprehensive webhook context to your scripts
  • πŸ“Š Observability: Structured logging with health check endpoint
  • πŸ”§ Configuration: Environment variable based configuration with validation

Quick Start

1. Build the Server

git clone <repository-url>
cd rusty-hook
cargo build --release

2. Configure Environment

Create a .env file:

# Required
WEBHOOK_SECRET=your-super-secure-webhook-secret-here #(Minimum 16 characters)

# Routing Strategy
ROUTING_STRATEGY=path

# Path-based routing executables
WEBHOOK_EXEC_BLOG=./scripts/deploy-blog.sh
WEBHOOK_EXEC_DOCS=./scripts/deploy-docs.sh
WEBHOOK_EXEC_API=./scripts/deploy-api.sh

# Server Configuration
BIND_ADDRESS=127.0.0.1:8080
WEBHOOK_ROUTE=/webhook
MAX_PAYLOAD_SIZE=2097152 #2MB

3. Create Deployment Script (example)

#!/bin/bash
# scripts/deploy-blog.sh
set -euo pipefail

echo "Deploying ${WEBHOOK_REPOSITORY} from ${WEBHOOK_REF}"
echo "Git Event: ${WEBHOOK_EVENT}, Private repo: ${WEBHOOK_PRIVATE_REPO}"
echo "Pusher name: ${WEBHOOK_PUSHER_NAME}, Pusher Email: ${WEBHOOK_PUSHER_EMAIL}"
echo "Route Key: ${WEBHOOK_ROUTE_KEY}, Git Action: ${WEBHOOK_ACTION}"

# Your deployment logic here
if [[ "$WEBHOOK_REF" == "refs/heads/main" ]]; then
    echo "Deploying to main branch..."
    # hugo build, docker deploy, etc.
fi

4. Run the Server

# Development
cargo run

# Production
./target/release/rusty-hook

5. Configure Webhooks

Set up webhooks pointing to:

  • Blog: https://yourserver.com/webhook/blog
  • Docs: https://yourserver.com/webhook/docs
  • API: https://yourserver.com/webhook/api

Routing Strategies

Path-Based Routing (Recommended)

Route webhooks based on URL path. Each path maps to a specific executable.

ROUTING_STRATEGY=path
WEBHOOK_EXEC_BLOG=./scripts/deploy-blog.sh
WEBHOOK_EXEC_DOCS=./scripts/deploy-docs.sh
WEBHOOK_EXEC_API=./scripts/deploy-api.sh

Webhook URLs:

  • /webhook/blog β†’ deploy-blog.sh
  • /webhook/docs β†’ deploy-docs.sh
  • /webhook/api β†’ deploy-api.sh

Repository-Based Routing

Route based on repository name from the webhook payload. (Replace "/" and "-" with "_" when creating variable names)

ROUTING_STRATEGY=repository

# Variable name format: WEBHOOK_EXEC_<Optional<USER>><REPOSITORY>
WEBHOOK_EXEC_MYAPP=./scripts/deploy-myapp.sh
# Replace "-" with "_" for hyphenated repo name: cool-app
WEBHOOK_EXEC_COOL_APP=./scripts/deploy-cool-app.sh
# Replace "/" with "_" for full repo name with user: username/repo-name
WEBHOOK_EXEC_USERNAME_REPO_NAME=./scripts/deploy-user-specific-payload.sh

Event-Based Routing

Route based on Git event type (push, pull_request, release, etc.).

ROUTING_STRATEGY=event
WEBHOOK_EXEC_PUSH=./scripts/deploy.sh
WEBHOOK_EXEC_PULL_REQUEST=./scripts/test.sh
WEBHOOK_EXEC_RELEASE=./scripts/release.sh

Single Executable

Use one script for all webhooks (default behavior).

ROUTING_STRATEGY=single
EXECUTABLE_PATH=./scripts/universal-handler.sh

Script Context

Your scripts receive rich context via environment variables:

Variable Description Example
WEBHOOK_EVENT Git event type push, pull_request, release
WEBHOOK_REPOSITORY Repository name my-blog, documentation
WEBHOOK_PUSHER_NAME Name of Git pusher John Doe, Alice Smith
WEBHOOK_PUSHER_EMAIL Email of Git pusher jdoe@example.com, alice@email.com
WEBHOOK_REF Git reference refs/heads/main, refs/tags/v1.0.0
WEBHOOK_ROUTE_KEY Webhook route identifier blog, docs, api
WEBHOOK_PRIVATE_REPO Is repository private true, false
WEBHOOK_ACTION Git action (if present) opened, closed, merged

Container Deployment

Docker Compose Setup

version: '3.8'

services:
  webhook-server:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: git-webhook
    restart: unless-stopped
    environment:
      - ROUTING_STRATEGY=path
      - WEBHOOK_SECRET=${WEBHOOK_SECRET}
      - BIND_ADDRESS=0.0.0.0:8080
      - WEBHOOK_EXEC_BLOG=./scripts/deploy-blog.sh
      - WEBHOOK_EXEC_DOCS=./scripts/deploy-docs.sh
    volumes:
      - ./scripts:/opt/scripts:ro
      - ./web-content:/var/www:rw
      - ./git-repos:/opt/repos:rw
    ports:
      - "127.0.0.1:8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3

Security Considerations

  • Signature Verification: Always verifies HMAC-SHA256 signatures using constant-time comparison
  • Content Type Validation: Only accepts application/json payloads
  • Rate Limiting: Configure reverse proxy rate limiting
  • HTTPS: Always use HTTPS in production
  • Minimal Permissions: Run with minimal filesystem permissions
  • Input Validation: All environment variables are validated on startup

Configuration Reference

Environment Variables

Variable Required Default Description
WEBHOOK_SECRET βœ… - Secret key for HMAC verification (min 16 chars)
ROUTING_STRATEGY ❌ single Routing strategy: path, repository, event, single
EXECUTABLE_PATH ❌ ./scripts/deploy.sh Default executable for single strategy
WEBHOOK_EXEC_<KEY> ❌ - Executable mappings for routing strategies
BIND_ADDRESS ❌ 127.0.0.1:8080 Server bind address
WEBHOOK_ROUTE ❌ /webhook Base webhook route
MAX_PAYLOAD_SIZE ❌ 1048576 Maximum payload size in bytes

Supported Webhook Headers

  • X-Hub-Signature-256 (GitHub, Forgejo)
  • X-Forgejo-Signature (Forgejo)
  • X-Gitea-Signature (Gitea)
  • X-Forgejo-Event / X-Gitea-Event (Event type)

Monitoring

Health Check

curl http://localhost:8080/health
# {"status":"healthy","service":"rusty-hook"}

Logging

Uses structured logging with configurable levels:

# Set log level
export RUST_LOG="rusty_hook=debug"

# JSON structured logs
export RUST_LOG_FORMAT=json

Troubleshooting

Common Issues

Signature Verification Failed

  • Verify webhook secret matches exactly
  • Check webhook is configured for application/json content type
  • Ensure HTTPS is used if webhook requires it

Script Execution Failed

  • Verify script file exists and is executable (chmod +x)
  • Check script shebang line (#!/bin/bash)
  • Review script output in server logs

No Handler Configured

  • Verify WEBHOOK_EXEC_* environment variables are set
  • Check routing strategy matches your webhook URLs
  • Ensure executable files exist at specified paths

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.


Built with Linux, ❀️ and Coffee.

About

Simple webhook server for executing a single script or binary

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages