Skip to content

balesco/github-webhooks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Laravel GitHub Webhooks Package

A comprehensive Laravel package for handling GitHub webhooks with database storage, signature validation, event management, and automated deployment capabilities.

Requirements

  • PHP ^8.2
  • Laravel ^11.0 or ^12.0

Installation

  1. Add the package to your local composer.json:
{
    "repositories": [
        {
            "type": "path",
            "url": "./packages/github-webhooks"
        }
    ],
    "require": {
        "laravel/github-webhooks": "*"
    }
}
  1. Install the package:
composer require laravel/github-webhooks
  1. Publish configuration and migrations:
php artisan vendor:publish --tag=github-webhooks-config
php artisan vendor:publish --tag=github-webhooks-migrations
  1. Run migrations:
php artisan migrate

Configuration

Environment Variables

Add these variables to your .env file:

# Secret for validating GitHub webhooks (optional but recommended)
GITHUB_WEBHOOK_SECRET=your-webhook-secret

# Route prefix (default: webhooks)
GITHUB_WEBHOOK_ROUTE_PREFIX=webhooks

# Store webhooks in database (default: true)
GITHUB_WEBHOOK_STORE=true

# Deployment Configuration
GITHUB_WEBHOOK_BRANCH=main
GITHUB_WEBHOOK_REPOSITORY_PATH=/path/to/your/project
GITHUB_WEBHOOK_RUN_COMPOSER=true
GITHUB_WEBHOOK_RUN_MIGRATIONS=true
GITHUB_WEBHOOK_RUN_NPM=false
GITHUB_WEBHOOK_RUN_CACHE_CLEAR=true
GITHUB_WEBHOOK_OPTIMIZE=true
GITHUB_WEBHOOK_CREATE_STORAGE_LINK=true
GITHUB_WEBHOOK_RESTART_QUEUE=false

Configuration File

The package configuration file (config/github-webhooks.php) provides extensive options:

return [
    // GitHub webhook secret for signature validation
    'secret' => env('GITHUB_WEBHOOK_SECRET'),

    // Route configuration
    'route_prefix' => env('GITHUB_WEBHOOK_ROUTE_PREFIX', 'webhooks'),
    'middleware' => [
        // Add middleware like 'throttle:60,1'
    ],

    // Storage configuration
    'store_webhooks' => env('GITHUB_WEBHOOK_STORE', true),

    // Handler configuration
    'handlers' => [
        'push' => [
            App\Webhooks\Handlers\PushHandler::class,
        ],
        'pull_request' => [
            App\Webhooks\Handlers\PullRequestHandler::class,
        ],
        '*' => [
            App\Webhooks\Handlers\LogAllEventsHandler::class,
        ],
    ],

    // Error handling
    'continue_on_handler_failure' => true,

    // Auto-deployment configuration
    'auto_update_branches' => ['main', 'master', 'develop'],
    'branch' => env('GITHUB_WEBHOOK_BRANCH', 'main'),
    'repository_path' => env('GITHUB_WEBHOOK_REPOSITORY_PATH', base_path()),

    'deployment' => [
        'run_composer' => env('GITHUB_WEBHOOK_RUN_COMPOSER', true),
        'run_migrations' => env('GITHUB_WEBHOOK_RUN_MIGRATIONS', true),
        'run_npm' => env('GITHUB_WEBHOOK_RUN_NPM', false),
        'cache_clear' => env('GITHUB_WEBHOOK_RUN_CACHE_CLEAR', true),
        'optimize' => env('GITHUB_WEBHOOK_OPTIMIZE', true),
        'create_storage_link' => env('GITHUB_WEBHOOK_CREATE_STORAGE_LINK', true),
        'restart_queue' => env('GITHUB_WEBHOOK_RESTART_QUEUE', false),
    ]
];

GitHub Configuration

  1. Go to your GitHub repository settings
  2. Click "Webhooks" in the left menu
  3. Click "Add webhook"
  4. Configure:
    • Payload URL: https://your-domain.com/webhooks/github
    • Content type: application/json
    • Secret: Your secret (same as GITHUB_WEBHOOK_SECRET)
    • Events: Select the events you want to receive

