Skip to content

Commit b069232

Browse files
Merge branch 'bugfix' into implement_oidc_groups
2 parents 3874e6e + 3d3427b commit b069232

File tree

13 files changed

+228
-22
lines changed

13 files changed

+228
-22
lines changed

docs/content/en/connecting_your_tools/import_intro.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ description: "Learn how to import data manually, through the API, or via a conne
44
weight: 1
55
---
66

7-
One of the things we understand at DefectDojo is that every company’s security needs are completely different. There is no ‘one\-size\-fits\-all’ approach. As your organization changes, having a flexible approach is key.
8-
9-
DefectDojo allows you to connect your security tools in a flexible way to match those changes.
7+
One of the things we understand at DefectDojo is that every company’s security needs are completely different. There is no one-size-fits-all approach. As your organization changes, having a flexible approach is key, and DefectDojo allows you to connect your security tools in a flexible way to match those changes.
108

119
## Scan Upload Methods
1210

13-
When DefectDojo receives a vulnerability report from a security tool, it will create Findings based on the vulnerabilities contained within that report. DefectDojo acts as the central repository for these Findings where they can be triaged, remediated or otherwise addressed by you and your team.
11+
When DefectDojo receives a vulnerability report from a security tool, it will create Findings based on the vulnerabilities contained within that report. DefectDojo acts as the central repository for these Findings where they can be triaged, remediated, or otherwise addressed by you and your team.
1412

1513
There are two main ways that DefectDojo can upload Finding reports.
1614

1715
* Via direct **import** through the UI: [Import Scan Form](../import_scan_files/import_scan_ui)
18-
* Via **API** endpoint (allowing for automated data ingest): See [API Docs](https://docs.defectdojo.com/en/api/api-v2-docs/)
16+
* Via **API** endpoint (allowing for automated data ingestion): See [API Docs](https://docs.defectdojo.com/en/api/api-v2-docs/)
1917

2018
#### DefectDojo Pro Methods
2119

@@ -29,8 +27,8 @@ There are two main ways that DefectDojo can upload Finding reports.
2927

3028
| | **UI Import** | **API** | **Connectors** <span style="background-color:rgba(242, 86, 29, 0.3)">(Pro)</span> | **Smart Upload** <span style="background-color:rgba(242, 86, 29, 0.3)">(Pro)</span>|
3129
| --- | --- | --- | --- | --- |
32-
| **Supported Scan Types** | All: see [Supported Tools](/supported_tools/) | All: see [Supported Tools](/supported_tools/) | Snyk, Semgrep, Burp Suite, AWS Security Hub, Probely, Checkmarx, Tenable | Nexpose, NMap, OpenVas, Qualys, Tenable |
33-
| **Automation?** | Available via API: `/reimport` `/import` endpoints | Triggered from [CLI Importer](../external_tools) or external code | Connectors is inherently automated | Available via API: `/smart_upload_import` endpoint |
30+
| **Supported Scan Types** | All: see [Supported Tools](/supported_tools/) | All: see [Supported Tools](/supported_tools/) | Anchore, AWS Security Hub, BurpSuite, Checkmarx ONE, Dependency-Track, Probely, Semgrep, SonarQube, Snyk, Tenable, Wiz | Nexpose, NMap, OpenVas, Qualys, Tenable |
31+
| **Automation?** | Available via API: `/reimport` `/import` endpoints | Triggered from [CLI Importer](../external_tools) or external code | Connectors is an inherently automated feature | Available via API: `/smart_upload_import` endpoint |
3432

3533
### Product Hierarchy and organization
3634

docs/content/en/working_with_findings/organizing_engagements_tests/product_hierarchy.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,17 @@ Tests always have:
116116
* an associated test **Environment**
117117
* an associated **Engagement**
118118

119-
Tests can be created in different ways. Tests can be automatically created when scan data is imported directly into to an Engagement, resulting in a new Test containing the scan data. Tests can also be created in anticipation of planning future engagements, or for manually entered security findings requiring tracking and remediation.
119+
Tests can be created in different ways. Tests can be automatically created when scan data is imported directly into an Engagement, resulting in a new Test containing the scan data. Tests can also be created in anticipation of planning future engagements, or for manually entered security findings requiring tracking and remediation.
120120

121121
### **Test Types**
122122

123123
DefectDojo supports two categories of Test Types:
124124

125125
1. **Parser-based Test Types**: These correspond to specific security scanners that produce output in formats like XML, JSON, or CSV. When importing scan results, DefectDojo uses specialized parsers to convert the scanner output into Findings.
126126

127-
2. **Non-parser Test Types**: These are used for manually created findings not imported from a scan files.
128-
The following Test Types appear in the "Scan Type" dropdown when creating a new test, but will not appear when selecting "Import Scan":
127+
2. **Non-parser Test Types**: These are used for manually created Findings not imported from scan files. These Test Types use the [Generic Findings Import](/supported_tools/parsers/generic_findings_import/) method to render Findings and metadata.
128+
129+
The following Test Types appear in the "Scan Type" dropdown when creating a new test.
129130
* API Test
130131
* Static Check
131132
* Pen Test

docs/content/supported_tools/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ DefectDojo can parse data from 200+ security reports and counting.
2626

2727
| [Connectors](/en/connecting_your_tools/connectors/about_connectors/): supported tools | [Smart Upload](/en/connecting_your_tools/import_scan_files/smart_upload/): supported tools |
2828
| --- | --- |
29-
| AWS Security Hub, BurpSuite, Checkmarx ONE, Dependency-Track, Probely, Semgrep, SonarQube, Snyk, Tenable | Nexpose, NMap, OpenVas, Qualys, Tenable, Wiz |
29+
| Anchore, AWS Security Hub, BurpSuite, Checkmarx ONE, Dependency-Track, Probely, Semgrep, SonarQube, Snyk, Tenable | Nexpose, NMap, OpenVas, Qualys, Tenable, Wiz |
3030

3131
# All Supported Tools
3232

docs/content/supported_tools/parsers/generic_findings_import.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ Open-source and Pro users can use Generic Findings Import as a method to ingest
88

99
Using Generic Findings Import will create a new Test Type in your DefectDojo instance called "`{The Name Of Your Test}` (Generic Findings Import)". For example, this JSON content will result in a Test Type called "Example Report (Generic Findings Import)":
1010

11+
```
1112
{
1213
"name": "Example Report",
1314
"findings": []
1415
}
16+
```
1517

1618
DefectDojo Pro users can also consider using the [Universal Parser](../universal_parser), a tool which allows for highly customizable JSON, XML and CSV imports.
1719

18-
For more information on supported parameters for Generic Findings Import, see the [Parser Guide](../file/generic)
20+
For more information on supported parameters for Generic Findings Import, see the related [Parser Guide](../file/generic).

dojo/api_v2/views.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from django.db.models.query import QuerySet as DjangoQuerySet
1515
from django.http import FileResponse, HttpResponse
1616
from django.shortcuts import get_object_or_404
17+
from django.urls import reverse
1718
from django.utils import timezone
1819
from django_filters.rest_framework import DjangoFilterBackend
1920
from drf_spectacular.renderers import OpenApiJsonRenderer2
@@ -176,6 +177,7 @@
176177
generate_file_response,
177178
get_setting,
178179
get_system_setting,
180+
process_tag_notifications,
179181
)
180182

181183
logger = logging.getLogger(__name__)
@@ -528,6 +530,15 @@ def notes(self, request, pk=None):
528530
)
529531
note.save()
530532
engagement.notes.add(note)
533+
# Determine if we need to send any notifications for user mentioned
534+
process_tag_notifications(
535+
request=request,
536+
note=note,
537+
parent_url=request.build_absolute_uri(
538+
reverse("view_engagement", args=(engagement.id,)),
539+
),
540+
parent_title=f"Engagement: {engagement.name}",
541+
)
531542

