All docs

GitHub integration

GitHub integration

Migration: 0011_webhook_events.sql Verifier: packages/core/src/verification/github.ts (pure, test-injected) Webhook receiver: apps/mcp/src/routes/webhooks-github.ts

Endpoints

The receiver verifies the signature against GITHUB_APP_WEBHOOK_SECRET, validates that X-GitHub-Delivery and X-GitHub-Event are present, then writes the raw payload into webhook_events with a unique index on (provider, delivery_id). Replays return 200 { status: 'replay' }.

Verification contract

The verifier consumes the snapshot stored on each task:

{ "v": 1, "kind": "github_pr", "required_checks": ["ci/build", "ci/test"] }

verifyGitHubPr({ owner, repo, prNumber, requiredChecks, expectedFiles? }) returns one of passed | failed | pending:

The function is pure — it consumes a GitHubClient interface (getPullRequest, getCheckRuns, getChangedFiles) so tests don't touch the network. The runtime adapter (Octokit-backed) lands when the verification engine in task 32 wires it up.

Idempotence

  • webhook_events.delivery_id is UNIQUE (provider, delivery_id). Replays

short-circuit via ON CONFLICT DO NOTHING.

  • A BullMQ webhooks-in worker is the natural place to drive the

verification pipeline (task 32 owns that handler).

Body-parser bypass

The global express.json() middleware would consume the request stream before our HMAC could read it. apps/mcp/src/index.ts skips the JSON parser when req.path === '/webhooks/github' and the handler reads the raw bytes itself.