fix(gitlab): Heal webhooks on integration reinstall#119340
Draft
billyvg wants to merge 2 commits into
Draft
Conversation
e96bb0f to
11a8033
Compare
9768d24 to
cd7f2ab
Compare
Contributor
Sentry Snapshot Testing
|
11a8033 to
761c010
Compare
f18fe26 to
c95ae46
Compare
761c010 to
c39d665
Compare
c95ae46 to
16058ad
Compare
Base automatically changed from
billyvong/ref/gitlab-webhook-creation-logging
to
master
July 10, 2026 20:32
Add structured logging to GitlabRepositoryProvider.on_create_repository so the webhook install path is observable in Sentry Logs (no Datadog metrics). Three logs, all on the sentry.integrations.gitlab logger: - gitlab.repository.on_create_repository on every invocation, with has_existing_webhook, to gauge how often the path runs. - gitlab.repository.webhook_created on success, so actual GitLab hook creation calls can be counted (i.e. request volume to GitLab). - gitlab.repository.webhook_creation_skipped when a stale webhook_id is already present and creation is skipped. No change to webhook creation behavior. This baseline lets us confirm that reinstalls silently skip webhook creation (stale webhook_id survives uninstall) and verify any future fix without flooding GitLab with requests. Co-Authored-By: Claude <noreply@anthropic.com>
When a GitLab integration is uninstalled and reinstalled, the stored webhook_id survives in Repository.config (disassociate_organization_integration clears integration_id but leaves the config intact and never deletes the GitLab hook). The old guard saw a truthy webhook_id and returned without touching GitLab, so no working webhook existed after reinstall. If the reinstall used a new OAuth app, the webhook secret rotated and the surviving hook's token no longer matched, so incoming events were rejected. Verify-then-refresh/create in on_create_repository instead of trusting a stored webhook_id: list the project's hooks and, if the stored hook is still present, refresh its token + events (healing the rotated-secret case); if it is gone, create a fresh hook and store the new id. Co-Authored-By: Claude <noreply@anthropic.com>
16058ad to
6cfc743
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes GitLab webhooks not being (re)created after uninstall → reinstall of the integration.
GitlabRepositoryProvider.on_create_repositoryno longer blindly trusts a storedwebhook_idand returns early. It addresses the hook directly by id and lets GitLab be the source of truth:webhook_idupdate_project_webhook— refresh token + events in place (heals a rotated secret)404)Root cause
On uninstall,
disassociate_organization_integrationclearsRepository.integration_idbut leavesconfig["webhook_id"]intact and never deletes the GitLab hook. On reinstall, the base provider merges that stalewebhook_idforward, and the old guard returned early — so no working webhook existed afterward. Reinstalling with a new OAuth application also rotates the webhook secret (sha1(hostname + client_id)), so the surviving hook's token stopped matching and inbound events were rejected (gitlab.webhook.invalid-token-secret). Updating the hook in place re-pushes the current token; a missing hook is recreated.Why address by id (not list-and-match)
We only ever persist a
webhook_idfor a hook we created, and GitLab never reuses hook ids. So the stored id resolves to exactly one of two states — our hook, or404. Addressing it directly:get_project_webhooksscan that could miss the hook and create a duplicate.PUTon the common heal path (previouslyGET-list +PUT);PUT+POSTonly when the hook is genuinely gone.Rate-limit safety (re: the reverted #117801)
#117801 was reverted because it flooded GitLab: it hooked
post_installand fanned outupdate_project_webhookacross every org × every repo sharing the integration, unconditionally, on every (re)install.This fix is structurally different:
update_project_webhook, plus acreateonly on404) runs only when a repo already has a storedwebhook_id. Fresh repos cost nothing extra (onePOST, as before).scm_repo_sync_beatsweep only feeds new/relinked repos intoon_create_repository; in steady state nothing fires — the healing is a one-time post-reinstall reconciliation.SYNC_BATCH_SIZE = 100percreate_repos_batchtask, scoped to a single org.ApiRateLimitedError(not in the session auto-retry list) aborts the batch;create_repos_batchretries afterdelay=120s. No hammering.Known follow-up: every reactivation with a stored
webhook_idstill issues aPUTeven when nothing rotated. A stacked PR adds a local secret-fingerprint short-circuit so steady-state reactivations make zero GitLab calls — kept separate to keep this diff focused on correctness.Observability (from #119333)
Install path logs on the
sentry.integrations.gitlablogger:on_create_repository(every invocation),webhook_refreshed(hook updated in place),webhook_stale_recreated(stale id404'd → recreated),webhook_created(fresh hook). Eachon_create_repositoryends in exactly one terminal event, logged after the GitLab call succeeds.Notes
disassociate_organization_integration.404failure while updating the hook surfaces as an error and does not fall through to create a duplicate hook (covered by tests).