ChangeGraphChangeGraph

Start here

Wire GitHub, Sentry, and Vercel: permissions, webhooks, troubleshooting.

Connect GitHub / Sentry / Vercel

Tier-1 providers feed the change graph. Configure secrets in env / integration_secrets. Never log them, never pass them into the scorer or LLM.

Setup UI

In the product app, open Setup (/setup). The page shows integration status cards for GitHub, Sentry, and Vercel. Each card has Test, Reconnect, and Disconnect (they call the provider registry). Feature gates are toggles on the same page. The current org comes from the local auth stub; production OAuth is deferred (docs/AUTH.md).

Backfill is API only: POST /api/v1/setup/backfill (authenticated owner or admin). It returns 202 and runs off the request, with a concurrency cap. Partial failure records last_error on the in-memory cursor. Setup has no backfill button. See Where the running app reads data.

GitHub

Permissions (App)

Prefer a GitHub App for webhooks + API:

  • Repository contents (read)
  • Pull requests (read)
  • Metadata
  • Deployments (read), when available

Webhook

  • Endpoint: POST /api/webhooks/github
  • Verify HMAC with GITHUB_WEBHOOK_SECRET
  • Reject unknown installation_id before upsert
  • Claim delivery id for idempotency

Natural keys

  • Tenant + PR number
  • Tenant + commit SHA
  • Installation + repo owner/name

Env

GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, GITHUB_WEBHOOK_SECRET, optional GITHUB_TOKEN for local/API backfill. Leave empty for mock/seed.

Troubleshooting

SymptomCheck
401 / signature failSecret mismatch; raw body used for HMAC
Events ignoredInstallation not mapped to tenant
Duplicate PRsNatural key collision / missing tenant scope
Empty file listsApp missing Contents/PR permissions

Sentry

What we ingest

Issues, events (stack frames), and releases. Incident builder maps release → commit when possible.

Webhook

  • Endpoint: POST /api/webhooks/sentry
  • Verify with SENTRY_WEBHOOK_SECRET
  • Reject unknown project / org

Mapping rules

  • commit_sha on a release may be null. Never invent a SHA
  • Stack paths drive file-overlap scoring
  • Incident window uses issue/event timestamps

Env

SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT, SENTRY_WEBHOOK_SECRET. Demo defaults match seed (acme-fixture / payments-api).

Troubleshooting

SymptomCheck
No incidentsWebhook not firing / project mismatch
Empty stackEvent payload missing frames; fixture path for local
Unmapped releaseExpected. UI shows null mapping as UNKNOWN

Vercel

Role in MVP

Deployments and project linkage for release / deploy correlation. Mock-first when token empty or VERCEL_USE_MOCK=1. Investigate still requires provider data (GitHub + Sentry + Vercel deploys). Deterministic scoring always runs. Investigation needs a configured LLM provider and fails closed as not_configured.

GitHub repo binding (required in live)

Vercel deployments correlate through github_repos. Live / non-mock mode fails closed unless the Vercel project is bound to a GitHub repo. There is no silent fallback to DEMO_GITHUB_OWNER / DEMO_GITHUB_REPO or acme/widgets.

Bind via (first match wins):

  1. Connection config owner + repo (or repoId of an existing github_repos row)
  2. Stored project mapping from Reconnect / connect / sync
  3. Explicit live env VERCEL_GITHUB_OWNER + VERCEL_GITHUB_REPO

Mock / fixture / local-dev may still use DEMO_GITHUB_* (seed acme / widgets).

Webhook

  • Endpoint: POST /api/webhooks/vercel
  • HMAC via VERCEL_WEBHOOK_SECRET (invalid signature → 401)
  • Unknown project → 403; missing GitHub repo binding in live → 422
  • Delivery id claimed for idempotent upsert of deployment + ChangeEvent

Env

VERCEL_TOKEN, VERCEL_PROJECT_ID, VERCEL_TEAM_ID, VERCEL_WEBHOOK_SECRET, VERCEL_USE_MOCK. Live mapping: VERCEL_GITHUB_OWNER, VERCEL_GITHUB_REPO.

Troubleshooting

SymptomCheck
No deploysMock mode vs real token; project id
HMAC fail (401)Secret / raw body
missing_github_repo_mapping (422)Bind owner+repo (or repoId); live does not use demo repos
Deploy not linkedSHA present on the deploy; project mapped to the GitHub repo ChangeGraph ingested

Local / mock path

Without real provider accounts:

docker compose up -d postgres
pnpm db:push && pnpm seed
pnpm dev

Mocks live under mock-integrations/. See Local fixtures.

Security notes

  • Reject unknown installation / project IDs
  • Claim delivery IDs for idempotent upserts
  • Store ciphertext only in integration_secrets
  • Secrets never appear in scorer inputs, evidence packages, or logs

More: repo docs/SECURITY.md and the Security page.