From 303c254743f7b4fc0ab967c97f870cfc105237bf Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 24 Nov 2025 17:14:08 +0000 Subject: [PATCH 1/4] Update versions in application files --- components/package.json | 2 +- helm/defectdojo/Chart.yaml | 8 ++++---- helm/defectdojo/README.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/package.json b/components/package.json index 564f54c63a0..07c351cf814 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.52.3", + "version": "2.53.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 182d0bfd1e7..fbc01d30eaf 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.52.3" +appVersion: "2.53.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.8.3 +version: 1.8.4-dev icon: https://defectdojo.com/hubfs/DefectDojo_favicon.png maintainers: - name: madchap @@ -33,5 +33,5 @@ dependencies: # - kind: security # description: Critical bug annotations: - artifacthub.io/prerelease: "false" - artifacthub.io/changes: "- kind: changed\n description: Bump DefectDojo to 2.52.3\n" + artifacthub.io/prerelease: "true" + artifacthub.io/changes: "" diff --git a/helm/defectdojo/README.md b/helm/defectdojo/README.md index 02c9da17348..8f633991551 100644 --- a/helm/defectdojo/README.md +++ b/helm/defectdojo/README.md @@ -512,7 +512,7 @@ The HELM schema will be generated for you. # General information about chart values -![Version: 1.8.3](https://img.shields.io/badge/Version-1.8.3-informational?style=flat-square) ![AppVersion: 2.52.3](https://img.shields.io/badge/AppVersion-2.52.3-informational?style=flat-square) +![Version: 1.8.4-dev](https://img.shields.io/badge/Version-1.8.4--dev-informational?style=flat-square) ![AppVersion: 2.53.0-dev](https://img.shields.io/badge/AppVersion-2.53.0--dev-informational?style=flat-square) A Helm chart for Kubernetes to install DefectDojo From c69eb0e632c5ac4151e76ff8f2f7f29e264e4543 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Sat, 29 Nov 2025 00:37:22 +0000 Subject: [PATCH 2/4] fix(helm): Avoid forbidden chars in annotation (#13772) Signed-off-by: kiblik <5609770+kiblik@users.noreply.github.com> --- .github/workflows/test-helm-chart.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-helm-chart.yml b/.github/workflows/test-helm-chart.yml index 8fa56ea0ba9..72c3719adce 100644 --- a/.github/workflows/test-helm-chart.yml +++ b/.github/workflows/test-helm-chart.yml @@ -114,7 +114,12 @@ jobs: - name: Update values in HELM chart if: startsWith(github.head_ref, 'renovate/') || startsWith(github.head_ref, 'dependabot/') run: | - yq -i '.annotations."artifacthub.io/changes" += "- kind: changed\n description: ${{ github.event.pull_request.title }}\n"' helm/defectdojo/Chart.yaml + title=${{ github.event.pull_request.title }} + chars='{}:[],&*#?|-<>=!%@' + for c in $(echo "$chars" | grep -o .); do + title="${title//"$c"/_}" + done + yq -i '.annotations."artifacthub.io/changes" += "- kind: changed\n description: $title\n"' helm/defectdojo/Chart.yaml git add helm/defectdojo/Chart.yaml git commit -m "ci: update Chart annotations from PR #${{ github.event.pull_request.number }}" || echo "No changes to commit" From 02a69efd7fc4f1638277ddc24798e4b2febb5e41 Mon Sep 17 00:00:00 2001 From: valentijnscholten Date: Sat, 29 Nov 2025 09:48:40 +0100 Subject: [PATCH 3/4] Remove left over log statement Remove unnecessary error logging for finding group status. --- dojo/jira_link/helper.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dojo/jira_link/helper.py b/dojo/jira_link/helper.py index bf2b0101fed..25f15219d22 100644 --- a/dojo/jira_link/helper.py +++ b/dojo/jira_link/helper.py @@ -208,7 +208,6 @@ def can_be_pushed_to_jira(obj, form=None): return False, f"Finding below the minimum JIRA severity threshold ({System_Settings.objects.get().jira_minimum_severity}).", "error_below_minimum_threshold" elif isinstance(obj, Finding_Group): finding_group_status = _safely_get_obj_status_for_jira(obj) - logger.error("Finding group status: %s", finding_group_status) if "Empty" in finding_group_status: return False, f"{to_str_typed(obj)} cannot be pushed to jira as it contains no findings above minimum treshold.", "error_empty" From ef3e19da20b305786950237e5caf511d47f863ce Mon Sep 17 00:00:00 2001 From: Valentijn Scholten Date: Sat, 29 Nov 2025 14:30:23 +0100 Subject: [PATCH 4/4] JIRA: add retries/rate limit support --- .../troubleshooting_jira.md | 28 +++++++++++++++++++ dojo/jira_link/helper.py | 9 ++++-- dojo/settings/settings.dist.py | 16 +++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/docs/content/en/share_your_findings/troubleshooting_jira.md b/docs/content/en/share_your_findings/troubleshooting_jira.md index aecdb8f1bcf..2b671b9e12d 100644 --- a/docs/content/en/share_your_findings/troubleshooting_jira.md +++ b/docs/content/en/share_your_findings/troubleshooting_jira.md @@ -101,6 +101,34 @@ To correct this issue, you can add the 'Epic Name' field to your Project's issue ![image](images/epic_name_error.png) +## Configuring JIRA Connection Retries and Timeouts + +DefectDojo's JIRA integration includes configurable retry and timeout settings to handle rate limiting and connection issues. These settings are important for maintaining system responsiveness, especially when using Celery workers. + +### Available Configuration Variables + +The following environment variables control JIRA connection behavior: + +- **`DD_JIRA_MAX_RETRIES`** (default: `3`): Maximum number of retry attempts for recoverable errors. The integration will automatically retry on HTTP 429 (Too Many Requests), HTTP 503 (Service Unavailable), and connection errors. See the [JIRA rate limiting documentation](https://developer.atlassian.com/cloud/jira/platform/rate-limiting/) for more information. + +- **`DD_JIRA_CONNECT_TIMEOUT`** (default: `10` seconds): Connection timeout for establishing a connection to the JIRA server. + +- **`DD_JIRA_READ_TIMEOUT`** (default: `30` seconds): Read timeout for waiting for a response from the JIRA server after the connection is established. + +**Note on Rate Limiting**: The jira library has a built-in maximum wait time of 60 seconds for rate limiting retries. If JIRA's `Retry-After` header indicates a wait time longer than 60 seconds, the request will fail and not be retried. This is a limitation of the jira library version currently in use. + +### Why Conservative Values Matter + +**Important**: It is recommended to use conservative (lower) values for these settings. Here's why: + +1. **Celery Task Blocking**: JIRA operations in DefectDojo run as asynchronous Celery tasks. When a task is waiting for a retry delay, it blocks that Celery worker from processing other tasks. + +2. **Worker Pool Exhaustion**: If multiple JIRA operations are retrying with long delays, you can quickly exhaust your Celery worker pool, causing other tasks (not just JIRA-related) to queue up and wait. + +3. **System Responsiveness**: Long retry delays can make the system appear unresponsive, especially during JIRA outages or rate limiting events. + +JIRA Rate limiting is new, so please let us know on Slack or GitHub what works best for you. + ## Jira and DefectDojo are out of sync Sometimes Jira is down, or DefectDojo is down, or there was bug in a webhook. In this case, Jira can become out of sync with DefectDojo. If this is the case for lots of issues, manual reconciliation might not be feasible. For this scenario there is the management command 'jira_status_reconciliation'. diff --git a/dojo/jira_link/helper.py b/dojo/jira_link/helper.py index bf2b0101fed..020a5a69b05 100644 --- a/dojo/jira_link/helper.py +++ b/dojo/jira_link/helper.py @@ -433,14 +433,19 @@ def has_jira_configured(obj): def connect_to_jira(jira_server, jira_username, jira_password): + max_retries = getattr(settings, "JIRA_MAX_RETRIES", 3) + timeout = getattr(settings, "JIRA_TIMEOUT", (10, 30)) + return JIRA( server=jira_server, basic_auth=(jira_username, jira_password), - max_retries=0, + max_retries=max_retries, + timeout=timeout, options={ "verify": settings.JIRA_SSL_VERIFY, "headers": settings.ADDITIONAL_HEADERS, - }) + }, + ) def get_jira_connect_method(): diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index 57c18e6ea56..a2258bdddc8 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -249,6 +249,16 @@ # When interacting with jira tickets that attached finding groups, we should no be opening any findings # on the DefectDojo side because jira has no way of knowing if a finding really should be reopened or not DD_JIRA_WEBHOOK_ALLOW_FINDING_GROUP_REOPEN=(bool, False), + # JIRA connection retry and timeout settings: https://developer.atlassian.com/cloud/jira/platform/rate-limiting/ + # Maximum number of retry attempts for recoverable errors (429, 503, ConnectionError) + # See https://jira.readthedocs.io/ for more in the jira library used by DefectDojo + # Note: The jira library has a built-in maximum wait time of 60s for rate limiting retries. + # If JIRA's Retry-After header indicates a wait time longer than 60s, the request will fail and not be retried. + DD_JIRA_MAX_RETRIES=(int, 3), + # Connection timeout (seconds) for establishing a connection to the JIRA server + DD_JIRA_CONNECT_TIMEOUT=(int, 10), + # Read timeout (seconds) for waiting for a response from the JIRA server + DD_JIRA_READ_TIMEOUT=(int, 30), # You can set extra Jira issue types via a simple env var that supports a csv format, like "Work Item,Vulnerability" DD_JIRA_EXTRA_ISSUE_TYPES=(str, ""), # if you want to keep logging to the console but in json format, change this here to 'json_console' @@ -1714,6 +1724,12 @@ def saml2_attrib_map_format(din): JIRA_SSL_VERIFY = env("DD_JIRA_SSL_VERIFY") JIRA_DESCRIPTION_MAX_LENGTH = env("DD_JIRA_DESCRIPTION_MAX_LENGTH") JIRA_WEBHOOK_ALLOW_FINDING_GROUP_REOPEN = env("DD_JIRA_WEBHOOK_ALLOW_FINDING_GROUP_REOPEN") +# JIRA connection retry and timeout settings +JIRA_MAX_RETRIES = env("DD_JIRA_MAX_RETRIES") +JIRA_CONNECT_TIMEOUT = env("DD_JIRA_CONNECT_TIMEOUT") +JIRA_READ_TIMEOUT = env("DD_JIRA_READ_TIMEOUT") +# Combine timeouts into a tuple for the JIRA library: (connect_timeout, read_timeout) +JIRA_TIMEOUT = (JIRA_CONNECT_TIMEOUT, JIRA_READ_TIMEOUT) # ------------------------------------------------------------------------------ # LOGGING