WebHooker/docs/guide/configuration.md

5.3 KiB

Configuration

Secrets

WebHooker requires several secrets to function. For local development, store them in .dev.vars. For production, use Cloudflare Worker Secrets.

Required Secrets

Variable Description
GITHUB_WEBHOOK_SECRET Webhook secret from your GitHub App settings
GITHUB_APP_ID Numeric ID of your GitHub App
GITHUB_PRIVATE_KEY App private key (PEM format, with \n escapes)
GITHUB_CLIENT_ID OAuth client ID from App settings
GITHUB_CLIENT_SECRET OAuth client secret from App settings
DISCORD_TOKEN Discord bot token

Optional Secrets

Variable Description Default
BASE_URL Public URL for OAuth callbacks http://localhost:8787
ADMIN_USER_IDS Comma-separated GitHub user IDs (or logins) allowed to access the Web UI Disabled
DISCORD_GATEWAY_ENABLED Set to true to connect the Discord Gateway (bot online status); messaging works without it via REST false

Web UI

WebHooker ships with a built-in config console at /admin for managing routes in the browser. It is protected by GitHub OAuth plus an admin whitelist.

Setup

  1. Configure ADMIN_USER_IDS with the GitHub user IDs allowed to manage routes. Logins are also accepted, e.g. ADMIN_USER_IDS=12345,RhenCloud. If unset, the console is disabled.
  2. Open /admin and sign in with GitHub.
  3. Only users in the whitelist receive a session cookie; everyone else gets 403.

Endpoints

Endpoint Description
GET /admin Config console UI
GET /admin/login Start GitHub OAuth sign-in
GET /admin/logout Destroy session
GET /admin/api/routes List routes (admin only)
PUT /admin/api/routes Replace routes (admin only)

The console lets you add, edit, delete, and toggle routes. Saved routes are written to KV config:routes immediately and the config cache is invalidated so the webhook pipeline picks them up on the next run.

Routes

Routes define which events get forwarded to which Discord channels. They are stored in Cloudflare KV under the key config:routes as a JSON array.

There are no default routes — each route must define its own target. If no routes are configured, no events are forwarded.

Route Schema

{
  "id": "unique-route-id",
  "name": "Human-readable name",
  "enabled": true,
  "filters": [
    { "type": "event", "match": "push" },
    { "type": "repo", "match": "org/repo", "exclude": false }
  ],
  "target": {
    "channelId": "REQUIRED_CHANNEL_ID",
    "threadId": "OPTIONAL_THREAD_ID"
  }
}

target.channelId is required and used as-is; there is no fallback to a default channel.

Custom Route Example

[
  {
    "id": "backend-prs",
    "name": "Backend PRs",
    "enabled": true,
    "filters": [
      { "type": "repo", "match": "myorg/backend" },
      { "type": "event", "match": "pull_request" },
      { "type": "actor", "match": "[bot]", "exclude": true }
    ],
    "target": {
      "channelId": "1234567890",
      "threadId": "9876543210"
    }
  }
]

Filter Types

Type Matches Example
event GitHub event name push, pull_request, issues
repo Repository full name org/repo
actor Sender login username, [bot]
action Event action opened, closed, published
branch Branch name main, feature/*
keyword Text in payload body deploy, /fix\s+\d+/ (regex)

Filter Behavior

  • All filters in a route must match for the route to trigger (AND logic)
  • Set "exclude": true on any filter to invert it (NOT logic)
  • keyword filter supports regex patterns — falls back to substring match if regex is invalid
  • branch filter works for push, pull_request, create/delete, workflow_run, and code_scanning_alert events

Match Values

Filters accept either a single string or an array of strings:

{ "type": "event", "match": "push" }
{ "type": "event", "match": ["push", "pull_request"] }

KV Storage Layout

Key Pattern Value TTL
config:routes JSON array of routes Permanent
session:{id} Admin session { userId, login } 7 days
token:{userId} { accessToken, expiresAt } Until expiry
state:{hex} { userId, createdAt } 600 seconds