Features

✅ Core Features

  • Webhook Reception: Secure endpoint for GitHub webhooks
  • Signature Validation: HMAC-SHA256 signature verification
  • Database Storage: Store webhook data for audit and replay
  • Event Handling: Flexible handler system for different events
  • Error Handling: Robust error handling with optional failure tolerance

✅ Deployment Automation

  • Automated Git Pull: Automatic repository updates on push events
  • Composer Management: Automatic dependency installation
  • NPM Support: Node.js dependency and build management
  • Database Migrations: Automatic migration execution
  • Cache Management: Cache clearing and optimization
  • Queue Management: Worker restart capability
  • Storage Links: Automatic symbolic link creation

✅ Management Commands

  • Webhook Management: List, filter, and reprocess webhooks
  • Repository Operations: Clone and update repositories
  • Secret Generation: Secure webhook secret generation
  • Configuration Validation: Validate webhook setup

Usage

Custom Handlers

Create handlers to process GitHub events:

<?php

namespace App\Webhooks\Handlers;

use Illuminate\Http\Request;
use Laravel\GitHubWebhooks\Contracts\WebhookHandler;

class DeploymentHandler implements WebhookHandler
{
    public function handle(string $event, array $payload, Request $request): mixed
    {
        if ($event === 'push') {
            $branch = str_replace('refs/heads/', '', $payload['ref'] ?? '');
            
            if ($branch === 'main') {
                // Trigger deployment
                $this->triggerDeployment($payload);
            }
        }

        return ['deployed' => true];
    }

    private function triggerDeployment(array $payload): void
    {
        // Your deployment logic
    }
}

Registering Handlers

In config/github-webhooks.php:

'handlers' => [
    'push' => [
        App\Webhooks\Handlers\DeploymentHandler::class,
    ],
    'pull_request' => [
        App\Webhooks\Handlers\PullRequestHandler::class,
    ],
    // Handler for all events
    '*' => [
        App\Webhooks\Handlers\LogAllEventsHandler::class,
    ],
],

Programmatic Usage

use Laravel\GitHubWebhooks\GitHubWebhooks;

// Register a handler on the fly
GitHubWebhooks::on('push', function ($event, $payload, $request) {
    // Process push event
    return ['status' => 'processed'];
});

// Register handler for multiple events
GitHubWebhooks::on(['push', 'pull_request'], new MyCustomHandler());

Deployment Service

The package includes a comprehensive deployment service for automated deployments:

use Laravel\GitHubWebhooks\Service\DeploymentService;

// In your webhook handler
public function handle(string $event, array $payload, Request $request): mixed
{
    if ($event === 'push') {
        $branch = str_replace('refs/heads/', '', $payload['ref'] ?? '');
        
        if (in_array($branch, config('github-webhooks.auto_update_branches', ['main']))) {
            $deploymentService = new DeploymentService();
            $result = $deploymentService->deploy($payload);
            
            return $result;
        }
    }
    
    return ['status' => 'skipped'];
}

The deployment service automatically handles:

  • Git Pull: Updates repository from the specified branch
  • Composer Install: Installs PHP dependencies with optimization
  • NPM Operations: Installs and builds frontend assets
  • Database Migrations: Runs pending migrations safely
  • Cache Management: Clears and rebuilds application cache
  • Optimization: Caches routes, config, and views for production
  • Storage Links: Creates symbolic links for public storage
  • Queue Restart: Restarts queue workers to load new code

Each step is configurable via the deployment configuration and logs detailed information for monitoring.

Event Listeners

use Laravel\GitHubWebhooks\Events\GitHubWebhookReceived;

// In your EventServiceProvider
protected $listen = [
    GitHubWebhookReceived::class => [
        App\Listeners\HandleGitHubWebhook::class,
    ],
];
<?php

namespace App\Listeners;

use Laravel\GitHubWebhooks\Events\GitHubWebhookReceived;

