chore(integrations): log Jira issue.updated webhook payloads behind a flag#114822
chore(integrations): log Jira issue.updated webhook payloads behind a flag#114822hobzcalvin wants to merge 1 commit intomasterfrom
Conversation
… flag Adds a temporary `organizations:jira-issue-updated-payload-logging` Flagpole feature that, when enabled for a linked org, causes the Jira Cloud `issue.updated` webhook handler to log the full webhook payload plus a focused log line whenever the changelog contains a `project` change. We need this data to design issue-link rewriting when a Jira issue is moved between projects.
| "issue_id": issue.get("id"), | ||
| "webhook_event": data.get("webhookEvent"), | ||
| "changed_fields": [item.get("field") for item in changelog_items], |
There was a problem hiding this comment.
Full Jira webhook payload logged to durable operational sink
The handler logs the entire Jira issue.updated webhook body ("payload": data) plus assignee/reporter fields nested in fields to the application logger. Jira issue payloads routinely contain real user PII (assignee/reporter emailAddress, displayName, accountId), customer org identifiers, and free-form issue summaries/descriptions that may contain customer-confidential content. Sending the raw payload to logs (a durable, vendor-visible sink) exposes user and customer data well beyond what the feature requires, which is project-change metadata.
Verification
Traced the data flow: data = request.data is the parsed Jira webhook body. Jira Cloud jira:issue_updated webhooks include issue.fields.assignee, issue.fields.reporter, issue.fields.creator with emailAddress/displayName/accountId, plus summary/description free text and user (the actor) with email. The new extra dict embeds the entire data under payload and additionally embeds fields.project (which together with the issue context links to a named customer's Jira instance). The logger is the standard module logger, which routes to durable operational logging. The skill explicitly calls out logging request.body/webhook payloads/identity-provider payloads as a high-severity privacy sink.
Identified by Warden wrdn-pii · JEH-S4Q
| def _payload_logging_enabled(integration_id: int) -> bool: | ||
| """True if any org linked to this Jira integration has the | ||
| `jira-issue-updated-payload-logging` feature enabled. | ||
|
|
||
| A Jira integration can be shared by multiple Sentry orgs, and | ||
| `features.has` needs an `Organization`, so we have to walk the linked | ||
| `OrganizationIntegration` rows and look each org up. | ||
| """ | ||
| contexts = integration_service.organization_contexts(integration_id=integration_id) | ||
| for oi in contexts.organization_integrations: |
There was a problem hiding this comment.
Bug: The function _payload_logging_enabled introduces an N+1 database query pattern in the Jira issue.updated webhook handler, causing unnecessary latency on every request.
Severity: MEDIUM
Suggested Fix
The organization_id values are already available in the contexts.organization_integrations object. Use these IDs directly for the feature flag check. Alternatively, fetch all required organization objects in a single batch query instead of making individual database calls in a loop.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/sentry/integrations/jira/webhooks/issue_updated.py#L33-L42
Potential issue: The function `_payload_logging_enabled` is called unconditionally on
every `issue.updated` webhook request, introducing an N+1 database query pattern. It
first fetches all `OrganizationIntegration` rows for the integration, then issues a
separate `organization_service.get_organization_by_id()` call for each linked
organization. This overhead occurs on every webhook even when the associated feature
flag is disabled for all linked organizations, adding unnecessary latency to a
high-frequency webhook handler.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7bfa989. Configure here.
| logger.info( | ||
| "jira.issue-updated.project-changed", | ||
| extra={**payload_extra, "project_change": project_change}, | ||
| ) |
There was a problem hiding this comment.
Unprotected diagnostic code can break webhook processing
Medium Severity
The call to _payload_logging_enabled on every webhook request makes multiple RPC calls (integration_service.organization_contexts + N × organization_service.get_organization_by_id) that are not wrapped in a try/except. If any of these calls raises an exception (e.g., transient database/network error), it propagates up and the dispatch method returns a 500, causing handle_assignee_change and handle_status_change to be skipped entirely. Temporary diagnostic code can thus break real webhook processing.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7bfa989. Configure here.
| id=oi.organization_id, include_teams=False, include_projects=False | ||
| ) | ||
| if org and features.has(PAYLOAD_LOGGING_FEATURE, org.organization): | ||
| return True |
There was a problem hiding this comment.
Redundant RPC calls on every webhook request
Medium Severity
_payload_logging_enabled calls integration_service.organization_contexts on every webhook request, duplicating the same RPC call already made by bind_org_context_from_integration a few lines earlier. It then makes N additional organization_service.get_organization_by_id calls (one per linked org). All of this runs on every issue.updated webhook regardless of whether the feature is enabled for any org, adding unnecessary latency and load to a high-throughput endpoint.
Reviewed by Cursor Bugbot for commit 7bfa989. Configure here.
Backend Test FailuresFailures on
|


Adds a temporary
organizations:jira-issue-updated-payload-loggingFlagpole feature that, when enabled for a linked org, causes the Jira Cloudissue.updatedwebhook handler to log the full webhook payload plus a focused log line whenever the changelog contains aprojectchange. We need this data to design issue-link rewriting when a Jira issue is moved between projects.Resolves ISWF-1512