Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(sentry apps): Improve Errors for Alert Rule Creation for Sentry Apps #82067

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

Christinarlong
Copy link
Contributor

@Christinarlong Christinarlong commented Dec 12, 2024

Introduces two classes to represent Sentry App exceptions:
SentryAppError should be used to represent client side errors like failed validation. For the webhook, these should not be sent to the integrator.
SentryAppIntegratorError is used to represent errors between Sentry & the integrator, i.e connection failed, integrator response is incorrect etc. These should be sent to the integrator for the webhook.

For this PR, we want to start wrapping errors in the SentryApp flows with these distinctions. And then in the endpoints we want to catch these two specific errors and return the error message. More info here in notion

This PR is a split of #81877 since that was turning into 2 PRs into 1

Context for Alert Rule Sentry App creation: Notion doc

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Dec 12, 2024
trigger_sentry_app_action_creators_for_incidents(serialized_data)
except (SentryAppError, SentryAppIntegratorError) as e:
return Response(
str(e),

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix AI 27 days ago

To fix the problem, we need to ensure that detailed exception messages are not exposed to the end user. Instead, we should log the detailed error message on the server and return a generic error message to the user. This can be achieved by modifying the exception handling code to log the exception and return a generic error message.

  1. Modify the exception handling code in the create_sentry_app_alert_rule_component_for_incidents function to log the detailed error message and return a generic error message.
  2. Modify the exception handling code in the create_sentry_app_alert_rule_issues_component function to log the detailed error message and return a generic error message.
Suggested changeset 1
src/sentry/sentry_apps/utils/alert_rule_action.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/sentry/sentry_apps/utils/alert_rule_action.py b/src/sentry/sentry_apps/utils/alert_rule_action.py
--- a/src/sentry/sentry_apps/utils/alert_rule_action.py
+++ b/src/sentry/sentry_apps/utils/alert_rule_action.py
@@ -41,4 +41,5 @@
     except (SentryAppError, SentryAppIntegratorError) as e:
+        sentry_sdk.capture_exception(e)
         return Response(
-            str(e),
+            "An error occurred while processing your request.",
             status=status.HTTP_400_BAD_REQUEST,
@@ -61,4 +62,5 @@
     except (SentryAppError, SentryAppIntegratorError) as e:
+        sentry_sdk.capture_exception(e)
         return Response(
-            {"actions": [str(e)]},
+            {"actions": ["An error occurred while processing your request."]},
             status=status.HTTP_400_BAD_REQUEST,
EOF
@@ -41,4 +41,5 @@
except (SentryAppError, SentryAppIntegratorError) as e:
sentry_sdk.capture_exception(e)
return Response(
str(e),
"An error occurred while processing your request.",
status=status.HTTP_400_BAD_REQUEST,
@@ -61,4 +62,5 @@
except (SentryAppError, SentryAppIntegratorError) as e:
sentry_sdk.capture_exception(e)
return Response(
{"actions": [str(e)]},
{"actions": ["An error occurred while processing your request."]},
status=status.HTTP_400_BAD_REQUEST,
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options

except (SentryAppError, SentryAppIntegratorError) as e:
return Response(
{"actions": [str(e)]},

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix AI 27 days ago

To fix the problem, we need to ensure that detailed exception messages are not exposed to the user. Instead, we should log the detailed error message on the server and return a generic error message to the user. This can be achieved by modifying the exception handling code to log the exception and return a generic error message.

  1. Modify the exception handling block to log the detailed error message using sentry_sdk.capture_exception(e).
  2. Return a generic error message to the user.
Suggested changeset 1
src/sentry/sentry_apps/utils/alert_rule_action.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/sentry/sentry_apps/utils/alert_rule_action.py b/src/sentry/sentry_apps/utils/alert_rule_action.py
--- a/src/sentry/sentry_apps/utils/alert_rule_action.py
+++ b/src/sentry/sentry_apps/utils/alert_rule_action.py
@@ -61,4 +61,5 @@
     except (SentryAppError, SentryAppIntegratorError) as e:
+        sentry_sdk.capture_exception(e)
         return Response(
-            {"actions": [str(e)]},
+            {"actions": ["An error occurred while processing the request."]},
             status=status.HTTP_400_BAD_REQUEST,
EOF
@@ -61,4 +61,5 @@
except (SentryAppError, SentryAppIntegratorError) as e:
sentry_sdk.capture_exception(e)
return Response(
{"actions": [str(e)]},
{"actions": ["An error occurred while processing the request."]},
status=status.HTTP_400_BAD_REQUEST,
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
Copy link

codecov bot commented Dec 13, 2024

Codecov Report

Attention: Patch coverage is 90.67797% with 11 lines in your changes missing coverage. Please review.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/sentry/sentry_apps/utils/alert_rule_action.py 91.66% 5 Missing ⚠️
...s/external_requests/alert_rule_action_requester.py 72.72% 3 Missing ⚠️
src/sentry/sentry_apps/services/app/impl.py 75.00% 2 Missing ⚠️
...rc/sentry/sentry_apps/alert_rule_action_creator.py 88.88% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #82067       +/-   ##
===========================================
+ Coverage   52.94%   80.37%   +27.42%     
===========================================
  Files        7247     7273       +26     
  Lines      319932   321339     +1407     
  Branches    20944    20944               
===========================================
+ Hits       169397   258264    +88867     
+ Misses     150133    62673    -87460     
  Partials      402      402               

trigger_sentry_app_action_creators_for_incidents(serialized_data)
except (SentryAppError, SentryAppIntegratorError) as e:
return Response(
str(e),
Copy link
Member

Choose a reason for hiding this comment

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

Add a comment here for future engineers about why this is safe.

raise Exception(result.message)


def create_sentry_app_alert_rule_component_for_incidents(
Copy link
Member

Choose a reason for hiding this comment

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

It is confusing to me that one of the create component methods you have here returns a component and one of them return an error and None on success.

Copy link
Member

Choose a reason for hiding this comment

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

[1] I don't see much benefit in this method. How about you directly call trigger_sentry_app_action_creators_for_incidents and let the exception go through.

@@ -285,7 +285,9 @@ def put(self, request: Request, project, rule) -> Response:
context = {"uuid": client.uuid}
return Response(context, status=202)

trigger_sentry_app_action_creators_for_issues(actions=kwargs["actions"])
result = create_sentry_app_alert_rule_issues_component(actions=kwargs["actions"])
if isinstance(result, Response):
Copy link
Member

Choose a reason for hiding this comment

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

It's not good practice to have different typed returned from a method and then decide what to do with it based on type. I have a suggestion below on how to improve this. Please read the comments annotated with [n] in the order on n.

@@ -285,7 +285,9 @@ def put(self, request: Request, project, rule) -> Response:
context = {"uuid": client.uuid}
return Response(context, status=202)

trigger_sentry_app_action_creators_for_issues(actions=kwargs["actions"])
result = create_sentry_app_alert_rule_issues_component(actions=kwargs["actions"])
Copy link
Member

Choose a reason for hiding this comment

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

[2] Then wrap this in try catch and then in the catch, catch the exception and call a method like return IntegrationResponse.from_exception() where this method is a util that does all the work you're doing to turn exceptions into response.

If from_exception() needs to know the caller for some reason to parse the errors better you can pass that as a param.

@@ -82,7 +84,12 @@ def update_alert_rule(request: Request, organization, alert_rule):
partial=True,
)
if serializer.is_valid():
trigger_sentry_app_action_creators_for_incidents(serializer.validated_data)
raised_error = create_sentry_app_alert_rule_component_for_incidents(
Copy link
Member

Choose a reason for hiding this comment

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

All comments applies to this method as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants