Skip to content

Commit

Permalink
Merge branch 'dev' into cloudsql-proxy-sidecar
Browse files Browse the repository at this point in the history
  • Loading branch information
jndeverteuil authored Sep 10, 2024
2 parents 9fff9b3 + dd444db commit 6e4128a
Show file tree
Hide file tree
Showing 79 changed files with 6,074 additions and 160 deletions.
4 changes: 2 additions & 2 deletions components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "defectdojo",
"version": "2.38.0-dev",
"version": "2.39.0-dev",
"license" : "BSD-3-Clause",
"private": true,
"dependencies": {
Expand All @@ -26,7 +26,7 @@
"google-code-prettify": "^1.0.0",
"jquery": "^3.7.1",
"jquery-highlight": "3.5.0",
"jquery-ui": "1.13.3",
"jquery-ui": "1.14.0",
"jquery.cookie": "1.4.1",
"jquery.flot.tooltip": "^0.9.0",
"jquery.hotkeys": "jeresig/jquery.hotkeys#master",
Expand Down
12 changes: 6 additions & 6 deletions components/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -678,12 +678,12 @@ [email protected]:
dependencies:
jquery ">= 1.0.0"

jquery-ui@1.13.3:
version "1.13.3"
resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.13.3.tgz#d9f5292b2857fa1f2fdbbe8f2e66081664eb9bc5"
integrity sha512-D2YJfswSJRh/B8M/zCowDpNFfwsDmtfnMPwjJTyvl+CBqzpYwQ+gFYIbUUlzijy/Qvoy30H1YhoSui4MNYpRwA==
jquery-ui@1.14.0:
version "1.14.0"
resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.14.0.tgz#b75d417826f0bab38125f907356d2e3313a9c6d5"
integrity sha512-mPfYKBoRCf0MzaT2cyW5i3IuZ7PfTITaasO5OFLAQxrHuI+ZxruPa+4/K1OMNT8oElLWGtIxc9aRbyw20BKr8g==
dependencies:
jquery ">=1.8.0 <4.0.0"
jquery ">=1.12.0 <5.0.0"

[email protected]:
version "1.4.1"
Expand All @@ -699,7 +699,7 @@ jquery.hotkeys@jeresig/jquery.hotkeys#master:
version "0.2.0"
resolved "https://codeload.github.com/jeresig/jquery.hotkeys/tar.gz/f24f1da275aab7881ab501055c256add6f690de4"

"jquery@>= 1.0.0", jquery@>=1.7, jquery@>=1.7.0, "jquery@>=1.8.0 <4.0.0", jquery@^3.7.1:
"jquery@>= 1.0.0", "jquery@>=1.12.0 <5.0.0", jquery@>=1.7, jquery@>=1.7.0, jquery@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de"
integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,15 @@ services:
source: ./docker/extra_settings
target: /app/docker/extra_settings
postgres:
image: postgres:16.4-alpine@sha256:492898505cb45f9835acc327e98711eaa9298ed804e0bb36f29e08394229550d
image: postgres:16.4-alpine@sha256:d898b0b78a2627cb4ee63464a14efc9d296884f1b28c841b0ab7d7c42f1fffdf
environment:
POSTGRES_DB: ${DD_DATABASE_NAME:-defectdojo}
POSTGRES_USER: ${DD_DATABASE_USER:-defectdojo}
POSTGRES_PASSWORD: ${DD_DATABASE_PASSWORD:-defectdojo}
volumes:
- defectdojo_postgres:/var/lib/postgresql/data
redis:
image: redis:7.2.5-alpine@sha256:0bc09d9f486508aa42ecc2f18012bb1e3a1b2744ef3a6ad30942fa12579f0b03
image: redis:7.2.5-alpine@sha256:6aaf3f5e6bc8a592fbfe2cccf19eb36d27c39d12dab4f4b01556b7449e7b1f44
volumes:
- defectdojo_redis:/data
volumes:
Expand Down
7 changes: 7 additions & 0 deletions docs/content/en/getting_started/upgrading/2.39.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: 'Upgrading to DefectDojo Version 2.39.x'
toc_hide: true
weight: -20240903
description: No special instructions.
---
There are no special instructions for upgrading to 2.39.x. Check the [Release Notes](https://github.com/DefectDojo/django-DefectDojo/releases/tag/2.39.0) for the contents of the release.
9 changes: 9 additions & 0 deletions docs/content/en/integrations/parsers/file/legitify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: "Legitify"
toc_hide: true
---
### File Types
This DefectDojo parser accepts JSON files (in flattened format) from Legitify. For further details regarding the results, please consult the relevant [documentation](https://github.com/Legit-Labs/legitify?tab=readme-ov-file#output-options).

### Sample Scan Data
Sample scan data for testing purposes can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/legitify).
9 changes: 9 additions & 0 deletions docs/content/en/integrations/parsers/file/threat_composer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: "Threat Composer"
toc_hide: true
---
### File Types
This DefectDojo parser accepts JSON files from Threat Composer. The tool supports the [export](https://github.com/awslabs/threat-composer/tree/main?#features) of JSON report out of the browser local storage to a local file.

### Sample Scan Data
Sample scan data for testing purposes can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/threat_composer).
14 changes: 7 additions & 7 deletions docs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"devDependencies": {
"postcss": "8.4.41",
"postcss": "8.4.45",
"autoprefixer": "10.4.20",
"postcss-cli": "11.0.0"
}
Expand Down
2 changes: 1 addition & 1 deletion dojo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.38.0-dev"
__version__ = "2.39.0-dev"
__url__ = "https://github.com/DefectDojo/django-DefectDojo"
__docs__ = "https://documentation.defectdojo.com"
6 changes: 3 additions & 3 deletions dojo/api_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1411,7 +1411,7 @@ class TestTypeSerializer(TaggitSerializer, serializers.ModelSerializer):

class Meta:
model = Test_Type
fields = "__all__"
exclude = ("dynamically_generated",)


class TestToNotesSerializer(serializers.Serializer):
Expand Down Expand Up @@ -1761,10 +1761,10 @@ def validate(self, data):
is_risk_accepted = data.get("risk_accepted", False)

if (is_active or is_verified) and is_duplicate:
msg = "Duplicate findings cannot be" " verified or active"
msg = "Duplicate findings cannot be verified or active"
raise serializers.ValidationError(msg)
if is_false_p and is_verified:
msg = "False positive findings cannot " "be verified."
msg = "False positive findings cannot be verified."
raise serializers.ValidationError(msg)

if is_risk_accepted and not self.instance.risk_accepted:
Expand Down
18 changes: 18 additions & 0 deletions dojo/db_migrations/0214_test_type_dynamically_generated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.8 on 2024-09-04 19:23

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dojo', '0213_system_settings_enable_ui_table_based_searching'),
]

operations = [
migrations.AddField(
model_name='test_type',
name='dynamically_generated',
field=models.BooleanField(default=False, help_text='Set to True for test types that are created at import time'),
),
]
31 changes: 20 additions & 11 deletions dojo/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ def __init__(self, *args, **kwargs):

class DateRangeFilter(ChoiceFilter):
options = {
None: (_("Any date"), lambda qs, name: qs.all()),
None: (_("Any date"), lambda qs, _: qs.all()),
1: (_("Today"), lambda qs, name: qs.filter(**{
f"{name}__year": now().year,
f"{name}__month": now().month,
Expand Down Expand Up @@ -651,7 +651,7 @@ def filter(self, qs, value):

class DateRangeOmniFilter(ChoiceFilter):
options = {
None: (_("Any date"), lambda qs, name: qs.all()),
None: (_("Any date"), lambda qs, _: qs.all()),
1: (_("Today"), lambda qs, name: qs.filter(**{
f"{name}__year": now().year,
f"{name}__month": now().month,
Expand Down Expand Up @@ -713,7 +713,7 @@ def filter(self, qs, value):

class ReportBooleanFilter(ChoiceFilter):
options = {
None: (_("Either"), lambda qs, name: qs.all()),
None: (_("Either"), lambda qs, _: qs.all()),
1: (_("Yes"), lambda qs, name: qs.filter(**{
f"{name}": True,
})),
Expand Down Expand Up @@ -1420,13 +1420,16 @@ class ApiFindingFilter(DojoFilter):
# DateRangeFilter
created = DateRangeFilter()
date = DateRangeFilter()
on = DateFilter(field_name="date", lookup_expr="exact")
before = DateFilter(field_name="date", lookup_expr="lt")
after = DateFilter(field_name="date", lookup_expr="gt")
discovered_on = DateFilter(field_name="date", lookup_expr="exact")
discovered_before = DateFilter(field_name="date", lookup_expr="lt")
discovered_after = DateFilter(field_name="date", lookup_expr="gt")
jira_creation = DateRangeFilter(field_name="jira_issue__jira_creation")
jira_change = DateRangeFilter(field_name="jira_issue__jira_change")
last_reviewed = DateRangeFilter()
mitigated = DateRangeFilter()
mitigated_on = DateFilter(field_name="mitigated", lookup_expr="exact")
mitigated_before = DateFilter(field_name="mitigated", lookup_expr="lt")
mitigated_after = DateFilter(field_name="mitigated", lookup_expr="gt")
# NumberInFilter
cwe = NumberInFilter(field_name="cwe", lookup_expr="in")
defect_review_requested_by = NumberInFilter(field_name="defect_review_requested_by", lookup_expr="in")
Expand Down Expand Up @@ -1544,17 +1547,20 @@ def filter(self, qs, value):
class FindingFilterHelper(FilterSet):
title = CharFilter(lookup_expr="icontains")
date = DateRangeFilter(field_name="date", label="Date Discovered")
on = DateFilter(field_name="date", lookup_expr="exact", label="On")
before = DateFilter(field_name="date", lookup_expr="lt", label="Before")
after = DateFilter(field_name="date", lookup_expr="gt", label="After")
on = DateFilter(field_name="date", lookup_expr="exact", label="Discovered On")
before = DateFilter(field_name="date", lookup_expr="lt", label="Discovered Before")
after = DateFilter(field_name="date", lookup_expr="gt", label="Discovered After")
last_reviewed = DateRangeFilter()
last_status_update = DateRangeFilter()
cwe = MultipleChoiceFilter(choices=[])
vulnerability_id = CharFilter(method=vulnerability_id_filter, label="Vulnerability Id")
severity = MultipleChoiceFilter(choices=SEVERITY_CHOICES)
duplicate = ReportBooleanFilter()
is_mitigated = ReportBooleanFilter()
mitigated = DateRangeFilter(label="Mitigated Date")
mitigated = DateRangeFilter(field_name="mitigated", label="Mitigated Date")
mitigated_on = DateFilter(field_name="mitigated", lookup_expr="exact", label="Mitigated On")
mitigated_before = DateFilter(field_name="mitigated", lookup_expr="lt", label="Mitigated Before")
mitigated_after = DateFilter(field_name="mitigated", lookup_expr="gt", label="Mitigated After")
planned_remediation_date = DateRangeOmniFilter()
planned_remediation_version = CharFilter(lookup_expr="icontains", label=_("Planned remediation version"))
file_path = CharFilter(lookup_expr="icontains")
Expand Down Expand Up @@ -1663,6 +1669,9 @@ def set_date_fields(self, *args: list, **kwargs: dict):
self.form.fields["on"].widget = date_input_widget
self.form.fields["before"].widget = date_input_widget
self.form.fields["after"].widget = date_input_widget
self.form.fields["mitigated_on"].widget = date_input_widget
self.form.fields["mitigated_before"].widget = date_input_widget
self.form.fields["mitigated_after"].widget = date_input_widget
self.form.fields["cwe"].choices = cwe_options(self.queryset)


Expand Down Expand Up @@ -3229,7 +3238,7 @@ class Meta:
filter_overrides = {
JSONField: {
"filter_class": CharFilter,
"extra": lambda f: {
"extra": lambda _: {
"lookup_expr": "icontains",
},
},
Expand Down
4 changes: 3 additions & 1 deletion dojo/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def __init__(self, *args, **kwargs):
class Test_TypeForm(forms.ModelForm):
class Meta:
model = Test_Type
exclude = [""]
exclude = ["dynamically_generated"]


class Development_EnvironmentForm(forms.ModelForm):
Expand Down Expand Up @@ -321,6 +321,8 @@ class ProductForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["prod_type"].queryset = get_authorized_product_types(Permissions.Product_Type_Add_Product)
if prod_type_id := getattr(kwargs.get("instance", Product()), "prod_type_id"): # we are editing existing instance
self.fields["prod_type"].queryset |= Product_Type.objects.filter(pk=prod_type_id) # even if user does not have permission for any other ProdType we need to add at least assign ProdType to make form submittable (otherwise empty list was here which generated invalid form)

# if this product has findings being asynchronously updated, disable the sla config field
if self.instance.async_updating:
Expand Down
2 changes: 2 additions & 0 deletions dojo/importers/base_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ def get_or_create_test_type(
test_type, created = Test_Type.objects.get_or_create(name=test_type_name)
if created:
logger.info(f"Created new Test_Type with name {test_type.name} because a report is being imported")
test_type.dynamically_generated = True
test_type.save()
return test_type

def verify_tool_configuration_from_test(self):
Expand Down
9 changes: 9 additions & 0 deletions dojo/importers/default_reimporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,13 @@ def process_matched_special_status_finding(
):
self.unchanged_items.append(existing_finding)
return existing_finding, True
# If the finding is risk accepted and inactive in Defectdojo we do not sync the status from the scanner
# We also need to add the finding to 'unchanged_items' as otherwise it will get mitigated by the reimporter
# (Risk accepted findings are not set to mitigated by Defectdojo)
# We however do not exit the loop as we do want to update the endpoints (in case some endpoints were fixed)
elif existing_finding.risk_accepted and not existing_finding.active:
self.unchanged_items.append(existing_finding)
return existing_finding, False
# The finding was not an exact match, so we need to add more details about from the
# new finding to the existing. Return False here to make process further
return existing_finding, False
Expand Down Expand Up @@ -697,6 +704,8 @@ def finding_post_processing(
finding.unsaved_files = finding_from_report.unsaved_files
self.process_files(finding)
# Process vulnerability IDs
if finding_from_report.unsaved_vulnerability_ids:
finding.unsaved_vulnerability_ids = finding_from_report.unsaved_vulnerability_ids
finding = self.process_vulnerability_ids(finding)

return finding
Expand Down
2 changes: 1 addition & 1 deletion dojo/jira_link/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ def get_jira_connection_raw(jira_server, jira_username, jira_password):
connect_method = get_jira_connect_method()
jira = connect_method(jira_server, jira_username, jira_password)

logger.debug("logged in to JIRA ""%s"" successfully", jira_server)
logger.debug("logged in to JIRA %s successfully", jira_server)

return jira
except JIRAError as e:
Expand Down
2 changes: 1 addition & 1 deletion dojo/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def get_system_settings(cls):
return None

@classmethod
def cleanup(cls, *args, **kwargs):
def cleanup(cls, *args, **kwargs): # noqa: ARG003
if hasattr(cls._thread_local, "system_settings"):
del cls._thread_local.system_settings

Expand Down
3 changes: 3 additions & 0 deletions dojo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,9 @@ class Test_Type(models.Model):
static_tool = models.BooleanField(default=False)
dynamic_tool = models.BooleanField(default=False)
active = models.BooleanField(default=True)
dynamically_generated = models.BooleanField(
default=False,
help_text=_("Set to True for test types that are created at import time"))

class Meta:
ordering = ("name",)
Expand Down
2 changes: 1 addition & 1 deletion dojo/settings/.settings.dist.py.sha256sum
Original file line number Diff line number Diff line change
@@ -1 +1 @@
38096a82c7cdeec6ca9c663c1ec3d6a5692a0e7bbfdea8fd2f05c58f753430d4
5adedc433a342d675492b86dc18786f72e167115f9718a397dc9b91c5fdc9c94
11 changes: 6 additions & 5 deletions dojo/settings/settings.dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,8 @@ def saml2_attrib_map_format(dict):
"Kiuwan SCA Scan": ["description", "severity", "component_name", "component_version", "cwe"],
"Rapplex Scan": ["title", "endpoints", "severity"],
"AppCheck Web Application Scanner": ["title", "severity"],
"Legitify Scan": ["title", "endpoints", "severity"],
"ThreatComposer Scan": ["title", "description"],
}

# Override the hardcoded settings here via the env var
Expand Down Expand Up @@ -1499,6 +1501,8 @@ def saml2_attrib_map_format(dict):
"Kiuwan SCA Scan": DEDUPE_ALGO_HASH_CODE,
"Rapplex Scan": DEDUPE_ALGO_HASH_CODE,
"AppCheck Web Application Scanner": DEDUPE_ALGO_HASH_CODE,
"Legitify Scan": DEDUPE_ALGO_HASH_CODE,
"ThreatComposer Scan": DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL_OR_HASH_CODE,
}

# Override the hardcoded settings here via the env var
Expand Down Expand Up @@ -1532,11 +1536,8 @@ def saml2_attrib_map_format(dict):
)

if env("DD_JIRA_EXTRA_ISSUE_TYPES") != "":
if env("DD_JIRA_EXTRA_ISSUE_TYPES").count(",") > 0:
for extra_type in env("DD_JIRA_EXTRA_ISSUE_TYPES").split(","):
JIRA_ISSUE_TYPE_CHOICES_CONFIG += (extra_type, extra_type)
else:
JIRA_ISSUE_TYPE_CHOICES_CONFIG += (env("DD_JIRA_EXTRA_ISSUE_TYPES"), env("DD_JIRA_EXTRA_ISSUE_TYPES"))
for extra_type in env("DD_JIRA_EXTRA_ISSUE_TYPES").split(","):
JIRA_ISSUE_TYPE_CHOICES_CONFIG += ((extra_type, extra_type),)

JIRA_SSL_VERIFY = env("DD_JIRA_SSL_VERIFY")

Expand Down
2 changes: 1 addition & 1 deletion dojo/templates/dojo/view_product_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ <h3 class="panel-title"><span class="fa-solid fa-circle-info fa-fw" aria-hidden=
</tr>
<tr>
<td><strong>{% trans "Product Type" %}</strong></td>
<td>{{ prod.prod_type|notspecified }}</td>
<td><a title="{% trans "Product Type" %}" href="{% url 'view_product_type' prod.prod_type.id %}">{{ prod.prod_type }}</a></td>
</tr>
<tr>
<td><strong>{% trans "Platform" %}</strong></td>
Expand Down
Loading

0 comments on commit 6e4128a

Please sign in to comment.