class HandleGitHubWebhook
{
    public function handle(GitHubWebhookReceived $event): void
    {
        $eventType = $event->eventType;
        $payload = $event->payload;
        $deliveryId = $event->deliveryId;

        // Your custom logic
    }
}

Artisan Commands

The package provides several Artisan commands for managing GitHub webhooks:

Secret Management

# Generate a new secure webhook secret
php artisan github-webhooks:generate-secret

# Show the secret without writing to .env
php artisan github-webhooks:generate-secret --show

# Force overwrite existing secret
php artisan github-webhooks:generate-secret --force

# Generate secret with custom length
php artisan github-webhooks:generate-secret --length=64

Configuration Validation

# Validate complete configuration
php artisan github-webhooks:validate

# Test with specific URL
php artisan github-webhooks:validate --url=https://your-domain.com/webhooks/github

Webhook Management

# List all webhooks
php artisan github-webhooks:list

# Filter by event type
php artisan github-webhooks:list --event=push

# Show only unprocessed webhooks
php artisan github-webhooks:list --unprocessed

# Show only processed webhooks
php artisan github-webhooks:list --processed

# Limit number of results
php artisan github-webhooks:list --limit=5

# Reprocess specific webhook
php artisan github-webhooks:reprocess {webhook_id}

Repository Management

# List all local repositories
php artisan github-webhooks:list-repos

# Update repository from GitHub
php artisan github-webhooks:update-repo owner/repo --branch=main --clone-url=https://github.com/owner/repo.git

# Force update (ignore local changes)
php artisan github-webhooks:update-repo owner/repo --force

# Use custom path
php artisan github-webhooks:list-repos --path=/custom/path

Data Model

The package stores webhooks in the git_hub_webhooks table with these fields:

  • id: Auto-incremented ID
  • event_type: GitHub event type (push, pull_request, etc.)
  • delivery_id: GitHub delivery ID for deduplication
  • payload: JSON webhook data from GitHub
  • headers: HTTP headers from the webhook request
  • processed_at: Processing timestamp (nullable)
  • created_at / updated_at: Laravel timestamps

Model Usage

use Laravel\GitHubWebhooks\Models\GitHubWebhook;

// Get all unprocessed push webhooks
$webhooks = GitHubWebhook::eventType('push')
    ->unprocessed()
    ->get();

// Get all processed webhooks
$processedWebhooks = GitHubWebhook::processed()->get();

// Mark a webhook as processed
$webhook->update(['processed_at' => now()]);

// Get webhooks by delivery ID
$webhook = GitHubWebhook::where('delivery_id', $deliveryId)->first();

Available Scopes

The GitHubWebhook model includes these query scopes:

  • unprocessed(): Webhooks that haven't been processed yet
  • processed(): Webhooks that have been processed
  • eventType($type): Filter by specific GitHub event type

Security

Signature Validation

The package automatically validates GitHub signatures if you configure a secret. This validation:

  • Uses HMAC-SHA256 algorithm as required by GitHub
  • Compares securely with hash_equals() to prevent timing attacks
  • Returns 401 error if signature is invalid
  • Logs security violations for monitoring

Exception Handling

The package provides specific exceptions for different error scenarios:

  • InvalidSignatureException: Thrown when webhook signature validation fails
  • DeploymentFailedException: Thrown when automated deployment encounters errors
  • WebhookHandlerException: Thrown when custom handlers fail
  • RepositoryException: Thrown when repository operations fail
  • SlackNotificationException: Thrown when notification services fail
use Laravel\GitHubWebhooks\Exceptions\InvalidSignatureException;
use Laravel\GitHubWebhooks\Exceptions\DeploymentFailedException;

try {
    // Your webhook handling code
} catch (InvalidSignatureException $e) {
    // Handle signature validation failure
    Log::warning('Invalid webhook signature', ['error' => $e->getMessage()]);
} catch (DeploymentFailedException $e) {
    // Handle deployment failure
    Log::error('Deployment failed', ['error' => $e->getMessage()]);
}

Recommended Middleware

Add middleware in configuration:

'middleware' => [
    'throttle:60,1', // Rate limiting
    'api',           // API middleware
],

Supported GitHub Events

The package can handle all GitHub events, including:

  • push: Commits pushed
  • pull_request: Pull requests (opened, closed, synchronized, etc.)
  • issues: Issues (opened, closed, labeled, etc.)
  • release: Releases
  • deployment: Deployments
  • workflow_run: GitHub Actions runs
  • And many more...

Troubleshooting

Debug Mode

Enable debug logging by setting the log level to debug in your webhook handlers:

use Illuminate\Support\Facades\Log;

public function handle(string $event, array $payload, Request $request): mixed
{
    Log::debug('Webhook received', [
        'event' => $event,
        'delivery_id' => $request->header('X-GitHub-Delivery'),
        'payload_size' => strlen(json_encode($payload))
    ]);
    
    // Your handling logic
}

Common Issues

Webhook Not Received

  1. Check URL accessibility: Ensure your webhook URL is publicly accessible
  2. Verify routing: Check that the route is properly registered
  3. Review middleware: Ensure middleware doesn't block the requests
  4. Check GitHub delivery: Review the "Recent Deliveries" tab in GitHub webhook settings

Signature Validation Fails

  1. Secret mismatch: Verify GITHUB_WEBHOOK_SECRET matches GitHub configuration
  2. Encoding issues: Ensure the secret doesn't contain special characters that might be encoded differently
  3. Environment loading: Verify the .env file is properly loaded

Deployment Failures

  1. Permission issues: Ensure the web server has proper file permissions
  2. Git access: Verify the server can access the Git repository
  3. Dependencies: Check that required tools (git, composer, npm) are installed
  4. Path configuration: Verify GITHUB_WEBHOOK_REPOSITORY_PATH is correct

Check Logs

Monitor webhook processing through Laravel logs:

# Follow real-time logs
tail -f storage/logs/laravel.log

# Search for webhook-related entries
grep -i "webhook" storage/logs/laravel.log

# Search for deployment logs
grep -i "deployment" storage/logs/laravel.log

Test Webhooks Locally

Use ngrok for local development and testing:

# Install ngrok
brew install ngrok  # macOS
# or download from https://ngrok.com

# Expose local server
ngrok http 8000

# Use the generated URL in GitHub webhook configuration
# Example: https://abc123.ngrok.io/webhooks/github

Validate Configuration

Use the built-in validation command to check your setup:

php artisan github-webhooks:validate

This command checks:

  • Configuration file validity
  • Environment variables
  • Route registration
  • Handler class existence
  • Database connectivity

Testing Webhook Processing

You can manually test webhook processing using the reprocess command:

# List recent webhooks
php artisan github-webhooks:list --limit=5

# Reprocess a specific webhook
php artisan github-webhooks:reprocess {webhook_id}

Contributing

This package is designed to be extensible and welcomes contributions. You can:

Extend Functionality

  • Create custom handlers: Implement the WebhookHandler interface for specialized processing
  • Extend the GitHubWebhook model: Add custom attributes and relationships
  • Add custom middleware: Implement additional security or processing layers
  • Custom deployment steps: Extend the DeploymentService for specific needs

Development Setup

  1. Clone the repository
  2. Install dependencies: composer install
  3. Run tests: vendor/bin/phpunit
  4. Follow PSR-12 coding standards

Testing

The package includes comprehensive tests. Run them with:

vendor/bin/phpunit

Package Information

  • Name: laravel/github-webhooks
  • Version: 1.0.0
  • Author: Balesco ([email protected])
  • License: MIT
  • Requirements: PHP ^8.2, Laravel ^11.0|^12.0

License

This package is open-sourced software licensed under the MIT license.

Support

For issues, feature requests, or questions:

  1. Check the troubleshooting section above
  2. Review existing GitHub issues
  3. Create a new issue with detailed information
  4. Include log outputs and configuration when reporting bugs

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors