Skip to content

Bug: Failed repository deletions leave permanent orphaned webhooks in GitHub #6369

@AftAb-25

Description

@AftAb-25

Describe the bug

There's a critical resource leak in internal/repositories/service.go when a user attempts to delete a repository from Minder.

When deleteRepository is called, the code first attempts to deregister the repository entity by deleting the webhook in GitHub via client.DeregisterEntity(...). However, if that GitHub API call fails for any reason (e.g., temporary network issue, rate limiting, or revoked credentials), the error is only logged. The code then completely ignores the failure and proceeds to execute the database transaction that permanently wipes the repository from the Minder DB.

The result is a permanent "zombie" webhook left in the user's GitHub repository.

The Impact

  1. Unrecoverable State: The user is completely locked out of attempting to delete the webhook gracefully through Minder. If they try calling the delete endpoint again, Minder returns sql.ErrNoRows since the repo is already gone natively.
  2. Infinite Ingress Spam: GitHub will continuously blast Minder with events for the targeted repository. Because Minder deleted the repo locally, the webhook handlers can't find it locally resulting in 404/ErrNoRows, silently dropping payloads indefinitely and wasting bandwidth, CPU, and DB queries over time.

Steps to reproduce

  1. Register a GitHub repository in Minder (verifying the webhook is created on GitHub).
  2. Manually invalidate/revoke the GitHub token, or simulate a network failure or 500 Internal Server Error using a proxy.
  3. Attempt to delete the repository via Minder.
  4. Observe the error deregistering repo in the Minder server logs.
  5. Check the Minder database: The repository has been successfully deleted.
  6. Check the GitHub repository settings: The webhook is still active and continuously sending data to Minder.

Expected Behavior

Repository deletion should be a safe, atomic operation from the user's perspective. If Minder fails to deregister the webhook upstream, it should abort the local database deletion and fail fast, allowing the user to retry the deletion once credentials or upstream connectivity are restored.

Suggested Fix

In internal/repositories/service.go, return the error explicitly if DeregisterEntity fails, blocking the db.WithTransaction block from executing:

	err = client.DeregisterEntity(ctx, pb.Entity_ENTITY_REPOSITORIES, repo.Properties)
	if err != nil {
		zerolog.Ctx(ctx).Error().
			Dict("properties", repo.Properties.ToLogDict()).
			Err(err).Msg("error deregistering repo")
        // Abort deletion to prevent an orphaned webhook state.
        return fmt.Errorf("failed to deregister webhook upstream: %w", err)
	}
    
    // Proceed with db.WithTransaction...

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions