Skip to main content

Configuration

GitHub Webhook Server uses a flexible YAML-based configuration system with support for global settings, repository-specific overrides, and environment variables. Configuration changes take effect immediately without server restart.

Configuration Files

Global Configuration

The main configuration file is config.yaml in your data directory (default: /home/podman/data/config.yaml).
config.yaml
# yaml-language-server: $schema=https://raw.githubusercontent.com/myk-org/github-webhook-server/refs/heads/main/webhook_server/config/schema.yaml

github-app-id: 123456
webhook-ip: https://your-domain.com/webhook_server
github-tokens:
  - ghp_your_github_token_here

repositories:
  my-repository:
    name: my-org/my-repository
    protected-branches:
      main: []
The yaml-language-server comment enables IDE autocompletion and validation. Keep it at the top of your config file.

Repository-Level Overrides

Create .github-webhook-server.yaml in your repository root to override or extend global configuration:
.github-webhook-server.yaml
minimum-lgtm: 2
can-be-merged-required-labels:
  - "ready-to-merge"
pre-commit: true
conventional-title: "feat,fix,docs"

labels:
  enabled-labels:
    - verified
    - hold
    - wip
  colors:
    hold: crimson
    verified: limegreen
Benefits:
  • Version-controlled configuration alongside your code
  • Per-project customization without modifying global config
  • Zero-downtime updates to repository settings
  • Repository maintainers can manage their own automation

Environment Variables

Environment variables control server behavior and override config file settings.

Core Settings

VariableDescriptionDefaultRequired
WEBHOOK_SERVER_DATA_DIRDirectory containing config.yaml/home/podman/dataYes
WEBHOOK_SERVER_IP_BINDIP address to bind server0.0.0.0No
WEBHOOK_SERVER_PORTPort to bind server5000No
MAX_WORKERSMaximum number of workers10No

Security Settings

Always configure WEBHOOK_SECRET and VERIFY_GITHUB_IPS for production deployments.
VariableDescriptionDefaultRequired
WEBHOOK_SECRETGitHub webhook secret for HMAC verification-Recommended
VERIFY_GITHUB_IPSVerify requests from GitHub IP rangesfalseNo
VERIFY_CLOUDFLARE_IPSVerify requests from Cloudflare IPsfalseNo

Feature Toggles

VariableDescriptionDefaultRequired
ENABLE_LOG_SERVEREnable log viewer web interfacefalseNo
ENABLE_MCP_SERVEREnable MCP server for AI agentsfalseNo

AI CLI API Keys

For AI-powered features like test-oracle and conventional title suggestions:
VariableDescriptionProvider
ANTHROPIC_API_KEYAPI key for Claude Code CLIClaude
GEMINI_API_KEYAPI key for Gemini CLIGemini
CURSOR_API_KEYAPI key for Cursor Agent CLICursor

Minimal Configuration

The smallest working configuration requires only three fields:
config.yaml
github-app-id: 123456
webhook-ip: https://your-domain.com/webhook_server
github-tokens:
  - ghp_your_token_here

repositories:
  my-repository:
    name: my-org/my-repository
    protected-branches:
      main: []
This is sufficient for:
  • Basic webhook processing
  • Pull request labeling
  • Branch protection

Advanced Configuration

Server Configuration

config.yaml
# Logging
log-level: INFO  # DEBUG, INFO, WARNING, ERROR
log-file: webhook-server.log
mcp-log-file: mcp_server.log
logs-server-log-file: logs_server.log
mask-sensitive-data: true  # Mask tokens in logs

# Server settings
ip-bind: "0.0.0.0"
port: 5000
max-workers: 20

# Security
webhook-secret: "your-webhook-secret"  # pragma: allowlist secret
verify-github-ips: true
verify-cloudflare-ips: true
disable-ssl-warnings: false

Global Defaults

config.yaml
# Status checks required for all repositories
default-status-checks:
  - "WIP"
  - "can-be-merged"
  - "build"

# Users whose PRs are auto-verified and merged
auto-verified-and-merged-users:
  - "renovate[bot]"
  - "dependabot[bot]"

# Auto-verify cherry-picked PRs
auto-verify-cherry-picked-prs: true

# Create tracking issues for new PRs
create-issue-for-new-pr: true

# Assign cherry-pick PRs to original author
cherry-pick-assign-to-pr-author: true

Docker Registry Configuration

For pulling private base images:
config.yaml
docker:
  username: your-docker-username
  password: your-docker-password

Branch Protection

Global branch protection rules applied to all repositories:
config.yaml
branch-protection:
  strict: true
  require_code_owner_reviews: true
  dismiss_stale_reviews: false
  required_approving_review_count: 1
  required_linear_history: true
  required_conversation_resolution: true

Repository Configuration

Basic Repository Setup

config.yaml
repositories:
  my-project:
    name: my-org/my-project
    log-level: DEBUG  # Override global log level
    slack-webhook-url: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
    
    # Enable features
    verified-job: true
    pre-commit: true
    
    # Protected branches
    protected-branches:
      main: []
      develop:
        include-runs:
          - "Required CI Check"
        exclude-runs:
          - "Optional Check"

Pull Request Settings

config.yaml
repositories:
  my-project:
    name: my-org/my-project
    
    # Review requirements
    minimum-lgtm: 2  # Require 2 approvals
    
    # Required labels for merge
    can-be-merged-required-labels:
      - "approved"
      - "tests-passed"
    
    # Conventional Commits validation
    conventional-title: "feat,fix,docs,refactor,test"
    
    # Auto-merge branches
    set-auto-merge-prs:
      - main
      - develop
    
    protected-branches:
      main: []
Use "*" for conventional-title to accept any type while enforcing format: type: description

CI/CD Configuration

config.yaml
repositories:
  my-project:
    name: my-org/my-project
    
    tox:
      main: all  # Run all tox environments for main branch PRs
      develop: unit,integration  # Specific envs for develop
      feature/*: quick  # Pattern matching for feature branches
    
    tox-python-version: "3.12"
    
    protected-branches:
      main: []
How it works:
  • Triggered on pull request creation and updates
  • Runs tox environments based on target branch
  • Results reported as GitHub check runs
config.yaml
repositories:
  my-project:
    name: my-org/my-project
    
    container:
      username: registry-user
      password: registry-password
      repository: quay.io/my-org/my-project
      tag: latest
      release: true  # Push on new releases
      
      # Build arguments
      build-args:
        - BUILD_VERSION=1.0.0
        - PYTHON_VERSION=3.12
      
      # Podman build arguments
      args:
        - --format docker
        - --no-cache
    
    protected-branches:
      main: []
Trigger with command:
/build-and-push-container
/build-and-push-container --build-arg VERSION=2.0
config.yaml
repositories:
  my-python-package:
    name: my-org/my-python-package
    
    pypi:
      token: pypi-AgEIcHlwaS5vcmc...
    
    protected-branches:
      main: []
How it works:
  • Automatically publishes to PyPI on new releases
  • Uses Poetry or setuptools for packaging
  • Version extracted from release tag

Label Configuration

Control which automation labels are applied to pull requests:
config.yaml
# Global label configuration
labels:
  enabled-labels:
    - verified
    - hold
    - wip
    - needs-rebase
    - has-conflicts
    - can-be-merged
    - size
    - branch
    - cherry-pick
    - automerge
  colors:
    hold: red
    verified: green
    wip: orange
    can-be-merged: limegreen

# Repository-specific (overrides global)
repositories:
  my-project:
    name: my-org/my-project
    labels:
      enabled-labels:
        - verified
        - size
        - can-be-merged
      colors:
        verified: lightgreen
    protected-branches:
      main: []
Available label categories:
CategoryLabelsDescription
verifiedverifiedManual verification status
holdholdBlock PR merging
wipwipWork in progress
needs-rebaseneeds-rebasePR needs rebasing
has-conflictshas-conflictsMerge conflicts
can-be-mergedcan-be-mergedMeets all requirements
sizesize/XS, size/S, etc.PR size labels
branchbranch/<name>Target branch
cherry-pickcherry-pick/<branch>Cherry-pick tracking
automergeautomergeAuto-merge enabled
Reviewed-by labels (approved-*, lgtm-*, changes-requested-*, commented-*) are always enabled and cannot be disabled.
Define custom size labels with your own thresholds and colors:
config.yaml
# Global PR size labels
pr-size-thresholds:
  Tiny:
    threshold: 10  # 0-9 lines changed
    color: lightgray
  Small:
    threshold: 50  # 10-49 lines changed
    color: green
  Medium:
    threshold: 150  # 50-149 lines changed
    color: orange
  Large:
    threshold: 300  # 150-299 lines changed
    color: red
  Massive:
    threshold: inf  # 300+ lines (unbounded)
    color: darkred

# Repository-specific (overrides global)
repositories:
  my-project:
    name: my-org/my-project
    pr-size-thresholds:
      Express:
        threshold: 25
        color: lightblue
      Standard:
        threshold: 100
        color: green
      Premium:
        threshold: 500
        color: orange
    protected-branches:
      main: []
Rules:
  • threshold: Positive integer or inf for unbounded
  • color: CSS3 color name (red, green, lightgray, etc.)
  • Size = additions + deletions
  • Use inf for largest category to catch all remaining PRs

AI Features

AI-powered test recommendations based on PR diff analysis:
config.yaml
# Global test-oracle configuration
test-oracle:
  server-url: "http://localhost:8000"
  ai-provider: "claude"  # claude | gemini | cursor
  ai-model: "claude-opus-4-6[1m]"
  test-patterns:
    - "tests/**/*.py"
  triggers:
    - approved  # Run when /approve command used
    # - pr-opened  # Run when PR opened
    # - pr-synchronized  # Run when commits pushed

# Repository-specific (overrides global)
repositories:
  my-project:
    name: my-org/my-project
    test-oracle:
      server-url: "http://localhost:8000"
      ai-provider: "gemini"
      ai-model: "gemini-pro"
      test-patterns:
        - "tests/**/*.py"
      triggers:
        - approved
    protected-branches:
      main: []
Trigger manually:
/test-oracle
See pr-test-oracle for server setup.
AI-powered PR title suggestions following Conventional Commits:
config.yaml
# Global AI features
ai-features:
  ai-provider: "claude"  # claude | gemini | cursor
  ai-model: "claude-opus-4-6[1m]"
  conventional-title: "true"  # "true" | "false" | "fix"

# Repository-specific (overrides global)
repositories:
  my-project:
    name: my-org/my-project
    ai-features:
      ai-provider: "claude"
      ai-model: "sonnet"
      conventional-title: "fix"  # Auto-update PR title
    protected-branches:
      main: []
Modes:
  • "true": Show AI suggestion in check run output when validation fails
  • "false": Disabled (default)
  • "fix": Automatically update PR title with validated AI suggestion
Requires AI CLI tools installed and API keys configured via environment variables.

Commands on Draft PRs

config.yaml
# Global setting: block all commands on draft PRs (default)
# allow-commands-on-draft-prs: []  # Allow all commands

# Allow specific commands globally
allow-commands-on-draft-prs:
  - build-and-push-container
  - retest

# Repository-specific (overrides global)
repositories:
  my-project:
    name: my-org/my-project
    allow-commands-on-draft-prs:
      - build-and-push-container
      - verified
    protected-branches:
      main: []
Behavior:
  • If not set: Commands blocked on draft PRs (default)
  • If empty array []: All commands allowed
  • If array with values: Only listed commands allowed

Configuration Validation

Schema Validation

Validate your configuration file before deploying:
# Validate configuration
uv run webhook_server/tests/test_schema_validator.py config.yaml

# Run schema tests
uv run pytest webhook_server/tests/test_config_schema.py -v

Real-time Validation

IDEs with YAML Language Server support provide real-time validation:
  1. Ensure the schema comment is at the top of your config:
    # yaml-language-server: $schema=https://raw.githubusercontent.com/myk-org/github-webhook-server/refs/heads/main/webhook_server/config/schema.yaml
    
  2. Install YAML extension in your IDE:
  3. Get autocompletion and validation as you type

Example Configurations

The examples/ directory contains comprehensive configuration examples:
FileDescription
config.yamlComplete configuration with all available options
docker-compose.yamlDocker Compose deployment configuration
.github-webhook-server.yamlRepository-specific configuration template

Next Steps

OWNERS Files

Configure OWNERS files for intelligent reviewer assignment

User Commands

Learn all available commands for PR management

Security

Configure security settings for production deployments

Monitoring

Set up monitoring and log analysis

Troubleshooting

Configuration Not Loading

# Check file exists
ls -la $WEBHOOK_SERVER_DATA_DIR/config.yaml

# Validate YAML syntax
python3 -c "import yaml; yaml.safe_load(open('config.yaml'))"

# Check server logs
podman logs github-webhook-server | grep -i config

Schema Validation Fails

# Run validation with verbose output
uv run webhook_server/tests/test_schema_validator.py config.yaml --verbose

# Check specific field
uv run pytest webhook_server/tests/test_config_schema.py::TestConfigSchema::test_valid_full_config_loads -v

Repository-Level Overrides Not Working

  1. Ensure .github-webhook-server.yaml is in repository root
  2. Check file permissions (must be readable)
  3. Validate YAML syntax
  4. Check server logs for parsing errors
  5. Verify repository name matches config
Configuration changes take effect immediately without server restart. The webhook server reloads configuration for each incoming webhook event.

Build docs developers (and LLMs) love