Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ def get(self, request: Request, user) -> Response:
return self.paginate(
request=request,
queryset=queryset,
on_results=lambda x: serialize(x, request.user),
on_results=lambda x: [item for item in serialize(x, request.user) if item is not None],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The get_attrs method in OrganizationIntegrationSerializer still uses direct dictionary access, which will cause a KeyError if an Integration record is missing, despite the PR's intent.
Severity: HIGH

Suggested Fix

In src/sentry/integrations/api/serializers/models/integration.py, modify the get_attrs method to use integrations_by_id.get(item.integration_id) instead of integrations_by_id[item.integration_id]. This will prevent a KeyError when an integration is not found, allowing the serialization process to handle the missing item gracefully.

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/api/endpoints/user_organizationintegrations.py#L56

Potential issue: The pull request aims to prevent a server error when an
`OrganizationIntegration` record points to a deleted `Integration`. However, the fix is
incomplete. The `OrganizationIntegrationSerializer.get_attrs` method still uses direct
dictionary access (`integrations_by_id[item.integration_id]`) instead of a safe method
like `.get()`. If an integration has been deleted,
`integration_service.get_integrations` will not return it, causing a `KeyError` when
`get_attrs` tries to access the missing ID. This error occurs before the per-item
serialization loop, so the filtering logic added in the API endpoints is never reached,
and the entire API request will fail with a 500 error.

Did we get this right? 👍 / 👎 to inform future reviews.

paginator_cls=OffsetPaginator,
)
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ def get(
def on_results(results: Sequence[OrganizationIntegration]) -> Sequence[Mapping[str, Any]]:
if feature_filters:
results = filter_by_features(results, feature_filters)
return serialize(results, request.user, include_config=include_config)
return [
item
for item in serialize(results, request.user, include_config=include_config)
if item is not None
]

return self.paginate(
queryset=queryset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,18 @@ def test_billing_users_dont_see_integrations(self) -> None:
assert response.status_code == 200
content = orjson.loads(response.content)
assert content == []

def test_serialization_error_filtered_from_response(self) -> None:
"""An exception during serialization should produce an empty list, not null entries."""
integration = self.create_provider_integration(provider="github")
self.create_organization_integration(
organization_id=self.organization.id, integration_id=integration.id
)

with patch(
"sentry.integrations.base.IntegrationInstallation.get_dynamic_display_information",
side_effect=RuntimeError("boom"),
):
response = self.get_success_response(self.user.id)

assert response.data == []
Loading