Skip to content

GitHub webhook registration is not idempotent — duplicate hooks accumulate on a repo #68

@dkhodakivskyi

Description

@dkhodakivskyi

Summary

cix's GitHub push-webhook auto-registration is not idempotent. When a repo's webhook is (re)registered — re-adding the project, a reindex, or a server upgrade — cix POSTs a new hook to GitHub instead of checking whether one with the same target URL already exists. Repeated registrations therefore accumulate multiple identical webhooks on the same repo, all pointing at the same /api/v1/webhooks/github/<HASH> endpoint.

GitHub then delivers every push N times to the same endpoint, so cix processes each push N times (redundant clone/reindex), and the repo's Settings → Webhooks fills up with duplicates.

Observed (cix v0.7.0)

One repo ended up with 3 identical webhooks:

created_at events url last delivery
15:16 push https://cix.example.com/api/v1/webhooks/github/<HASH> OK
17:46 push https://cix.example.com/api/v1/webhooks/github/<HASH> OK
17:49 push https://cix.example.com/api/v1/webhooks/github/<HASH> OK

<HASH> is identical on all three (same project), so these are true duplicates — not distinct projects/refs. They were created minutes-to-hours apart, i.e. each register attempt added another hook rather than reusing the existing one. All three are active and deliver successfully → every push fans out 3×.

(The server startup log also surfaces the auto-registration path, e.g. webhooks: ... manual_webhooks:N auto_webhooks:M.)

Expected

Registration should be idempotent:

  • Before creating, GET /repos/{owner}/{repo}/hooks and skip (or PATCH) if a hook already targets the same cix webhook URL.
  • Never POST a second hook with a URL that already exists on the repo.

Why it matters

  • N× duplicate push deliveries → N× redundant reindex/clone per push (wasted CPU + embedding-provider API calls).
  • Every connected repo's webhook list accumulates duplicates over time.
  • Compounds with the v0.7 webhook-URL format change (workspace_reposgit_repos + workspace_projects): the startup WARN advises re-registering old-format hooks, but if re-registration doesn't dedupe, a repo ends up with old and new and repeated hooks instead of a single migrated one.

Suggested fix

  • Make webhook registration idempotent — match existing hooks on config.url; reuse or PATCH instead of creating a new one.
  • On the v0.7 URL migration, update the existing hook's URL in place rather than adding a new hook.
  • Optional: a reconcile/cleanup that removes duplicate (and stale-URL) cix hooks from a repo.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions