Purpose: Configure the GitHub repository webhook that feeds theDocumentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
github-webhook Edge Function for spec-tracking automation (auto-label from [CORE-##], optional project add, optional sync table).
Related: GITHUB_PROJECT_SPEC_TRACKING_PLAN.md (labels, project board, workflow).
1. Edge Function Endpoint
- URL:
https://<supabase-project-ref>.supabase.co/functions/v1/github-webhook - Method:
POSTonly;OPTIONSsupported for CORS. - Replace
<supabase-project-ref>with your Supabase project reference (Dashboard → Project Settings → General).
2. GitHub Repository Configuration
- In the GitHub repo: Settings → Webhooks → Add webhook.
- Payload URL: The Edge Function URL above.
- Content type:
application/json. - Secret: Generate a random string (e.g.
openssl rand -hex 32) and set it in both:- GitHub: Secret field.
- Supabase: Edge Function secrets →
GITHUB_WEBHOOK_SECRET= same value.
- SSL verification: Enable (default).
- Which events? Choose Let me select individual events, then enable:
- Issues
- Issue comments
- Pull requests (optional; for future “Fixes #N” handling)
- Save; GitHub will send a
pingevent. The function responds with200and{ "received": true, "event": "ping" }.
3. Supabase Secrets
Set in Supabase Dashboard → Edge Functions → github-webhook → Secrets (or via CLI):| Secret | Required | Description |
|---|---|---|
GITHUB_WEBHOOK_SECRET | Yes (recommended) | Same value as the webhook Secret in GitHub. If unset, signature verification is skipped (not recommended in production). |
GITHUB_TOKEN | No | GitHub PAT or app token with repo / issues:write (and project if adding issues to Projects). Used for auto-label and “add to project” when enabled in the function. |
4. Behavior Summary
- Verification: Request body is verified with
X-Hub-Signature-256using HMAC-SHA256 andGITHUB_WEBHOOK_SECRET. Invalid or missing signature (when secret is set) returns401. - Idempotency:
X-GitHub-Deliveryis stored inpf_github_webhook_events. Duplicate delivery IDs receive200and are not processed again. - Events:
ping→200immediately.issues→ Parsed foraction,issue,repository;[CORE-##]in title is parsed for optional auto-label/sync.issue_comment→ Logged; optional bot comment or notify can be added later.- Other events → Logged and acknowledged with
200.
5. Optional: Auto-Label and Add to Project
To have the function add labels and/or add issues to a GitHub Project:- Set
GITHUB_TOKENin Edge Function secrets (token withrepoand, if needed,projectscope). - In code, the handler already parses
[CORE-##]from the issue title; you can extendhandleIssuesto:- Ensure label
core:{CORE}exists (e.g. GitHub APIGET /repos/:owner/:repo/labels, create if missing). - Add the label to the issue (
POST /repos/:owner/:repo/issues/:number/labels). - If label
spec-trackingis present, add the issue to the project (Projects v2 API).
- Ensure label
6. Optional: Sync Table for Dashboards
To show “open spec issues” or “recent activity” inside the app:- Add a migration that creates
pf_github_issue_sync(e.g.organization_id,repo_owner,repo_name,issue_number,issue_url,title,state,spec_id,labels,updated_at,last_event_type) with RLS as needed. - In the
issueshandler, upsert a row keyed by(repo_owner, repo_name, issue_number)on eachissuesevent.
7. Testing
7.1 Unit tests (no deployment)
- Vitest (CI): From project root run:
Tests signature verification (valid / invalid / tampered) and
[CORE-##]parsing from issue titles. - Deno (edge function): With Deno installed, from project root run:
Or from
supabase/functions:deno test --allow-env --allow-read github-webhook/index.test.tsThese cover the same logic as implemented in the Edge Function.
7.2 Local endpoint (Supabase Functions serve)
- Start local Supabase (if you need the DB for idempotency):
npx supabase startthennpx supabase db reset. - Serve the function (no JWT for webhooks):
Functions are available at http://localhost:54321/functions/v1/github-webhook (see Supabase Edge Functions local development).
- Optional: set
GITHUB_WEBHOOK_SECRETvia env file so signature verification is tested:Use the same secret value you will configure in GitHub (or a test secret for local only).
7.3 Manual curl (ping and issues)
Without a secret (verification skipped):X-Hub-Signature-256 (e.g. echo -n '<body>' | openssl dgst -sha256 -hmac '<secret>' -binary | xxd -p -c 256 then prefix with sha256=).
7.4 Forward real webhooks with GitHub CLI (development only)
To receive real GitHub webhook deliveries (issues, issue_comment, ping) on your local endpoint while you develop:- Install the webhook extension: Using the GitHub CLI to forward webhooks
- Start your local handler: Run
npx supabase functions serve github-webhook --no-verify-jwtso the function is listening athttp://localhost:54321/functions/v1/github-webhook. - Forward repo webhooks to local: In a second terminal (replace
OWNER/REPOwith your repo, e.g.myorg/northsight-health-OS):Leave this running; it forwards the selected events to your local URL. Only one forward can be active per repository at a time. - Trigger events: Create or edit an issue, or add a comment, in the repo; you should see the request in the terminal where
supabase functions serveis running.
GITHUB_WEBHOOK_SECRET in the environment used by supabase functions serve to the same value as the webhook secret configured for that repo in GitHub.
8. Troubleshooting
- 401 Signature required / Invalid signature: Ensure
GITHUB_WEBHOOK_SECRETmatches the webhook secret in GitHub and that the raw body is used for verification (no parsing before verification). - Duplicate delivery: Expected when GitHub retries; the function returns
200and skips processing. - Logs: Use Supabase Edge Function logs (or
createLoggeroutput) to inspectevent,action, andissue_number; never log secrets or full request bodies. - gh webhook forward: If you get “Hook already exists”, only one forward can be active per repo; stop another client’s forward or use a different repo. For org webhooks, use
--org=ORGand ensuregh auth refresh --scopes admin:org_hookif needed.