This project is an AWS Lambda function that processes GitHub webhook events for comprehensive repository monitoring and automation. It validates incoming event data and triggers appropriate actions based on the event type, supporting all major GitHub webhook events with secure signature validation.
webhook
├── src
│ ├── handler.ts # Entry point for the AWS Lambda function
│ ├── handler.test.ts # Comprehensive test suite for all webhook events
│ ├── types
│ │ └── github.ts # TypeScript interfaces for GitHub webhook events
│ └── utils
│ ├── health.ts # Health check fun tion for the webhook
├── logging.ts # Advanced logging utilities with structured event data
│ ├── validator.ts # Utility functions for validating webhook data
│ └── signature.ts # Webhook signature verification utilities
├── package.json # npm configuration file
├── tsconfig.json # TypeScript configuration file
├── serverless.yml # Serverless Framework configuration file
├── .env.example # Environment variable template
└── README.md # Project documentation
This handler supports all major GitHub webhook events, organized by category:
ping- Webhook ping event for testing connectivityrepository- Repository created, deleted, archived, etc.push- Code pushed to repositorycreate- Branch or tag createddelete- Branch or tag deletedfork- Repository forkedstar- Repository starred/unstarredwatch- Repository watched/unwatchedpublic- Repository made public
pull_request- Pull request opened, closed, merged, etc.pull_request_review- Pull request review submitted, edited, dismissedpull_request_review_comment- Comments on pull request reviews
issues- Issue opened, closed, edited, labeled, etc.issue_comment- Comments on issues and pull requests
commit_comment- Comments on commitsstatus- Commit status updates from CI/CD systemsgollum- Wiki page updates
workflow_run- GitHub Actions workflow runsworkflow_job- Individual workflow job statuscheck_suite- Check suite created, completed, etc.check_run- Individual check run status
release- Release published, edited, deletedpackage- GitHub Packages published, updated
organization- Organization settings changedteam- Team created, deleted, modifiedmember- Organization member added, removed
deployment- Deployment createddeployment_status- Deployment status updated
discussion- Repository discussion created, edited, etc.discussion_comment- Comments on discussions
milestone- Milestone creation, editing, deletionlabel- Repository label managementproject- Classic project board eventsproject_card- Project card movementsproject_column- Project column management
dependabot_alert- Dependabot vulnerability alertssecurity_advisory- Security advisory publicationscode_scanning_alert- Code scanning security alertssecret_scanning_alert- Secret scanning alerts
audit_log_streaming- Organization audit logsbranch_protection_rule- Branch protection rule changesrepository_dispatch- Custom repository dispatch eventsrepository_vulnerability_alert- Repository vulnerability alertsmarketplace_purchase- GitHub Marketplace purchasesinstallation- GitHub App installationsinstallation_repositories- GitHub App repository access changes
- Node.js 20.x or later
- AWS CLI configured
- Serverless Framework installed globally
npm installCreate a .env file for local development:
# Copy the example file
cp .env.example .env
# Edit the file with your values
GITHUB_WEBHOOK_SECRET=your-github-secret-webhookGenerate a secure webhook secret:
# Use openssl to generate a secure random string
openssl rand -base64 32
# Or use Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"# Set environment variable for deployment
export GITHUB_WEBHOOK_SECRET="your-super-secret-webhook-key-here"This project reads the webhook secret from serverless.yml via:
GITHUB_WEBHOOK_SECRET: ${env:GITHUB_WEBHOOK_SECRET}That means you can rotate the secret manually by changing the environment value and redeploying.
# Deploy to AWS
npm run deploy
# Run comprehensive test suite
npm test
# Run tests with coverage
npm run test:coverage
# Test specific event types
npm test -- --testNamePattern="Pull Request"Use these steps any time you need to rotate a compromised or expired webhook secret.
- Generate a new secret.
openssl rand -base64 32- Update the webhook secret in GitHub.
- Repository(Simi): Settings -> Webhooks -> select webhook -> Edit -> Change secret
- Replace the Secret value and save.
- Update your deployment environment variable with the same new value.
export GITHUB_WEBHOOK_SECRET="paste-new-secret-here"- AWS(mmob-dev): Lambda -> Functions -> select webhook -> Environment variables -> GITHUB_WEBHOOK_SECRET
- Replace the Secret value and save.
- Redeploy Lambda.
npm run deployFor production profile/stage:
export GITHUB_WEBHOOK_SECRET="paste-new-secret-here"
npm run deploy:prod- Verify delivery.
- In GitHub Webhook "Recent Deliveries", confirm new deliveries return
200. - If deliveries fail signature checks, confirm GitHub secret and
GITHUB_WEBHOOK_SECRETmatch exactly.
-
Navigate to Repository Settings
- Go to your repository on GitHub
- Click on "Settings" tab
- Select "Webhooks" from the left sidebar
-
Add New Webhook
- Click "Add webhook"
- Payload URL: Your Lambda endpoint (from
serverless deployoutput) - Content type:
application/json - Secret: Enter your webhook secret (same as
GITHUB_WEBHOOK_SECRET) - SSL verification: ✅ Enable SSL verification
- Which events: Select individual events or "Send me everything"
-
Event Selection Examples
Repository events: repository, push, create, delete, fork, star, watch Pull Request events: pull_request, pull_request_review, pull_request_review_comment Issue events: issues, issue_comment Workflow events: workflow_run, workflow_job, check_suite, check_run
-
Navigate to Organization Settings
- Go to your organization on GitHub
- Click on "Settings" tab
- Select "Webhooks" from the left sidebar
-
Configure Organization-Wide Events
- Follow same setup as repository webhooks
- Additional events:
organization,team,member - Audit log streaming: Enable for
audit_log_streamingevents
{
"name": "GitHub Webhook Handler",
"url": "https://your-api-gateway-url.amazonaws.com/dev/webhook",
"content_type": "application/json",
"secret": "your-super-secret-webhook-key-here",
"insecure_ssl": false,
"events": ["push", "pull_request", "issues", "workflow_run"]
}- GitHub generates signature using your webhook secret
- Signature sent in header as
X-Hub-Signature-256 - Lambda validates signature using HMAC-SHA256
- Timing-safe comparison prevents timing attacks
- Request rejected if signature doesn't match
// Verify GitHub webhook signature
const verifyGitHubSignature = (
payload: string,
signature: string,
secret: string,
): boolean => {
try {
const expectedSignature = `sha256=${crypto
.createHmac("sha256", secret)
.update(payload, "utf8")
.digest("hex")}`;
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature),
);
} catch (error) {
return false;
}
};{
"statusCode": 200,
"body": {
"message": "Event type processed successfully",
"event_data": {
"repository": "my-org/test-repo",
"action": "opened",
"details": "..."
}
}
}Missing Signature:
{
"statusCode": 401,
"body": {
"message": "Missing signature header"
}
}Invalid Signature:
{
"statusCode": 401,
"body": {
"message": "Invalid signature"
}
}Unsupported Event:
{
"statusCode": 400,
"body": {
"message": "Unsupported GitHub event: event_name",
"supported_events": [
"ping",
"repository",
"push",
"pull_request",
"issues",
"..."
]
}
}Configuration Error:
{
"statusCode": 500,
"body": {
"message": "Webhook secret not configured"
}
}- Update handler.ts - Add new event case with signature validation
- Update types/github.ts - Add TypeScript interfaces
- Add comprehensive tests - Include signature validation tests
- Update README.md - Document the new event type
// Test pattern for all webhook events
const body = JSON.stringify(payload);
const signature = generateWebhookSignature(body, testSecret);
mockEvent.headers["X-GitHub-Event"] = "event_name";
mockEvent.headers["X-Hub-Signature-256"] = signature;
mockEvent.body = body;
await webhookHandler(mockEvent, mockContext, mockCallback);# Install dependencies
npm install
# Run tests with signature validation
npm test
# Run tests in watch mode
npm run test:watch
# Type checking
npm run type-check
# Build project
npm run build
# Local development with serverless-offline
serverless offline# Test signature generation
node -e "
const crypto = require('crypto');
const payload = JSON.stringify({test: 'data'});
const secret = 'your-secret';
const signature = 'sha256=' + crypto.createHmac('sha256', secret).update(payload).digest('hex');
console.log('Signature:', signature);
"// Signature validation happens before event processing
case "pull_request":
await processPullRequestEvent(payload as GitHubPullRequestPayload);
return {
statusCode: 200,
body: JSON.stringify({
message: `Pull request ${payload.action} event processed`,
pr_number: payload.pull_request.number,
title: payload.pull_request.title,
action: payload.action,
})
};// All events require valid signatures
case "push":
await processPushEvent(payload as GitHubPushPayload);
return {
statusCode: 200,
body: JSON.stringify({
message: "Push event processed",
ref: payload.ref,
commits_count: payload.commits.length,
repository: payload.repository.full_name,
})
};// Secure workflow event processing
case "workflow_run":
await processWorkflowRunEvent(payload as GitHubWorkflowRunPayload);
return {
statusCode: 200,
body: JSON.stringify({
message: `Workflow ${payload.action} event processed`,
workflow_name: payload.workflow_run.name,
conclusion: payload.workflow_run.conclusion,
action: payload.action,
})
};The handler automatically logs:
- Successful webhook processing with event details
- Signature validation failures with source IP
- Processing errors with full error context
- Performance metrics for each event type
INFO: Webhook signature validated successfully
INFO: Received GitHub webhook event: pull_request
INFO: Processing pull request opened event
INFO: Pull request #123 opened in my-org/test-repo
ERROR: Invalid webhook signature from IP: 192.168.1.1
ERROR: Missing X-Hub-Signature-256 header
ERROR: Webhook secret not configured
# CloudWatch Alarms
SignatureValidationFailures:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: GitHub-Webhook-Invalid-Signatures
MetricName: SignatureValidationFailures
Threshold: 5
ComparisonOperator: GreaterThanThreshold
EvaluationPeriods: 2
Period: 300-
Signature Validation Failures
- Verify webhook secret matches in GitHub and Lambda
- Check for trailing whitespace in secret
- Ensure content-type is
application/json
-
Missing Environment Variables
- Verify
GITHUB_WEBHOOK_SECRETis set - Check serverless.yml environment configuration
- Validate AWS parameter store/secrets manager setup
- Verify
-
Deployment Issues
- Ensure AWS credentials are configured
- Check IAM permissions for Lambda execution
- Verify API Gateway configuration
-
Testing Issues
- Use correct signature generation in tests
- Verify test secret matches handler expectations
- Check mock setup for all required headers
# Check environment variables
serverless info
# View Lambda logs
serverless logs -f webhookHandler
# Test health check endpoint
curl -v https://yyk1br4jof.execute-api.eu-west-2.amazonaws.com/dev/health
# Test specific webhook event
curl -X POST https://yyk1br4jof.execute-api.eu-west-2.amazonaws.com/dev/webhook \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: ping" \
-H "X-Hub-Signature-256: sha256=your-signature" \
-d '{"zen":"test"}'- Never commit webhook secrets to version control
- Test signature validation for all new event types
- Follow secure coding practices
- Review security implications of changes
🔒 Security Notice: This webhook handler implements GitHub's recommended security practices including HMAC-SHA256 signature validation and timing-safe comparison. It's designed for production use in enterprise environments with comprehensive error handling, logging, and monitoring capabilities.