Skip to content

[bug] webhook: registered-repo gate uses case-sensitive PK lookup and silently skips events #140

@kiannidev

Description

@kiannidev

Duplicate check

Item Relation
#120 (open) Uninstall/remove fails + duplicate PK rows → ingestion continues after remove
#121 (open) PR fix for #120 (install lowercase + case-insensitive remove) — does not fix webhook.service gate
#70 (closed) Admin validateRepoFullName lowercases — not webhook path
No open/closed issue findOneBy({ repoFullName }) false-negative skip when casing differs

Description

Before handling repo-scoped webhooks, WebhookService checks registration with an exact-case primary-key lookup on payload.repository.full_name. GitHub repository names are case-insensitive. Rows created by installation_repositories.added store repo.full_name as sent by GitHub (often mixed case). Admin registration updates via LOWER(repo_full_name) but does not rename the PK. If the webhook payload casing does not exactly match the stored repos.repo_full_name, findOneBy returns null and the handler logs “not registered” and drops the event—even when a registered row exists under another casing variant.

This is the inverse failure mode of #120 (ingestion continues); here ingestion stops incorrectly.

Steps to Reproduce

  1. installation_repositories.added creates repos row Org/MyRepo (registered=false).
  2. Admin POST /api/v1/admin/repos/register with org/myrepoLOWER match sets registered=true on the existing PK Org/MyRepo (or creates a second row if both exist — see Critical] Silent uninstall failure — data ingestion continues after app removal due to case-sensitive PK match #120).
  3. GitHub delivers pull_request webhook with repository.full_name = org/myrepo.
  4. webhook.service.ts runs repoRepo.findOneBy({ repoFullName: 'org/myrepo' }) → no match.
  5. Event skipped; PR/issue data in mirror stays stale while repo is registered.

Expected Behavior

Registration gate should resolve repos case-insensitively (e.g. LOWER(repo_full_name) = LOWER($1)), consistent with admin register, getTokenForRepo, and miner queries.

Actual Behavior

// webhook.service.ts ~L83–89
const repo = await this.repoRepo.findOneBy({ repoFullName });
if (!repo?.registered) {
  this.logger.log(`Skipping ${event}: repo ${repoFullName} not registered`);
  return;
}

Environment

  • OS: Linux
  • Runtime/Node version: Node 20
  • Browser (if applicable): N/A

Additional Context

Related: Normalize repo_full_name to lowercase on all insert paths (#121) plus case-insensitive lookup in WebhookService for legacy rows.

PR scope: ~15–40 lines.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions