From 22e0b934d62cbaf75e6276ee81ba3f61293a2a6a Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 4 Aug 2025 15:47:21 +0000 Subject: [PATCH 01/12] Update versions in application files --- components/package.json | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/package.json b/components/package.json index a89b39866cf..23c211dc40b 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.49.0", + "version": "2.50.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 4a6dce3dab4..8fd6a559091 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.49.0" +appVersion: "2.50.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.201 +version: 1.6.202-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From 84d149ef79aa13b1bfcd679b8a1b25dcd0f7aff9 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Thu, 7 Aug 2025 08:17:12 +0200 Subject: [PATCH 02/12] Revert "Feat(nginx): Add support for IPv6" (#12916) This reverts commit e9d987206cd747b76df89605e9bf8108e8abdfc4. --- nginx/nginx.conf | 1 - nginx/nginx_TLS.conf | 2 -- 2 files changed, 3 deletions(-) diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 0300a82a829..711954d5916 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -25,7 +25,6 @@ http { server { server_tokens off; listen 8080; - listen [::]:8080; gzip on; gzip_types application/atom+xml application/geo+json application/javascript application/x-javascript application/json application/ld+json application/manifest+json application/rdf+xml application/rss+xml application/xhtml+xml application/xml font/eot font/otf font/ttf image/svg+xml text/css text/javascript text/plain text/xml; diff --git a/nginx/nginx_TLS.conf b/nginx/nginx_TLS.conf index 085b19586de..2b2bd18b7ad 100644 --- a/nginx/nginx_TLS.conf +++ b/nginx/nginx_TLS.conf @@ -20,7 +20,6 @@ http { } server { listen 8080; - listen [::]:8080; location / { return 301 https://$host:8443$request_uri; } @@ -33,7 +32,6 @@ http { server { server_tokens off; listen 8443 ssl; - listen [::]:8443 ssl; server_name your.servername.com; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; From 64a118ab301030c36d55f3b3f1d11b5536881538 Mon Sep 17 00:00:00 2001 From: valentijnscholten Date: Thu, 7 Aug 2025 08:19:05 +0200 Subject: [PATCH 03/12] debug toolbar: downgrade to 5.2.0 (#12919) --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 27ac5afc8e9..3e05356f1ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -51,7 +51,7 @@ packageurl-python==0.17.3 django-crum==0.7.9 JSON-log-formatter==1.1.1 django-split-settings==1.3.2 -django-debug-toolbar==6.0.0 +django-debug-toolbar==5.2.0 django-debug-toolbar-request-history==0.1.4 vcrpy==7.0.0 vcrpy-unittest==0.1.7 @@ -75,4 +75,4 @@ fontawesomefree==6.6.0 PyYAML==6.0.2 pyopenssl==25.1.0 parameterized==0.9.0 -watchdog==6.0.0 # only needed for development, but would require some docker refactoring if we want to exclude it for production images \ No newline at end of file +watchdog==6.0.0 # only needed for development, but would require some docker refactoring if we want to exclude it for production images From 38169185fbce99e290eabb49081f5279fef2027a Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Fri, 8 Aug 2025 12:04:43 -0500 Subject: [PATCH 04/12] Webhook Notifications: Support the owner field (#12940) * Webhook Notifications: Support the owner field * Forgot the `engagement_added` event in docs * Support the case where the owner is not supplied * Adding tests * Adding a new user to the test data had surprising consequences... --- .../notification_webhooks/engagement_added.md | 10 ++++++- .../open_source/notification_webhooks/ping.md | 10 ++++++- .../notification_webhooks/product_added.md | 10 ++++++- .../product_type_added.md | 10 ++++++- .../notification_webhooks/scan_added.md | 10 ++++++- .../notification_webhooks/test_added.md | 10 ++++++- dojo/fixtures/dojo_testdata.json | 8 +++--- .../webhooks/subtemplates/base.tpl | 2 +- .../webhooks/subtemplates/user.tpl | 16 +++++++++++ unittests/test_notifications.py | 27 +++++++++++++++++++ 10 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 dojo/templates/notifications/webhooks/subtemplates/user.tpl diff --git a/docs/content/en/open_source/notification_webhooks/engagement_added.md b/docs/content/en/open_source/notification_webhooks/engagement_added.md index c4129005c46..2a782999034 100644 --- a/docs/content/en/open_source/notification_webhooks/engagement_added.md +++ b/docs/content/en/open_source/notification_webhooks/engagement_added.md @@ -34,6 +34,14 @@ X-DefectDojo-Event: engagement_added }, "url_api": "http://localhost:8080/api/v2/engagements/7/", "url_ui": "http://localhost:8080/engagement/7", - "user": null + "user": { + "id": 1, + "email": "admin@defectdojo.local", + "first_name": "Admin", + "last_name": "User", + "username": "admin", + "url_api": "http://localhost:8080/api/v2/users/1/", + "url_ui": "http://localhost:8080/user/1" + } } ``` diff --git a/docs/content/en/open_source/notification_webhooks/ping.md b/docs/content/en/open_source/notification_webhooks/ping.md index aba1de25979..fcd1e9f93ae 100644 --- a/docs/content/en/open_source/notification_webhooks/ping.md +++ b/docs/content/en/open_source/notification_webhooks/ping.md @@ -17,6 +17,14 @@ X-DefectDojo-Event: ping { "description": "Test webhook notification", "title": "", - "user": null, + "user": { + "id": 1, + "email": "admin@defectdojo.local", + "first_name": "Admin", + "last_name": "User", + "username": "admin", + "url_api": "http://localhost:8080/api/v2/users/1/", + "url_ui": "http://localhost:8080/user/1" + }, } ``` diff --git a/docs/content/en/open_source/notification_webhooks/product_added.md b/docs/content/en/open_source/notification_webhooks/product_added.md index 1839ab6efb2..0291fc56b07 100644 --- a/docs/content/en/open_source/notification_webhooks/product_added.md +++ b/docs/content/en/open_source/notification_webhooks/product_added.md @@ -29,6 +29,14 @@ X-DefectDojo-Event: product_added }, "url_api": "http://localhost:8080/api/v2/products/4/", "url_ui": "http://localhost:8080/product/4", - "user": null + "user": { + "id": 1, + "email": "admin@defectdojo.local", + "first_name": "Admin", + "last_name": "User", + "username": "admin", + "url_api": "http://localhost:8080/api/v2/users/1/", + "url_ui": "http://localhost:8080/user/1" + } } ``` diff --git a/docs/content/en/open_source/notification_webhooks/product_type_added.md b/docs/content/en/open_source/notification_webhooks/product_type_added.md index 079b39115f0..5f76658a29b 100644 --- a/docs/content/en/open_source/notification_webhooks/product_type_added.md +++ b/docs/content/en/open_source/notification_webhooks/product_type_added.md @@ -23,6 +23,14 @@ X-DefectDojo-Event: product_type_added }, "url_api": "http://localhost:8080/api/v2/product_types/4/", "url_ui": "http://localhost:8080/product/type/4", - "user": null + "user": { + "id": 1, + "email": "admin@defectdojo.local", + "first_name": "Admin", + "last_name": "User", + "username": "admin", + "url_api": "http://localhost:8080/api/v2/users/1/", + "url_ui": "http://localhost:8080/user/1" + } } ``` diff --git a/docs/content/en/open_source/notification_webhooks/scan_added.md b/docs/content/en/open_source/notification_webhooks/scan_added.md index 70a5d804c06..ea9dae28c40 100644 --- a/docs/content/en/open_source/notification_webhooks/scan_added.md +++ b/docs/content/en/open_source/notification_webhooks/scan_added.md @@ -87,6 +87,14 @@ X-DefectDojo-Event: scan_added_empty }, "url_api": "http://localhost:8080/api/v2/tests/90/", "url_ui": "http://localhost:8080/test/90", - "user": null + "user": { + "id": 1, + "email": "admin@defectdojo.local", + "first_name": "Admin", + "last_name": "User", + "username": "admin", + "url_api": "http://localhost:8080/api/v2/users/1/", + "url_ui": "http://localhost:8080/user/1" + } } ``` diff --git a/docs/content/en/open_source/notification_webhooks/test_added.md b/docs/content/en/open_source/notification_webhooks/test_added.md index cf7d676726a..f3b44a8a9a4 100644 --- a/docs/content/en/open_source/notification_webhooks/test_added.md +++ b/docs/content/en/open_source/notification_webhooks/test_added.md @@ -41,6 +41,14 @@ X-DefectDojo-Event: test_added }, "url_api": "http://localhost:8080/api/v2/tests/90/", "url_ui": "http://localhost:8080/test/90", - "user": null + "user": { + "id": 1, + "email": "admin@defectdojo.local", + "first_name": "Admin", + "last_name": "User", + "username": "admin", + "url_api": "http://localhost:8080/api/v2/users/1/", + "url_ui": "http://localhost:8080/user/1" + } } ``` diff --git a/dojo/fixtures/dojo_testdata.json b/dojo/fixtures/dojo_testdata.json index b8b6e192815..92d3ec0bb20 100644 --- a/dojo/fixtures/dojo_testdata.json +++ b/dojo/fixtures/dojo_testdata.json @@ -94,8 +94,8 @@ "model": "auth.user", "fields": { "username": "user5", - "first_name": "", - "last_name": "", + "first_name": "User", + "last_name": "Five", "is_active": true, "is_superuser": false, "is_staff": false, @@ -108,7 +108,7 @@ 28 ], "password": "pbkdf2_sha256$36000$pe8Ff8HrBPac$Lb3ee6/R9z/aL9nM+D2AXWTpIt9Pa9kcLueXxYNy1ZY=", - "email": "", + "email": "user5@email.com", "date_joined": "2018-04-13T07:59:51.527Z" } }, @@ -3070,7 +3070,7 @@ "first_error": null, "last_error": null, "note": null, - "owner": 2 + "owner": 6 } } ] \ No newline at end of file diff --git a/dojo/templates/notifications/webhooks/subtemplates/base.tpl b/dojo/templates/notifications/webhooks/subtemplates/base.tpl index aad0892655b..8f810747b48 100644 --- a/dojo/templates/notifications/webhooks/subtemplates/base.tpl +++ b/dojo/templates/notifications/webhooks/subtemplates/base.tpl @@ -3,7 +3,7 @@ --- description: {{ description | as_json_no_html_esc }} title: {{ title | as_json_no_html_esc }} -user: {{ user | as_json_no_html_esc }} +{% include 'notifications/webhooks/subtemplates/user.tpl' %} {% if url %} url_ui: {{ url | full_url | as_json_no_html_esc }} {% endif %} diff --git a/dojo/templates/notifications/webhooks/subtemplates/user.tpl b/dojo/templates/notifications/webhooks/subtemplates/user.tpl new file mode 100644 index 00000000000..2128433b1e4 --- /dev/null +++ b/dojo/templates/notifications/webhooks/subtemplates/user.tpl @@ -0,0 +1,16 @@ +{% load display_tags %} +{% load as_json %} +{% if user %} +{% url 'view_user' user.id as user_url_ui %} +{% url 'user-detail' user.id as user_url_api %} +user: + id: {{ user.pk }} + email: {{ user.email | as_json_no_html_esc }} + username: {{ user.username | as_json_no_html_esc }} + first_name: {{ user.first_name | as_json_no_html_esc }} + last_name: {{ user.last_name | as_json_no_html_esc }} + url_ui: {{ user_url_ui | full_url | as_json_no_html_esc }} + url_api: {{ user_url_api | full_url | as_json_no_html_esc }} +{% else %} +user: {{ user | as_json_no_html_esc }} +{% endif %} diff --git a/unittests/test_notifications.py b/unittests/test_notifications.py index b66fcc54c24..b3e22747194 100644 --- a/unittests/test_notifications.py +++ b/unittests/test_notifications.py @@ -976,3 +976,30 @@ def test_events_messages(self, mock): "url_ui": "http://localhost:8080/finding/239", }], }) + + @patch("requests.request", **{"return_value.status_code": 200}) + def test_ping_with_owner_assigned(self, mock): + """ + We only need to test one event because the user is serialized in the base sub template. This allows to] + assert that if the test passes for one event, it will pass for all events. + """ + manager = WebhookNotificationManger() + manager._test_webhooks_notification(Notification_Webhooks.objects.filter(owner__isnull=False).first()) + self.assertEqual(mock.call_args.kwargs["headers"]["X-DefectDojo-Event"], "ping") + self.maxDiff = None + self.assertEqual( + mock.call_args.kwargs["json"], + { + "description": "Test webhook notification", + "title": "", + "user": { + "id": 6, + "username": "user5", + "first_name": "User", + "last_name": "Five", + "email": "user5@email.com", + "url_api": "http://localhost:8080/api/v2/users/6/", + "url_ui": "http://localhost:8080/user/6", + }, + }, + ) From 6e38ffa2b1848e6428bc4d1a170154a2192d7afc Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Fri, 8 Aug 2025 19:04:56 -0500 Subject: [PATCH 05/12] Display Tags: Do not rely on the request object being present (#12939) --- dojo/templatetags/display_tags.py | 3 +++ dojo/templatetags/navigation_tags.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/dojo/templatetags/display_tags.py b/dojo/templatetags/display_tags.py index 01a38e70b0a..525e4065b03 100644 --- a/dojo/templatetags/display_tags.py +++ b/dojo/templatetags/display_tags.py @@ -343,6 +343,9 @@ def action_log_entry(value, autoescape=None): @register.simple_tag(takes_context=True) def dojo_body_class(context): + if "request" not in context: + return "" + request = context["request"] return request.COOKIES.get("dojo-sidebar", "min") diff --git a/dojo/templatetags/navigation_tags.py b/dojo/templatetags/navigation_tags.py index 3da215bc88d..57a23f6d89e 100644 --- a/dojo/templatetags/navigation_tags.py +++ b/dojo/templatetags/navigation_tags.py @@ -11,6 +11,9 @@ @register.simple_tag(takes_context=True) def query_string_as_hidden(context): + if "request" not in context: + return "" + request = context["request"] query_string = request.META["QUERY_STRING"] inputs = "" From 30b7e21cb2cebf38f39ee6d47d3110b0325fadf8 Mon Sep 17 00:00:00 2001 From: valentijnscholten Date: Sat, 9 Aug 2025 02:06:43 +0200 Subject: [PATCH 06/12] new snyk_issue_api parser for `code` issues (file based) (#12903) * snyk_issue_api: support code items * make fix_available backward compatible --- .../parsers/file/snyk_issue_api.md | 63 +++++ dojo/tools/snyk_issue_api/__init__.py | 0 dojo/tools/snyk_issue_api/parser.py | 180 ++++++++++++ unittests/scans/snyk_issue_api/empty.json | 6 + .../snyk_code_scan_api_many_vuln.json | 266 ++++++++++++++++++ unittests/tools/test_snyk_issue_api_parser.py | 59 ++++ 6 files changed, 574 insertions(+) create mode 100644 docs/content/en/connecting_your_tools/parsers/file/snyk_issue_api.md create mode 100644 dojo/tools/snyk_issue_api/__init__.py create mode 100644 dojo/tools/snyk_issue_api/parser.py create mode 100644 unittests/scans/snyk_issue_api/empty.json create mode 100644 unittests/scans/snyk_issue_api/snyk_code_scan_api_many_vuln.json create mode 100644 unittests/tools/test_snyk_issue_api_parser.py diff --git a/docs/content/en/connecting_your_tools/parsers/file/snyk_issue_api.md b/docs/content/en/connecting_your_tools/parsers/file/snyk_issue_api.md new file mode 100644 index 00000000000..6de9cd61f94 --- /dev/null +++ b/docs/content/en/connecting_your_tools/parsers/file/snyk_issue_api.md @@ -0,0 +1,63 @@ +--- +title: "Snyk Issue API" +toc_hide: true +--- +The Snyk Issue API parser supports importing vulnerability data from the Snyk Issue API in JSON format. Currently only parsing issues of type `code` is supported. Samples of ther issue types are welcome. + +For more information about the Snyk Issue API, refer to the [official Snyk API documentation](https://docs.snyk.io/snyk-api/reference/issues#get-orgs-org_id-issues). + +### API request +Example API request to get only code issues: +``` +GET https://api.snyk.io/rest/orgs/{org_id}/issues?version=2025-08-02&type=code +``` + +For more details see: https://docs.snyk.io/snyk-api/reference/issues#get-orgs-org_id-issues + +### Sample Scan Data +Sample Snyk Issue API scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/snyk_issue_api). + +### Field Mapping +The parser maps fields from the Snyk Issue API response to DefectDojo's Finding model as follows: + +| Finding Field | Snyk Issue API Field | Notes | +|--------------|---------------------|-------| +| title | attributes.title | | +| severity | attributes.effective_severity_level | Mapped to Critical/High/Medium/Low/Info | +| description | attributes.description | | +| unique_id_from_tool | id | Top-level issue ID | +| file_path | coordinates[].representations[].sourceLocation.file | First occurrence | +| line | coordinates[].representations[].sourceLocation.region.start.line | Line where the issue starts | +| date | attributes.created_at | ISO format date | +| cwe | classes[].id | First CWE class found | +| active | attributes.status == "open" AND NOT attributes.ignored | Inactive if ignored or not open | +| verified | true | Always set to true | +| static_finding | true | Always set to true | +| dynamic_finding | false | Always set to false | +| out_of_scope | attributes.ignored | Set to true if issue is ignored | +| fix_available* | coordinates[].is_fixable_* | True if any fixability flag is true. | + +#### Impact Field +The impact field combines multiple pieces of information: +1. Problem details: + - Source (e.g., "SNYK") + - Type (e.g., "vulnerability") + - Last update timestamp + - Severity level +2. All source locations, each containing: + - File path + - Commit ID + - Line range (start-end) + - Column range (start-end) + +#### Additional Processing +- Multiple CWEs are handled by using the first one as the primary CWE and listing additional ones in the references field +- Risk scores are included in the severity_justification field when available +- Only issues with type="code" are processed +- Line numbers: Only the starting line is stored in the Finding model, but both start and end lines are included in the impact field for reference + +### Default Deduplication Hashcode Fields +By default, DefectDojo identifies duplicate Findings using these [hashcode fields](https://docs.defectdojo.com/en/working_with_findings/finding_deduplication/about_deduplication/): + +- unique id from tool +- file path \ No newline at end of file diff --git a/dojo/tools/snyk_issue_api/__init__.py b/dojo/tools/snyk_issue_api/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dojo/tools/snyk_issue_api/parser.py b/dojo/tools/snyk_issue_api/parser.py new file mode 100644 index 00000000000..a8e24e5ae8c --- /dev/null +++ b/dojo/tools/snyk_issue_api/parser.py @@ -0,0 +1,180 @@ +import json +from contextlib import suppress +from datetime import datetime + +from dojo.models import Finding + + +class SnykIssueApiParser: + def get_scan_types(self): + return ["Snyk Issue API Scan"] + + def get_label_for_scan_types(self, scan_type): + return scan_type + + def get_description_for_scan_types(self, scan_type): + return "Snyk Issue API output file can be imported in JSON format." + + def get_findings(self, json_output, test): + tree = self.parse_json(json_output) + return self.process_tree(tree, test) + + def parse_json(self, json_output): + try: + data = json_output.read() + try: + tree = json.loads(str(data, "utf-8")) + except Exception: + tree = json.loads(data) + except Exception: + msg = "Invalid format" + raise ValueError(msg) + + return tree + + def process_tree(self, tree, test): + if not tree or "data" not in tree: + return [] + + findings = [] + for issue in tree.get("data", []): + finding = self.get_finding(issue, test) + if finding: + findings.append(finding) + return findings + + def get_finding(self, issue, test): + # Check top-level type must be "issue" as "packages" have their own API it seems. + if not issue or issue.get("type") != "issue": + return None + + attributes = issue.get("attributes", {}) + + # Check attributes-level type must be "code" + # Other items are not supported yet due to a lack of samples and lack of documentation + # package_vulnerability,license,cloud,code,customconfig + if attributes.get("type") != "code": + return None + + # Extract CWE classes + cwes = [] + for class_info in attributes.get("classes", []): + if class_info.get("source") == "CWE": + cwe_id = class_info.get("id", "").replace("CWE-", "") + if cwe_id.isdigit(): + cwes.append(int(cwe_id)) + + # Extract location information, fixability and collect all source locations for impact + file_path = None + line = None + fix_available = False + impact_locations = [] + + for coordinate in attributes.get("coordinates", []): + # Check if any fix is available + if coordinate.get("is_fixable_snyk") or \ + coordinate.get("is_fixable_upstream") or \ + coordinate.get("is_fixable_manually"): + fix_available = True + + for representation in coordinate.get("representations", []): + if "sourceLocation" in representation: + location = representation["sourceLocation"] + region = location.get("region", {}) + start = region.get("start", {}) + end = region.get("end", {}) + + # Store location details for impact field + impact_locations.append([ + "Source Location:", + f"File: {location.get('file', 'Unknown')}", + f"Commit: {location.get('commit_id', 'Unknown')}", + f"Lines: {start.get('line', '?')}-{end.get('line', '?')}", + f"Columns: {start.get('column', '?')}-{end.get('column', '?')}", + "", # Empty line between locations + ]) + + # Store first location for finding fields + if not file_path: + file_path = location.get("file") + if region: + line = start.get("line") + + # Map severity levels + severity_map = { + "critical": "Critical", + "high": "High", + "medium": "Medium", + "low": "Low", + "info": "Info", + } + severity = severity_map.get(attributes.get("effective_severity_level", "").lower(), "Info") + + # Parse created_at date + created = None + if attributes.get("created_at"): + with suppress(ValueError): + created = datetime.strptime(attributes["created_at"], "%Y-%m-%dT%H:%M:%S.%fZ") + if not created: + with suppress(ValueError): + created = datetime.strptime(attributes["created_at"], "%Y-%m-%dT%H:%M:%SZ") + + # Create finding + finding = Finding( + title=attributes.get("title", ""), + test=test, + severity=severity, + description=attributes.get("description", ""), + static_finding=True, + dynamic_finding=False, + unique_id_from_tool=issue.get("id"), + file_path=file_path, + line=line, + out_of_scope=attributes.get("ignored", False), + active=attributes.get("status") == "open" and not attributes.get("ignored", False), + verified=True, + cwe=cwes[0] if cwes else None, + date=created, + ) + + # Set fix_available if the field exists in the model + if hasattr(finding, "fix_available"): + finding.fix_available = fix_available + + # Add risk score if available + risk = attributes.get("risk", {}) + if risk and "score" in risk: + score = risk["score"] + if isinstance(score, dict): + finding.severity_justification = ( + f"Risk Score: {score.get('value', 'N/A')} " + f"(Model: {score.get('model', 'N/A')})" + ) + + # Add additional CWEs as references + if len(cwes) > 1: + finding.references = "Additional CWEs: " + ", ".join(f"CWE-{cwe}" for cwe in cwes[1:]) + + # Add problem details and all source locations to impact + impact_details = [] + + # Add problem information + problems = attributes.get("problems", []) + if problems: + problem = problems[0] # Take the first problem + impact_details.extend([ + f"Source: {problem.get('source', 'Unknown')}", + f"Type: {problem.get('type', 'Unknown')}", + f"Last Updated: {problem.get('updated_at', 'Unknown')}", + f"Severity: {severity}", + "", # Empty line before locations + ]) + + # Add all source locations + for location in impact_locations: + impact_details.extend(location) + + if impact_details: + finding.impact = "\n".join(impact_details).rstrip() + + return finding diff --git a/unittests/scans/snyk_issue_api/empty.json b/unittests/scans/snyk_issue_api/empty.json new file mode 100644 index 00000000000..e6b11fc0300 --- /dev/null +++ b/unittests/scans/snyk_issue_api/empty.json @@ -0,0 +1,6 @@ +{ + "jsonapi": { + "version": "1.0" + }, + "data": [] +} \ No newline at end of file diff --git a/unittests/scans/snyk_issue_api/snyk_code_scan_api_many_vuln.json b/unittests/scans/snyk_issue_api/snyk_code_scan_api_many_vuln.json new file mode 100644 index 00000000000..a032603dec3 --- /dev/null +++ b/unittests/scans/snyk_issue_api/snyk_code_scan_api_many_vuln.json @@ -0,0 +1,266 @@ +{ + "jsonapi": { + "version": "1.0" + }, + "links": { + "self": "/rest/orgs/str123/issues?limit=10&scan_item.id=25502d3a-2799-4e20-97d6-2cb552058894&scan_item.type=project&version=2024-10-15", + "first": "/rest/orgs/str123/issues?limit=10&scan_item.id=25502d3a-2799-4e20-97d6-2cb552058894&scan_item.type=project&version=2024-10-15", + "last": "/rest/orgs/str123/issues?ending_before=end&limit=10&scan_item.id=25502d3a-2799-4e20-97d6-2cb552058894&scan_item.type=project&version=2024-10-15" + }, + "data": [ + { + "id": "3916a413-2fca-45c9-a1bf-a1373258fe69", + "type": "issue", + "attributes": { + "classes": [ + { + "id": "CWE-352", + "source": "CWE", + "type": "weakness" + } + ], + "coordinates": [ + { + "is_fixable_manually": false, + "is_fixable_snyk": false, + "is_fixable_upstream": false, + "representations": [ + { + "sourceLocation": { + "commit_id": "5ab48c7da75182753420725182db92b679c1e4f0", + "file": "path/path/file.abc", + "region": { + "end": { + "column": 22, + "line": 71 + }, + "start": { + "column": 9, + "line": 65 + } + } + } + } + ] + } + ], + "created_at": "2024-12-13T12:29:59.035Z", + "description": "Cross-Site Request Forgery (CSRF)", + "effective_severity_level": "high", + "ignored": false, + "key": "9a29d87f-aa94-47eb-b46f-375b293a8631", + "key_asset": "4312279e-39d9-463d-b684-3a10059058f6", + "problems": [ + { + "id": "9a29d87f-aa94-47eb-b46f-375b293a8631", + "source": "SNYK", + "type": "vulnerability", + "updated_at": "2025-04-13T04:13:03.151452Z" + } + ], + "risk": { + "factors": [], + "score": { + "model": "v1", + "value": 829 + } + }, + "status": "open", + "title": "Cross-Site Request Forgery (CSRF)", + "type": "code", + "updated_at": "2025-03-08T01:31:31.667Z" + }, + "relationships": { + "organization": { + "data": { + "id": "str123", + "type": "organization" + }, + "links": { + "related": "/orgs/str123" + } + }, + "scan_item": { + "data": { + "id": "25502d3a-2799-4e20-97d6-2cb552058894", + "type": "project" + }, + "links": { + "related": "/orgs/str123/projects/25502d3a-2799-4e20-97d6-2cb552058894" + } + } + } + }, + { + "id": "605a2477-69d4-4317-8649-1f7b92fa7c27", + "type": "issue", + "attributes": { + "classes": [ + { + "id": "CWE-79", + "source": "CWE", + "type": "weakness" + } + ], + "coordinates": [ + { + "is_fixable_manually": false, + "is_fixable_snyk": false, + "is_fixable_upstream": false, + "representations": [ + { + "sourceLocation": { + "commit_id": "pab48c7da7t682753420725182db92b6k9c1e4f0", + "file": "path/path/file.abc", + "region": { + "end": { + "column": 90, + "line": 27 + }, + "start": { + "column": 61, + "line": 27 + } + } + } + } + ] + } + ], + "created_at": "2024-12-13T12:29:59.035Z", + "description": "Cross-site Scripting (XSS)", + "effective_severity_level": "medium", + "ignored": true, + "key": "b25fb1d7-c99b-46fb-818b-e94971ee9db0", + "key_asset": "081e6cf8-4249-4cbb-ae2f-0e3cdafba0cd", + "problems": [ + { + "id": "b25fb1d7-c99b-46fb-818b-e94971ee9db0", + "source": "SNYK", + "type": "vulnerability", + "updated_at": "2025-05-10T01:45:25.464473Z" + } + ], + "risk": { + "factors": [], + "score": { + "model": "v1", + "value": 579 + } + }, + "status": "open", + "title": "Cross-site Scripting (XSS)", + "type": "code", + "updated_at": "2025-05-10T01:45:23.452Z" + }, + "relationships": { + "organization": { + "data": { + "id": "str123", + "type": "organization" + }, + "links": { + "related": "/orgs/str123" + } + }, + "scan_item": { + "data": { + "id": "25502d3a-2799-4e20-97d6-2cb552058894", + "type": "project" + }, + "links": { + "related": "/orgs/str123/projects/25502d3a-2799-4e20-97d6-2cb552058894" + } + } + } + }, + { + "id": "922e2d65-d2ce-4a5c-818c-ab196ba834c3", + "type": "issue", + "attributes": { + "classes": [ + { + "id": "CWE-259", + "source": "CWE", + "type": "weakness" + }, + { + "id": "CWE-798", + "source": "CWE", + "type": "weakness" + } + ], + "coordinates": [ + { + "is_fixable_manually": false, + "is_fixable_snyk": false, + "is_fixable_upstream": false, + "representations": [ + { + "sourceLocation": { + "commit_id": "5ab48c7da75182753420725182db92b679c1e4f0", + "file": "path/path/file.abc", + "region": { + "end": { + "column": 41, + "line": 94 + }, + "start": { + "column": 33, + "line": 94 + } + } + } + } + ] + } + ], + "created_at": "2024-12-13T12:29:59.035Z", + "description": "Use of Hardcoded Passwords", + "effective_severity_level": "low", + "ignored": false, + "key": "a8edd3ae-722f-4668-81da-478b46fdf961", + "key_asset": "1dc3c841-be59-4889-a88f-a9ad10bbcd98", + "problems": [ + { + "id": "a8edd3ae-722f-4668-81da-478b46fdf961", + "source": "SNYK", + "type": "vulnerability", + "updated_at": "2025-05-31T01:32:18.84232Z" + } + ], + "risk": { + "factors": [], + "score": { + "model": "v1", + "value": 379 + } + }, + "status": "open", + "title": "Use of Hardcoded Passwords", + "type": "code", + "updated_at": "2025-05-31T01:32:17.121Z" + }, + "relationships": { + "organization": { + "data": { + "id": "str123", + "type": "organization" + }, + "links": { + "related": "/orgs/str123" + } + }, + "scan_item": { + "data": { + "id": "25502d3a-2799-4e20-97d6-2cb552058894", + "type": "project" + }, + "links": { + "related": "/orgs/str123/projects/25502d3a-2799-4e20-97d6-2cb552058894" + } + } + } + } + ] +} \ No newline at end of file diff --git a/unittests/tools/test_snyk_issue_api_parser.py b/unittests/tools/test_snyk_issue_api_parser.py new file mode 100644 index 00000000000..bd7dd8fa094 --- /dev/null +++ b/unittests/tools/test_snyk_issue_api_parser.py @@ -0,0 +1,59 @@ +from pathlib import Path + +from django.test import TestCase + +from dojo.models import Test +from dojo.tools.snyk_issue_api.parser import SnykIssueApiParser + + +class TestSnykIssueApiParser(TestCase): + def test_parse_no_findings(self): + with Path("unittests/scans/snyk_issue_api/empty.json").open(encoding="utf-8") as testfile: + parser = SnykIssueApiParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(0, len(findings)) + + def test_parse_many_findings(self): + with Path("unittests/scans/snyk_issue_api/snyk_code_scan_api_many_vuln.json").open(encoding="utf-8") as testfile: + parser = SnykIssueApiParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(3, len(findings)) + + # Verify first finding + finding = findings[0] + self.assertEqual("Cross-Site Request Forgery (CSRF)", finding.title) + self.assertEqual("High", finding.severity) + self.assertEqual("Cross-Site Request Forgery (CSRF)", finding.description) + self.assertEqual("path/path/file.abc", finding.file_path) + self.assertEqual(65, finding.line) + self.assertEqual(352, finding.cwe) + self.assertEqual("3916a413-2fca-45c9-a1bf-a1373258fe69", finding.unique_id_from_tool) + self.assertEqual(False, finding.false_p) + self.assertEqual(True, finding.active) + self.assertEqual(True, finding.verified) + self.assertEqual(True, finding.static_finding) + self.assertEqual(False, finding.dynamic_finding) + self.assertIn("Risk Score: 829", finding.severity_justification) + # Check fix_available if the field exists + if hasattr(finding, "fix_available"): + self.assertEqual(False, finding.fix_available) + + # Verify second finding + finding = findings[1] + self.assertEqual("Cross-site Scripting (XSS)", finding.title) + self.assertEqual("Medium", finding.severity) + self.assertEqual(79, finding.cwe) + self.assertEqual(True, finding.out_of_scope) # This one is ignored + # Check fix_available if the field exists + if hasattr(finding, "fix_available"): + self.assertEqual(False, finding.fix_available) + + # Verify third finding + finding = findings[2] + self.assertEqual("Use of Hardcoded Passwords", finding.title) + self.assertEqual("Low", finding.severity) + self.assertEqual(259, finding.cwe) + self.assertEqual("Additional CWEs: CWE-798", finding.references) # Has multiple CWEs + # Check fix_available if the field exists + if hasattr(finding, "fix_available"): + self.assertEqual(False, finding.fix_available) From ce05b7192e714a30956b7e1b8a6a0b0f8346fc02 Mon Sep 17 00:00:00 2001 From: valentijnscholten Date: Sat, 9 Aug 2025 06:44:11 +0200 Subject: [PATCH 07/12] fix async stuff in perf test (#12901) --- dojo/importers/default_reimporter.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dojo/importers/default_reimporter.py b/dojo/importers/default_reimporter.py index 694bd8bc4e8..4fd9065af90 100644 --- a/dojo/importers/default_reimporter.py +++ b/dojo/importers/default_reimporter.py @@ -453,7 +453,7 @@ def process_matched_mitigated_finding( "have different dates, not taking action" ) logger.debug(msg) - # Return True here to force the loop to continue + # Return True here to force the loop to continue to the next finding return existing_finding, True # even if there is no mitigation time, skip it, because both the current finding and # the reimported finding are is_mitigated @@ -480,8 +480,7 @@ def process_matched_mitigated_finding( ) note.save() existing_finding.notes.add(note) - existing_finding.save_no_options() - # Return True here to force the loop to continue + # Return True here to force the loop to continue to the next finding return existing_finding, True logger.debug( f"Reactivating: - {existing_finding.id}: {existing_finding.title} " From 33f6e36fc847a8154707be312c56fd0adab1c8c3 Mon Sep 17 00:00:00 2001 From: valentijnscholten Date: Sat, 9 Aug 2025 06:58:13 +0200 Subject: [PATCH 08/12] restore entrypoint-unit-tests-devDocker.sh (#12904) --- docker/entrypoint-unit-tests-devDocker.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docker/entrypoint-unit-tests-devDocker.sh b/docker/entrypoint-unit-tests-devDocker.sh index ec2810cd545..7a01f6cd199 100755 --- a/docker/entrypoint-unit-tests-devDocker.sh +++ b/docker/entrypoint-unit-tests-devDocker.sh @@ -73,15 +73,15 @@ echo "Unit Tests" echo "------------------------------------------------------------" # Removing parallel and shuffle for now to maintain stability -# python3 manage.py test unittests -v 3 --keepdb --no-input --exclude-tag="non-parallel" || { -# exit 1; -# } -# python3 manage.py test unittests -v 3 --keepdb --no-input --tag="non-parallel" || { -# exit 1; -# } +python3 manage.py test unittests -v 3 --keepdb --no-input --exclude-tag="non-parallel" || { + exit 1; +} +python3 manage.py test unittests -v 3 --keepdb --no-input --tag="non-parallel" || { + exit 1; +} # you can select a single file to "test" unit tests -python3 manage.py test unittests.test_importers_performance.TestDojoImporterPerformance --keepdb -v 3 &> /app/dev2.log +# python3 manage.py test unittests.test_importers_performance.TestDojoImporterPerformance --keepdb -v 3 &> /app/dev2.log # or even a single method # python3 manage.py test unittests.tools.test_npm_audit_scan_parser.TestNpmAuditParser.test_npm_audit_parser_many_vuln_npm7 --keepdb -v 3 From a2bb109a3b9e62cd727b310ae4aaeda4fc03c410 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Sat, 9 Aug 2025 07:16:44 +0200 Subject: [PATCH 09/12] Enable ipv6 in nginx (if available) (#12938) * Revert "Feat(nginx): Add support for IPv6" This reverts commit e9d987206cd747b76df89605e9bf8108e8abdfc4. * Feat(nginx): Add support for IPv6 * proper handling non-IPv6 hosts --- docker/entrypoint-nginx.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/entrypoint-nginx.sh b/docker/entrypoint-nginx.sh index 375aba6c04b..d426d79499e 100755 --- a/docker/entrypoint-nginx.sh +++ b/docker/entrypoint-nginx.sh @@ -20,6 +20,10 @@ else NGINX_CONFIG="/etc/nginx/nginx.conf" fi +if ! ip -6 addr show dev lo | grep -q 'inet6 ::1'; then + sed -i '/listen \[::\]:/d' "$NGINX_CONFIG" +fi + if [ "${NGINX_METRICS_ENABLED}" = true ]; then sed -i "s/#stub_status/stub_status/g;" $NGINX_CONFIG echo "Nginx metrics are enabled" From 0ca79ab90b6b34a35c5226a3fdb95bfcf5690b31 Mon Sep 17 00:00:00 2001 From: ThiagoCruzBr Date: Sat, 9 Aug 2025 02:23:37 -0300 Subject: [PATCH 10/12] ADD: Alternative command to change password (#12931) Alternative command useful for automation. --- readme-docs/DOCKER.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme-docs/DOCKER.md b/readme-docs/DOCKER.md index 2510bcd5984..30ebdaa57c2 100644 --- a/readme-docs/DOCKER.md +++ b/readme-docs/DOCKER.md @@ -152,6 +152,11 @@ Make sure you write down the first password generated as you'll need it when re- docker compose exec -it uwsgi ./manage.py changepassword admin ``` +Alternatively, you can run the command below to change the admin password in a single command. Useful for automation. +```zsh +docker compose exec uwsgi ./manage.py shell -c 'from django.contrib.auth.models import User; u = User.objects.get(username="admin"); u.set_password("Password123!"); u.save()' +``` + # Logging For docker compose release mode the log level is INFO. In the other modes the log level is DEBUG. Logging is configured in `settings.dist.py` and can be tuned using a `local_settings.py`, see [template for local_settings.py](../dojo/settings/template-local_settings)). For example the deduplication logger can be set to DEBUG in a local_settings.py file: From 1980c5280ba272978d889fd450038a1f6a92f412 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Mon, 11 Aug 2025 09:29:41 -0500 Subject: [PATCH 11/12] Documentation: Guide to testing hugo pipeline locally (#12959) * Documentation: Guide to testing hugo pipeline locally * Forgot I was on an a newer version of hugo --- README.md | 1 + docs/README.md | 64 +++++++++++++++++ docs/assets/scss/app.scss | 80 ++++++++++----------- docs/config/development/hugo.toml | 2 + docs/config/production/hugo.toml | 3 +- docs/layouts/partials/head/custom-head.html | 5 ++ docs/package-lock.json | 2 + docs/package.json | 4 +- 8 files changed, 117 insertions(+), 44 deletions(-) create mode 100644 docs/README.md create mode 100644 docs/config/development/hugo.toml diff --git a/README.md b/README.md index 5b14aa455e6..ef3389e6ec2 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ Navigate to `http://localhost:8080` to see your new instance! * [OAuth2/SAML2](https://docs.defectdojo.com/en/open_source/archived_docs/integrations/social-authentication/) * [LDAP](https://docs.defectdojo.com/en/open_source/ldap-authentication/) * [Supported tools](https://docs.defectdojo.com/en/connecting_your_tools/parsers/) +* [How to Write Documentation Locally](/docs/README.md) ## Supported Installation Options diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..9f3087d8f13 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,64 @@ +# Guide to Writing Documentation + +When developing documentation, there are steps to take before submitting a pull request + +1. Writing your documentation with [hot reloading](#development-with-hot-reloading) live in your browser +2. Verifying your changes with a [production build](#mimic-production-environment) to ensure Hugo will minify everything correctly + +## Development with Hot Reloading + +This method performs the following from the `django-DefectDojo/docs` directory: + +1. Remove any existing packages to perform a fresh install each time: `rm -rf public node_modules` +2. Install all packages: `npm install` +3. Start the server: `npm run dev` +4. Access the [site in the browser at http://localhost:1313](http://localhost:1313) + +### Execution List + +```bash +rm -rf public node_modules +npm install +npm run dev +``` + +or for a one liner: + +```bash +rm -rf public node_modules && \ +npm install && \ +npm run dev +``` + +## Mimic Production Environment + +This method performs the following from the `django-DefectDojo/docs` directory: + +1. Remove any existing packages to perform a fresh install each time: `rm -rf public node_modules` +2. Install all packages in CI mode to only install from `package-lock.json`: `npm ci` +3. Run Hugo to build the site in the way the CI job does, but in development environment to point at `localhost` for integrity checks : `npm run build -- --environment development` +4. Change directory to the new `public` directory to run the site locally: `cd public` +5. Run a light weight webserver to server the files, and [access the site at http://localhost:8080](http://localhost:8080): `python3 -m http.server 8080` +6. After killing the webserver process, navigate back to the `django-DefectDojo/docs` directory: `cd ../` + +### Execution List + +```bash +rm -rf public node_modules +npm ci +npm run build -- --environment development +cd public +python3 -m http.server 8080 +cd ../ +``` + +or for a one liner: + +```bash +rm -rf public node_modules && \ +npm ci && \ +npm run build -- --environment development && \ +cd public && \ +python3 -m http.server 8080 && \ +cd ../ +``` diff --git a/docs/assets/scss/app.scss b/docs/assets/scss/app.scss index 61835f6d106..53c25405329 100644 --- a/docs/assets/scss/app.scss +++ b/docs/assets/scss/app.scss @@ -1,7 +1,7 @@ // Source: https://getbootstrap.com/docs/5.3/customize/sass/#importing // 1. Include functions first (so you can manipulate colors, SVGs, calc, etc) -@import "bootstrap/scss/functions"; +@import "node_modules/bootstrap/scss/functions"; // 2. Include any default variable overrides here @import "common/colors"; @@ -9,54 +9,54 @@ @import "common/variables-custom"; // 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets) -@import "bootstrap/scss/variables"; -@import "bootstrap/scss/variables-dark"; +@import "node_modules/bootstrap/scss/variables"; +@import "node_modules/bootstrap/scss/variables-dark"; // 4. Include any default map overrides here // 5. Include remainder of required parts -@import "bootstrap/scss/maps"; -@import "bootstrap/scss/mixins"; -@import "bootstrap/scss/root"; +@import "node_modules/bootstrap/scss/maps"; +@import "node_modules/bootstrap/scss/mixins"; +@import "node_modules/bootstrap/scss/root"; // 6. Optionally include any other parts as needed // Layout & components -@import "bootstrap/scss/utilities"; -@import "bootstrap/scss/reboot"; -@import "bootstrap/scss/type"; -@import "bootstrap/scss/images"; -@import "bootstrap/scss/containers"; -@import "bootstrap/scss/grid"; -@import "bootstrap/scss/helpers"; -@import "bootstrap/scss/tables"; -@import "bootstrap/scss/forms"; -@import "bootstrap/scss/buttons"; -@import "bootstrap/scss/transitions"; -@import "bootstrap/scss/dropdown"; -@import "bootstrap/scss/button-group"; -@import "bootstrap/scss/nav"; -@import "bootstrap/scss/navbar"; -@import "bootstrap/scss/card"; -@import "bootstrap/scss/accordion"; -@import "bootstrap/scss/breadcrumb"; -@import "bootstrap/scss/pagination"; -@import "bootstrap/scss/badge"; -@import "bootstrap/scss/alert"; -@import "bootstrap/scss/progress"; -@import "bootstrap/scss/list-group"; -@import "bootstrap/scss/close"; -@import "bootstrap/scss/toasts"; -@import "bootstrap/scss/modal"; -@import "bootstrap/scss/tooltip"; -@import "bootstrap/scss/popover"; -@import "bootstrap/scss/carousel"; -@import "bootstrap/scss/spinners"; -@import "bootstrap/scss/offcanvas"; -@import "bootstrap/scss/placeholders"; +@import "node_modules/bootstrap/scss/utilities"; +@import "node_modules/bootstrap/scss/reboot"; +@import "node_modules/bootstrap/scss/type"; +@import "node_modules/bootstrap/scss/images"; +@import "node_modules/bootstrap/scss/containers"; +@import "node_modules/bootstrap/scss/grid"; +@import "node_modules/bootstrap/scss/helpers"; +@import "node_modules/bootstrap/scss/tables"; +@import "node_modules/bootstrap/scss/forms"; +@import "node_modules/bootstrap/scss/buttons"; +@import "node_modules/bootstrap/scss/transitions"; +@import "node_modules/bootstrap/scss/dropdown"; +@import "node_modules/bootstrap/scss/button-group"; +@import "node_modules/bootstrap/scss/nav"; +@import "node_modules/bootstrap/scss/navbar"; +@import "node_modules/bootstrap/scss/card"; +@import "node_modules/bootstrap/scss/accordion"; +@import "node_modules/bootstrap/scss/breadcrumb"; +@import "node_modules/bootstrap/scss/pagination"; +@import "node_modules/bootstrap/scss/badge"; +@import "node_modules/bootstrap/scss/alert"; +@import "node_modules/bootstrap/scss/progress"; +@import "node_modules/bootstrap/scss/list-group"; +@import "node_modules/bootstrap/scss/close"; +@import "node_modules/bootstrap/scss/toasts"; +@import "node_modules/bootstrap/scss/modal"; +@import "node_modules/bootstrap/scss/tooltip"; +@import "node_modules/bootstrap/scss/popover"; +@import "node_modules/bootstrap/scss/carousel"; +@import "node_modules/bootstrap/scss/spinners"; +@import "node_modules/bootstrap/scss/offcanvas"; +@import "node_modules/bootstrap/scss/placeholders"; // 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss` -@import "bootstrap/scss/utilities/api"; +@import "node_modules/bootstrap/scss/utilities/api"; // 8. Add additional custom code here @import "common/fonts"; @@ -96,4 +96,4 @@ body { // 10. DocSearch @import "common/variables-docsearch"; -@import "@docsearch/css/dist/modal"; \ No newline at end of file +@import "node_modules/@docsearch/css/dist/modal"; \ No newline at end of file diff --git a/docs/config/development/hugo.toml b/docs/config/development/hugo.toml new file mode 100644 index 00000000000..33098c53bbc --- /dev/null +++ b/docs/config/development/hugo.toml @@ -0,0 +1,2 @@ +# Overrides for production environment +baseurl = "http://localhost/" \ No newline at end of file diff --git a/docs/config/production/hugo.toml b/docs/config/production/hugo.toml index 1fd97c4cec2..fb6e5f111e3 100644 --- a/docs/config/production/hugo.toml +++ b/docs/config/production/hugo.toml @@ -1,3 +1,2 @@ # Overrides for production environment -# baseurl = "https://documentation.defectdojo.com/" -baseurl = "https://docs.defectdojo.com" +baseurl = "https://docs.defectdojo.com" \ No newline at end of file diff --git a/docs/layouts/partials/head/custom-head.html b/docs/layouts/partials/head/custom-head.html index 21e7beaf35d..47fadc5772f 100644 --- a/docs/layouts/partials/head/custom-head.html +++ b/docs/layouts/partials/head/custom-head.html @@ -1 +1,6 @@ +{{ if site.Params.add_ons.docSearch -}} + {{ $options := (dict "targetPath" "/css/main.min.css" "outputStyle" "compressed") }} + {{ $style := resources.Get "scss/app.scss" | resources.ToCSS $options }} + +{{ end -}} \ No newline at end of file diff --git a/docs/package-lock.json b/docs/package-lock.json index aeba2387448..a66726b305a 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9,6 +9,8 @@ "version": "0.0.0", "license": "MIT", "dependencies": { + "@docsearch/css": "3.9.0", + "@docsearch/js": "3.9.0", "@tabler/icons": "3.34.1", "@thulite/doks-core": "1.8.0", "@thulite/images": "3.3.0", diff --git a/docs/package.json b/docs/package.json index aa4bfa7837e..d4f0df6bef5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -12,8 +12,8 @@ "preview": "vite preview --outDir public" }, "dependencies": { - "@docsearch/css": "^3.9.0", - "@docsearch/js": "^3.9.0", + "@docsearch/css": "3.9.0", + "@docsearch/js": "3.9.0", "@thulite/doks-core": "1.8.0", "@thulite/images": "3.3.0", "@thulite/inline-svg": "1.2.0", From 19c1fe1338fe928f1cae4a5e49b6732fe2f830f8 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 11 Aug 2025 14:38:16 +0000 Subject: [PATCH 12/12] Update versions in application files --- components/package.json | 2 +- dojo/__init__.py | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/package.json b/components/package.json index 23c211dc40b..fc2c6d35b2b 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.50.0-dev", + "version": "2.49.1", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index 5585c95616b..f62199bbedc 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -4,6 +4,6 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app # noqa: F401 -__version__ = "2.49.0" +__version__ = "2.49.1" __url__ = "https://github.com/DefectDojo/django-DefectDojo" __docs__ = "https://documentation.defectdojo.com" diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 8fd6a559091..356c1568f66 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.50.0-dev" +appVersion: "2.49.1" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.202-dev +version: 1.6.202 icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap