Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

github-webhook-filter

A Cloudflare Worker that sits between GitHub and another webhook consumer. It accepts GitHub release webhook deliveries, keeps only the actions you list, and replays those deliveries to an upstream URL unchanged — same body bytes, same GitHub headers — so the receiver cannot tell the difference from a direct delivery.

Everything else (other events, other release actions) is acknowledged with a 200 and dropped.

How a delivery is handled

Condition Result
Not a POST 405
Missing/invalid X-Hub-Signature-256 401, nothing forwarded
X-GitHub-Event: ping 200, nothing forwarded
Event is not release 200, nothing forwarded
release action not in INCLUDED_ACTIONS 200, nothing forwarded
release action in INCLUDED_ACTIONS forwarded upstream, 200
Upstream errored or timed out (10s) 502, so GitHub can redeliver

Every delivery is signature-verified with GITHUB_WEBHOOK_SECRET before it is parsed. If any setting is missing the worker fails closed with a 500.

Configuration

All settings live in .env (gitignored). See .env.sample:

Setting Stored as Purpose
INCLUDED_ACTIONS plain var Comma-separated release actions to forward, e.g. published,released. Matching is case-insensitive.
UPSTREAM_WEBHOOK_URL secret Where included deliveries are replayed.
GITHUB_WEBHOOK_SECRET secret Shared secret used to verify GitHub's HMAC signature.

GitHub's release actions are: published, unpublished, created, edited, deleted, prereleased, released.

Deploy

1. Install prerequisites — Node 18+ and a Cloudflare account.

npm install
npx wrangler login          # one-time browser auth

For CI instead of wrangler login, set CLOUDFLARE_API_TOKEN (needs the Edit Cloudflare Workers template) and CLOUDFLARE_ACCOUNT_ID in the environment.

2. Fill in your settings

cp .env.sample .env
openssl rand -hex 32        # use this for GITHUB_WEBHOOK_SECRET
$EDITOR .env

3. Deploy

npm run deploy              # add --dry-run to preview without touching Cloudflare

scripts/deploy.sh reads .env, publishes the worker with wrangler deploy --var INCLUDED_ACTIONS:…, then pushes UPSTREAM_WEBHOOK_URL and GITHUB_WEBHOOK_SECRET with wrangler secret put. The secrets are stored encrypted in Cloudflare and are write-only in the dashboard afterwards. .env is never uploaded.

Wrangler prints the deployed URL, e.g. https://github-webhook-filter.<your-subdomain>.workers.dev.

The first deploy of a brand-new worker publishes before the secrets are attached, so for a few seconds it answers 500 (fail-closed). Re-running npm run deploy later updates everything in place.

4. Point GitHub at it — in the repo (or org): Settings → Webhooks → Add webhook

  • Payload URL: the worker URL from step 3
  • Content type: application/json
  • Secret: the same GITHUB_WEBHOOK_SECRET value from .env
  • Events: Let me select individual events → check Releases only

GitHub immediately sends a ping; a green checkmark in Recent Deliveries means the signature check passed.

5. Verify — tail the live logs and cut a release:

npx wrangler tail

Each delivery logs one line, e.g. delivery=<uuid> forwarded: action=published upstreamStatus=200 or delivery=<uuid> skipped: release action=edited is not included.

Changing settings later

Edit .env and re-run npm run deploy.

Local development

wrangler dev reads secrets from .dev.vars, which uses the same format as .env:

cp .env .dev.vars
npm run dev

Send yourself a signed test delivery:

BODY='{"action":"published","release":{"tag_name":"v1.0.0"}}'
SECRET=$(grep '^GITHUB_WEBHOOK_SECRET=' .env | cut -d= -f2-)
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

curl -sS -i http://localhost:8787/ \
  -H 'content-type: application/json' \
  -H 'x-github-event: release' \
  -H 'x-github-delivery: local-test' \
  -H "x-hub-signature-256: sha256=$SIG" \
  -d "$BODY"

Tests

npm test          # vitest: filtering, signature checks, forwarding, failure modes
npm run typecheck

Layout

src/index.ts        worker: verify -> filter -> forward
scripts/deploy.sh   reads .env, deploys, pushes vars + secrets to Cloudflare
test/worker.test.ts unit tests
wrangler.toml       worker name, entrypoint, compatibility date
.env.sample         documented template for .env

About

Filter Github webhooks

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages