Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Purpose: Configure the GitHub repository webhook that feeds the 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: POST only; OPTIONS supported for CORS.
  • Replace <supabase-project-ref> with your Supabase project reference (Dashboard → Project Settings → General).

2. GitHub Repository Configuration

  1. In the GitHub repo: Settings → Webhooks → Add webhook.
  2. Payload URL: The Edge Function URL above.
  3. Content type: application/json.
  4. Secret: Generate a random string (e.g. openssl rand -hex 32) and set it in both:
    • GitHub: Secret field.
    • Supabase: Edge Function secretsGITHUB_WEBHOOK_SECRET = same value.
  5. SSL verification: Enable (default).
  6. Which events? Choose Let me select individual events, then enable:
    • Issues
    • Issue comments
    • Pull requests (optional; for future “Fixes #N” handling)
  7. Save; GitHub will send a ping event. The function responds with 200 and { "received": true, "event": "ping" }.

3. Supabase Secrets

Set in Supabase Dashboard → Edge Functions → github-webhook → Secrets (or via CLI):
SecretRequiredDescription
GITHUB_WEBHOOK_SECRETYes (recommended)Same value as the webhook Secret in GitHub. If unset, signature verification is skipped (not recommended in production).
GITHUB_TOKENNoGitHub 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-256 using HMAC-SHA256 and GITHUB_WEBHOOK_SECRET. Invalid or missing signature (when secret is set) returns 401.
  • Idempotency: X-GitHub-Delivery is stored in pf_github_webhook_events. Duplicate delivery IDs receive 200 and are not processed again.
  • Events:
    • ping200 immediately.
    • issues → Parsed for action, 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:
  1. Set GITHUB_TOKEN in Edge Function secrets (token with repo and, if needed, project scope).
  2. In code, the handler already parses [CORE-##] from the issue title; you can extend handleIssues to:
    • Ensure label core:{CORE} exists (e.g. GitHub API GET /repos/:owner/:repo/labels, create if missing).
    • Add the label to the issue (POST /repos/:owner/:repo/issues/:number/labels).
    • If label spec-tracking is present, add the issue to the project (Projects v2 API).
See GitHub Webhook events and payloads and GitHub REST API for endpoints.

6. Optional: Sync Table for Dashboards

To show “open spec issues” or “recent activity” inside the app:
  1. 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.
  2. In the issues handler, upsert a row keyed by (repo_owner, repo_name, issue_number) on each issues event.
This is optional and can be implemented in a follow-up.

7. Testing

7.1 Unit tests (no deployment)

  • Vitest (CI): From project root run:
    npx vitest run tests/unit/platform/monitoring/github-webhook.test.ts
    
    Tests signature verification (valid / invalid / tampered) and [CORE-##] parsing from issue titles.
  • Deno (edge function): With Deno installed, from project root run:
    npm run test:functions
    
    Or from supabase/functions: deno test --allow-env --allow-read github-webhook/index.test.ts These cover the same logic as implemented in the Edge Function.

7.2 Local endpoint (Supabase Functions serve)

  1. Start local Supabase (if you need the DB for idempotency): npx supabase start then npx supabase db reset.
  2. Serve the function (no JWT for webhooks):
    npx supabase functions serve github-webhook --no-verify-jwt
    
    Functions are available at http://localhost:54321/functions/v1/github-webhook (see Supabase Edge Functions local development).
  3. Optional: set GITHUB_WEBHOOK_SECRET via env file so signature verification is tested:
    npx supabase functions serve github-webhook --no-verify-jwt --env-file .env.local
    
    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):
# Ping (expect 200, {"received":true,"event":"ping"})
curl -s -X POST http://localhost:54321/functions/v1/github-webhook \
  -H "Content-Type: application/json" \
  -H "X-GitHub-Event: ping" \
  -H "X-GitHub-Delivery: test-delivery-$(date +%s)" \
  -d '{"zen":"test"}'

# Issues opened (expect 200, {"received":true,"event":"issues"})
curl -s -X POST http://localhost:54321/functions/v1/github-webhook \
  -H "Content-Type: application/json" \
  -H "X-GitHub-Event: issues" \
  -H "X-GitHub-Delivery: test-issues-$(date +%s)" \
  -d '{"action":"opened","issue":{"number":1,"title":"[HR-05] Time & Attendance","state":"open","html_url":"https://github.com/org/repo/issues/1","body":null,"labels":[],"assignees":[]},"repository":{"id":1,"full_name":"org/repo","name":"repo","owner":{"login":"org"}}}'
With a secret, compute 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:
  1. Install the webhook extension: Using the GitHub CLI to forward webhooks
    gh extension install cli/gh-webhook
    
  2. Start your local handler: Run npx supabase functions serve github-webhook --no-verify-jwt so the function is listening at http://localhost:54321/functions/v1/github-webhook.
  3. Forward repo webhooks to local: In a second terminal (replace OWNER/REPO with your repo, e.g. myorg/northsight-health-OS):
    gh webhook forward --repo=OWNER/REPO --events=issues,issue_comment,ping --url="http://127.0.0.1:54321/functions/v1/github-webhook"
    
    Leave this running; it forwards the selected events to your local URL. Only one forward can be active per repository at a time.
  4. 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 serve is running.
Note: Webhook forwarding is for testing and development only, not for production. The forwarded request will include GitHub’s signature; for verification to succeed locally, set 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_SECRET matches 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 200 and skips processing.
  • Logs: Use Supabase Edge Function logs (or createLogger output) to inspect event, action, and issue_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=ORG and ensure gh auth refresh --scopes admin:org_hook if needed.