Repeated integration DELETE runs uninstall() again and can remove a shared install from another org

オープン 初心者向け
#129,229 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@sentry-junior がすでに取り組んでいます。

2026年10月29日 から。

  • #129230 @sentry-junior による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
django, python
領域
api, backend

調査の方向性

src/sentry/integrations/api/endpoints/organization_integration_details.py の OrganizationIntegrationDetailsEndpoint.delete から始めて、uninstall() 呼び出し前後のステータスチェックを追ってください。すでに PENDING_DELETION または DELETION_IN_PROGRESS のインテグレーションには204を返し、最初の DELETE の順序を維持してください。DELETE を2回送信し、2回目のリクエストで uninstall() が再度呼び出されないことを確認する回帰テストを追加または実行してください。

索引モデルが issue の本文から書いたものです。

説明

Bug

Problem

OrganizationIntegrationDetailsEndpoint.delete (src/sentry/integrations/api/endpoints/organization_integration_details.py) calls the provider's uninstall() hook on every request, even when the OrganizationIntegration is already PENDING_DELETION:

  1. The org integration lookup doesn't filter on status, so a second DELETE finds the pending row.
  2. integration.get_installation(...).uninstall() runs unconditionally.
  3. Only after that, the status__in=[ACTIVE, DISABLED] guard prevents a second ScheduledDeletion and audit entry.
  4. The endpoint returns 204 either way.

The guard covers the database side effects, but not the external one.

Impact

Discord's and Cursor Origin's uninstall() only remove the external install when they think the current org is the last one using it, and they skip rows that are PENDING_DELETION / DELETION_IN_PROGRESS when counting.

With orgs A and B sharing one Discord server:

  • First DELETE from A: A's row is still active, the hook counts A and B, sees 2 installs and does nothing. A's row becomes pending.
  • Second DELETE from A (client retry, double click, replayed request): the hook now counts only B, sees 1 install, and calls leave_guild. The Sentry bot leaves the server that org B still uses.

Cursor Origin has the same pattern and would call delete_installation on an installation another org still uses to mint tokens.

Reproduced locally with a regression test on master: the second DELETE triggers one leave_guild call.

Fix

Return 204 before calling uninstall() when the org integration is already PENDING_DELETION or DELETION_IN_PROGRESS. The first DELETE keeps its current ordering (uninstall runs while the row is still active, so the hooks count it).

Notes

  • Concurrent first DELETEs can still both pass the check before either commits the status change. That window is narrow; closing it would mean holding a row lock across the external uninstall call, which this fix doesn't do.
  • Found during the endpoint idempotency audit in #128927.

via @BYK.

--

View Junior Session [Sentry]

主要言語
Python
スター
45.7k
フォーク
5k
平均マージ
1日 3時間
マージ済み PR(30日)
655

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

getsentry/sentry のほかの issue

getsentry/sentry の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。