532543
serialized_note = serializers.NoteSerializer(
533544
{"author": author, "entry": entry, "private": private},
@@ -1086,6 +1097,15 @@ def notes(self, request, pk=None):
10861097
)
10871098
note.save()
10881099
finding.notes.add(note)
1100+
# Determine if we need to send any notifications for user mentioned
1101+
process_tag_notifications(
1102+
request=request,
1103+
note=note,
1104+
parent_url=request.build_absolute_uri(
1105+
reverse("view_finding", args=(finding.id,)),
1106+
),
1107+
parent_title=f"Finding: {finding.title}",
1108+
)
10891109

10901110
if finding.has_jira_issue:
10911111
jira_helper.add_comment(finding, note)
@@ -2135,6 +2155,15 @@ def notes(self, request, pk=None):
21352155
)
21362156
note.save()
21372157
test.notes.add(note)
2158+
# Determine if we need to send any notifications for user mentioned
2159+
process_tag_notifications(
2160+
request=request,
2161+
note=note,
2162+
parent_url=request.build_absolute_uri(
2163+
reverse("view_test", args=(test.id,)),
2164+
),
2165+
parent_title=f"Test: {test.title}",
2166+
)
21382167

21392168
serialized_note = serializers.NoteSerializer(
21402169
{"author": author, "entry": entry, "private": private},

dojo/finding/helper.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
22
from contextlib import suppress
3+
from datetime import datetime
34
from time import strftime
45

56
from django.conf import settings
@@ -9,6 +10,7 @@
910
from django.dispatch.dispatcher import receiver
1011
from django.urls import reverse
1112
from django.utils import timezone
13+
from django.utils.timezone import is_naive, make_aware, now
1214
from fieldsignals import pre_save_changed
1315

1416
import dojo.jira_link.helper as jira_helper
@@ -740,6 +742,17 @@ def save_vulnerability_ids_template(finding_template, vulnerability_ids):
740742
finding_template.cve = None
741743

742744

745+
def normalize_datetime(value):
746+
"""Ensure value is timezone-aware datetime."""
747+
if value:
748+
if not isinstance(value, datetime):
749+
value = datetime.combine(value, datetime.min.time())
750+
# Make timezone-aware if naive
751+
if is_naive(value):
752+
value = make_aware(value)
753+
return value
754+
755+
743756
def close_finding(
744757
*,
745758
finding,
@@ -761,15 +774,16 @@ def close_finding(
761774
"""
762775
# Core status updates
763776
finding.is_mitigated = is_mitigated
764-
now = timezone.now()
765-
finding.mitigated = mitigated or now
777+
current_time = now()
778+
mitigated_date = normalize_datetime(mitigated) or current_time
779+
finding.mitigated = mitigated_date
766780
finding.mitigated_by = mitigated_by or user
767781
finding.active = False
768782
finding.false_p = bool(false_p)
769783
finding.out_of_scope = bool(out_of_scope)
770784
finding.duplicate = bool(duplicate)
771785
finding.under_review = False
772-
finding.last_reviewed = finding.mitigated
786+
finding.last_reviewed = mitigated_date
773787
finding.last_reviewed_by = user
774788

775789
# Create note if provided
@@ -779,16 +793,16 @@ def close_finding(
779793
entry=note_entry,
780794
author=user,
781795
note_type=note_type,
782-
date=finding.mitigated,
796+
date=mitigated_date,
783797
)
784798
finding.notes.add(new_note)
785799

786800
# Endpoint statuses
787801
for status in finding.status_finding.all():
788802
status.mitigated_by = finding.mitigated_by
789-
status.mitigated_time = finding.mitigated
803+
status.mitigated_time = mitigated_date
790804
status.mitigated = True
791-
status.last_modified = timezone.now()
805+
status.last_modified = current_time
792806
status.save()
793807

794808
# Risk acceptance

dojo/finding/views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,12 +1145,14 @@ def close_finding(request, fid):
11451145
note_type_activation = Note_Type.objects.filter(is_active=True)
11461146
missing_note_types = get_missing_mandatory_notetypes(finding) if len(note_type_activation) else note_type_activation
11471147
form = CloseFindingForm(
1148+
instance=finding,
11481149
missing_note_types=missing_note_types,
11491150
can_edit_mitigated_data=finding_helper.can_edit_mitigated_data(request.user),
11501151
)
11511152
if request.method == "POST":
11521153
form = CloseFindingForm(
11531154
request.POST,
1155+
instance=finding,
11541156
missing_note_types=missing_note_types,
11551157
can_edit_mitigated_data=finding_helper.can_edit_mitigated_data(request.user),
11561158
)

dojo/importers/default_reimporter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,4 +772,6 @@ def calculate_unsaved_finding_hash_code(
772772
self,
773773
unsaved_finding: Finding,
774774
) -> str:
775+
# this is overridden in Pro, but will still call this via super()
776+
deduplicationLogger.debug("Calculating hash code for unsaved finding")
775777
return unsaved_finding.compute_hash_code()

dojo/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,6 +2910,11 @@ def risk_acceptance(self):
29102910
return None
29112911

29122912
def compute_hash_code(self):
2913+
# Allow Pro to overwrite compute hash_code which gets dedupe settings from a database instead of django.settings
2914+
from dojo.utils import get_custom_method # noqa: PLC0415 circular import
2915+
if compute_hash_code_method := get_custom_method("FINDING_COMPUTE_HASH_METHOD"):
2916+
deduplicationLogger.debug("using custom compute_hash_code method")
2917+
return compute_hash_code_method(self)
29132918

29142919
# Check if all needed settings are defined
29152920
if not hasattr(settings, "HASHCODE_FIELDS_PER_SCANNER") or not hasattr(settings, "HASHCODE_ALLOWS_NULL_CWE") or not hasattr(settings, "HASHCODE_ALLOWED_FIELDS"):

dojo/tools/pwn_sast/parser.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ def get_findings(self, filename, test):
115115
file_path=offending_file,
116116
unique_id_from_tool=unique_finding_key,
117117
)
118+
if mitigation:
119+
finding.fix_available = True
120+
else:
121+
finding.fix_available = False
118122
findings[unique_finding_key] = finding
119123

120124
return list(findings.values())

0 commit comments

Comments
 (0)