From 8f32f0379d4c2a875f816bf43f791b4b73622c6e Mon Sep 17 00:00:00 2001 From: Sam Vader Date: Fri, 11 Sep 2026 13:59:14 -0500 Subject: [PATCH] fix(jira): correct the exception class the webhook lookups catch The two JIRA_Issue lookups in the webhook caught JIRA_Instance.DoesNotExist, which the query never raises, so the response they were written to return never fired and the request fell through to the general handler instead. Catch the exception the query actually raises. Move failure detail to the server log so the general handler returns a fixed response. --- dojo/jira/views.py | 26 ++++++-------------------- unittests/test_jira_webhook.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/dojo/jira/views.py b/dojo/jira/views.py index b325fab696d..e63f20d2b27 100644 --- a/dojo/jira/views.py +++ b/dojo/jira/views.py @@ -11,7 +11,7 @@ from django.core.exceptions import PermissionDenied from django.db import DEFAULT_DB_ALIAS from django.db.models import Q -from django.http import Http404, HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.utils import timezone @@ -106,10 +106,9 @@ def webhook(request, secret=None): if parsed.get("webhookEvent") == "jira:issue_updated": # xml examples at the end of file jid = parsed["issue"]["id"] - # This may raise a 404, but it will be handled in the exception response try: jissue = JIRA_Issue.objects.get(jira_id=jid) - except JIRA_Instance.DoesNotExist: + except JIRA_Issue.DoesNotExist: return webhook_responser_handler("info", f"JIRA issue {jid} is not linked to a DefectDojo Finding") # Add jira_key to context now that we have it pghistory.context(jira_key=jissue.jira_key) @@ -182,22 +181,9 @@ def webhook(request, secret=None): if (error_response := check_for_and_create_comment(parsed)) is not None: return error_response - except Exception as e: - # Check if the issue is originally a 404 - if isinstance(e, Http404): - return webhook_responser_handler("debug", str(e)) - # Try to get a little more information on the exact exception - try: - message = ( - f"Original Exception: {e}\n" - f"jira webhook body parsed:\n{json.dumps(parsed, indent=4)}" - ) - except Exception: - message = ( - f"Original Exception: {e}\n" - f"jira webhook body :\n{request.body.decode('utf-8')}" - ) - return webhook_responser_handler("debug", message) + except Exception: + logger.exception("Failed to process incoming JIRA webhook") + return webhook_responser_handler("debug", "Could not process the incoming JIRA webhook") return webhook_responser_handler("No logging here", "Success!") @@ -262,7 +248,7 @@ def check_for_and_create_comment(parsed_json): jid = comment.get("self", "").split("/")[-3] try: jissue = JIRA_Issue.objects.get(jira_id=jid) - except JIRA_Instance.DoesNotExist: + except JIRA_Issue.DoesNotExist: return webhook_responser_handler("info", f"JIRA issue {jid} is not linked to a DefectDojo Finding") logger.debug(f"Received issue comment for {jissue.jira_key}") logger.debug("jissue: %s", vars(jissue)) diff --git a/unittests/test_jira_webhook.py b/unittests/test_jira_webhook.py index a63e35f07aa..8038e8b5bf7 100644 --- a/unittests/test_jira_webhook.py +++ b/unittests/test_jira_webhook.py @@ -640,6 +640,36 @@ def test_webhook_update_no_jira_issue_at_all(self): self.assertEqual(200, response.status_code, response.content[:1000]) + def test_webhook_unlinked_issue_returns_the_not_linked_message(self): + self.system_settings(enable_jira=True, enable_jira_web_hook=True, disable_jira_webhook_secret=False, jira_webhook_secret=self.correct_secret) + + # no JIRA_Issue row carries this id at all + body = json.loads(self.jira_issue_update_template_string) + body["issue"]["id"] = 999999 + + response = self.client.post(reverse("jira_web_hook_secret", args=(self.correct_secret, )), + body, + content_type="application/json") + + self.assertEqual(200, response.status_code, response.content[:1000]) + self.assertEqual(b"JIRA issue 999999 is not linked to a DefectDojo Finding", response.content) + + def test_webhook_failure_does_not_echo_the_request_body(self): + self.system_settings(enable_jira=True, enable_jira_web_hook=True, disable_jira_webhook_secret=False, jira_webhook_secret=self.correct_secret) + + # "updated" is required by the handler, so dropping it forces the fall-through handler + body = json.loads(self.jira_issue_update_template_string) + body["issue"]["fields"].pop("updated") + body["canary"] = "DO-NOT-ECHO-THIS" + + response = self.client.post(reverse("jira_web_hook_secret", args=(self.correct_secret, )), + body, + content_type="application/json") + + self.assertEqual(200, response.status_code, response.content[:1000]) + self.assertNotIn(b"DO-NOT-ECHO-THIS", response.content) + self.assertNotIn(b"Original Exception", response.content) + def test_webhook_issue_updated_extracts_comment(self): self.system_settings(enable_jira=True, enable_jira_web_hook=True, disable_jira_webhook_secret=False, jira_webhook_secret=self.correct_secret)