Skip to content

Commit bd7462a

Browse files
Merge branch 'bugfix' into fix_13628
2 parents 2e6751d + 2b54bbb commit bd7462a

15 files changed

Lines changed: 249 additions & 47 deletions

File tree

.github/workflows/test-helm-chart.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ jobs:
107107
steps:
108108
- name: Checkout
109109
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
110+
with:
111+
repository: ${{ github.event.pull_request.head.repo.full_name }}
112+
ref: ${{ github.event.pull_request.head.ref }}
110113

111114
- name: Update values in HELM chart
112115
if: startsWith(github.head_ref, 'renovate/') || startsWith(github.head_ref, 'dependabot/')

docs/content/supported_tools/parsers/file/nancy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This parser expects a JSON file.
1616
Sample Nancy scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/nancy).
1717

1818
### Link To Tool
19-
See Nancy on GitHub: https://github.com/sonatype-nexus-community/nancy
19+
See Nancy on [Github](https://github.com/sonatype-nexus-community/nancy)
2020

2121
### Default Deduplication Hashcode Fields
2222
By default, DefectDojo identifies duplicate Findings using these [hashcode fields](https://docs.defectdojo.com/en/working_with_findings/finding_deduplication/about_deduplication/):

dojo/forms.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,18 @@ def __init__(self, *args, **kwargs):
11311131
else:
11321132
self.fields["lead"].queryset = get_authorized_users(Permissions.Test_View).filter(is_active=True)
11331133

1134+
def is_valid(self):
1135+
valid = super().is_valid()
1136+
1137+
# we're done now if not valid
1138+
if not valid:
1139+
return valid
1140+
if self.cleaned_data["target_start"] > self.cleaned_data["target_end"]:
1141+
self.add_error("target_start", "Your target start date exceeds your target end date")
1142+
self.add_error("target_end", "Your target start date exceeds your target end date")
1143+
return False
1144+
return True
1145+
11341146
class Meta:
11351147
model = Test
11361148
fields = ["title", "test_type", "target_start", "target_end", "description",

dojo/middleware.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,23 @@ def __call__(self, request):
8383
class CustomSocialAuthExceptionMiddleware(SocialAuthExceptionMiddleware):
8484
def process_exception(self, request, exception):
8585
if isinstance(exception, requests.exceptions.RequestException):
86-
messages.error(request, "Please use the standard login below.")
86+
messages.error(request, settings.SOCIAL_AUTH_EXCEPTION_MESSAGE_REQUEST_EXCEPTION)
8787
return redirect("/login?force_login_form")
8888
if isinstance(exception, AuthCanceled):
89-
messages.warning(request, "Social login was canceled. Please try again or use the standard login.")
89+
messages.warning(request, settings.SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_CANCELED)
9090
return redirect("/login?force_login_form")
9191
if isinstance(exception, AuthFailed):
92-
messages.error(request, "Social login failed. Please try again or use the standard login.")
92+
messages.error(request, settings.SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FAILED)
9393
return redirect("/login?force_login_form")
9494
if isinstance(exception, AuthForbidden):
95-
messages.error(request, "You are not authorized to log in via this method. Please contact support or use the standard login.")
95+
messages.error(request, settings.SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FORBIDDEN)
9696
return redirect("/login?force_login_form")
9797
if isinstance(exception, AuthTokenError):
98-
messages.error(request, "Social login failed due to an invalid or expired token. Please try again or use the standard login.")
98+
messages.error(request, settings.SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_TOKEN_ERROR)
9999
return redirect("/login?force_login_form")
100100
if isinstance(exception, TypeError) and "'NoneType' object is not iterable" in str(exception):
101101
logger.warning("OIDC login error: NoneType is not iterable")
102-
messages.error(request, "An unexpected error occurred during social login. Please use the standard login.")
102+
messages.error(request, settings.SOCIAL_AUTH_EXCEPTION_MESSAGE_NONE_TYPE)
103103
return redirect("/login?force_login_form")
104104
logger.error(f"Unhandled exception during social login: {exception}")
105105
return super().process_exception(request, exception)

dojo/models.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,8 +1093,8 @@ def save(self, *args, **kwargs):
10931093
product.async_updating = True
10941094
super(Product, product).save()
10951095
# launch the async task to update all finding sla expiration dates
1096-
from dojo.sla_config.helpers import update_sla_expiration_dates_sla_config_async # noqa: I001, PLC0415 circular import
1097-
update_sla_expiration_dates_sla_config_async(self, products, tuple(severities))
1096+
from dojo.sla_config.helpers import async_update_sla_expiration_dates_sla_config_sync # noqa: I001, PLC0415 circular import
1097+
async_update_sla_expiration_dates_sla_config_sync(self, products, severities=severities)
10981098

10991099
def clean(self):
11001100
sla_days = [self.critical, self.high, self.medium, self.low]
@@ -1255,8 +1255,8 @@ def save(self, *args, **kwargs):
12551255
sla_config.async_updating = True
12561256
super(SLA_Configuration, sla_config).save()
12571257
# launch the async task to update all finding sla expiration dates
1258-
from dojo.sla_config.helpers import update_sla_expiration_dates_product_async # noqa: I001, PLC0415 circular import
1259-
update_sla_expiration_dates_product_async(self, sla_config)
1258+
from dojo.sla_config.helpers import async_update_sla_expiration_dates_sla_config_sync # noqa: I001, PLC0415 circular import
1259+
async_update_sla_expiration_dates_sla_config_sync(sla_config, Product.objects.filter(id=self.id))
12601260

12611261
def get_absolute_url(self):
12621262
return reverse("view_product", args=[str(self.id)])
@@ -3146,16 +3146,25 @@ def get_sla_configuration(self):
31463146
return self.test.engagement.product.sla_configuration
31473147

31483148
def get_sla_period(self):
3149+
# Determine which method to use to calculate the SLA
3150+
from dojo.utils import get_custom_method # noqa: PLC0415 circular import
3151+
if method := get_custom_method("FINDING_SLA_PERIOD_METHOD"):
3152+
return method(self)
3153+
# Run the default method
31493154
sla_configuration = self.get_sla_configuration()
31503155
sla_period = getattr(sla_configuration, self.severity.lower(), None)
31513156
enforce_period = getattr(sla_configuration, str("enforce_" + self.severity.lower()), None)
31523157
return sla_period, enforce_period
31533158

31543159
def set_sla_expiration_date(self):
3160+
# First check if SLA is enabled globally
31553161
system_settings = System_Settings.objects.get()
31563162
if not system_settings.enable_finding_sla:
31573163
return
3164+
# Call the internal method to set the sla expiration date
3165+
self._set_sla_expiration_date()
31583166

3167+
def _set_sla_expiration_date(self):
31593168
# some parsers provide date as a `str` instead of a `date` in which case we need to parse it #12299 on GitHub
31603169
sla_start_date = self.get_sla_start_date()
31613170
if sla_start_date and isinstance(sla_start_date, str):

dojo/settings/settings.dist.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@
174174
DD_SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY=(str, ""),
175175
DD_SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET=(str, ""),
176176
DD_SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL=(bool, True),
177+
DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_REQUEST_EXCEPTION=(str, "Please use the standard login below."),
178+
DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_CANCELED=(str, "Social login was canceled. Please try again or use the standard login."),
179+
DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FAILED=(str, "Social login failed. Please try again or use the standard login."),
180+
DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FORBIDDEN=(str, "You are not authorized to log in via this method. Please contact support or use the standard login."),
181+
DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_NONE_TYPE=(str, "An unexpected error occurred during social login. Please use the standard login."),
182+
DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_TOKEN_ERROR=(str, "Social login failed due to an invalid or expired token. Please try again or use the standard login."),
177183
DD_SAML2_ENABLED=(bool, False),
178184
# Allows to override default SAML authentication backend. Check https://djangosaml2.readthedocs.io/contents/setup.html#custom-user-attributes-processing
179185
DD_SAML2_AUTHENTICATION_BACKENDS=(str, "djangosaml2.backends.Saml2Backend"),
@@ -649,6 +655,13 @@ def generate_url(scheme, double_slashes, user, password, host, port, path, param
649655
if value := env("DD_SOCIAL_AUTH_OIDC_LOGIN_BUTTON_TEXT"):
650656
SOCIAL_AUTH_OIDC_LOGIN_BUTTON_TEXT = value
651657

658+
SOCIAL_AUTH_EXCEPTION_MESSAGE_REQUEST_EXCEPTION = env("DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_REQUEST_EXCEPTION")
659+
SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_CANCELED = env("DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_CANCELED")
660+
SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FAILED = env("DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FAILED")
661+
SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FORBIDDEN = env("DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_FORBIDDEN")
662+
SOCIAL_AUTH_EXCEPTION_MESSAGE_NONE_TYPE = env("DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_NONE_TYPE")
663+
SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_TOKEN_ERROR = env("DD_SOCIAL_AUTH_EXCEPTION_MESSAGE_AUTH_TOKEN_ERROR")
664+
652665
AUTH0_OAUTH2_ENABLED = env("DD_SOCIAL_AUTH_AUTH0_OAUTH2_ENABLED")
653666
SOCIAL_AUTH_AUTH0_KEY = env("DD_SOCIAL_AUTH_AUTH0_KEY")
654667
SOCIAL_AUTH_AUTH0_SECRET = env("DD_SOCIAL_AUTH_AUTH0_SECRET")

dojo/sla_config/helpers.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,50 @@
22

33
from dojo.celery import app
44
from dojo.decorators import dojo_async_task
5-
from dojo.models import Finding, Product, SLA_Configuration
6-
from dojo.utils import calculate_grade, mass_model_updater
5+
from dojo.models import Finding, Product, SLA_Configuration, System_Settings
6+
from dojo.utils import get_custom_method, mass_model_updater
77

88
logger = logging.getLogger(__name__)
99

1010

1111
@dojo_async_task
1212
@app.task
13-
def update_sla_expiration_dates_sla_config_async(sla_config, products, severities, *args, **kwargs):
14-
update_sla_expiration_dates_sla_config_sync(sla_config, products, severities)
13+
def async_update_sla_expiration_dates_sla_config_sync(sla_config: SLA_Configuration, products: list[Product], *args, severities: list[str] | None = None, **kwargs):
14+
if method := get_custom_method("FINDING_SLA_EXPIRATION_CALCULATION_METHOD"):
15+
method(sla_config, products, severities=severities)
16+
else:
17+
update_sla_expiration_dates_sla_config_sync(sla_config, products, severities=severities)
1518

1619

17-
@dojo_async_task
18-
@app.task
19-
def update_sla_expiration_dates_product_async(product, sla_config, *args, **kwargs):
20-
update_sla_expiration_dates_sla_config_sync(sla_config, [product])
21-
22-
23-
def update_sla_expiration_dates_sla_config_sync(sla_config, products, severities=None):
20+
def update_sla_expiration_dates_sla_config_sync(sla_config: SLA_Configuration, products: list[Product], severities: list[str] | None = None):
2421
logger.info("Updating finding SLA expiration dates within the %s SLA configuration", sla_config)
22+
# First check if SLA is enabled globally
23+
system_settings = System_Settings.objects.get()
24+
if not system_settings.enable_finding_sla:
25+
return
2526
# update each finding that is within the SLA configuration that was saved
2627
findings = Finding.objects.filter(test__engagement__product__sla_configuration_id=sla_config.id)
2728
if products:
2829
findings = findings.filter(test__engagement__product__in=products)
2930
if severities:
3031
findings = findings.filter(severity__in=severities)
3132

32-
findings = findings.prefetch_related(
33+
findings = (
34+
findings.prefetch_related(
3335
"test",
3436
"test__engagement",
3537
"test__engagement__product",
3638
"test__engagement__product__sla_configuration",
39+
)
40+
.order_by("id")
41+
.only("id", "sla_start_date", "date", "severity", "test")
3742
)
38-
39-
findings = findings.order_by("id").only("id", "sla_start_date", "date", "severity", "test")
40-
43+
# Call the internal method so that we are not checking system settings for each finding
4144
mass_model_updater(Finding, findings, lambda f: f.set_sla_expiration_date(), fields=["sla_expiration_date"])
4245

4346
# reset the async updating flag to false for all products using this sla config
44-
for product in products:
45-
product.async_updating = False
46-
super(Product, product).save()
47-
calculate_grade(product)
47+
# use update as we don't want save() and signals to be triggered
48+
products.update(async_updating=False)
4849

4950
# reset the async updating flag to false for this sla config
5051
sla_config.async_updating = False

dojo/tools/nancy/parser.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22

33
from cvss.cvss3 import CVSS3
4+
from cvss.cvss4 import CVSS4
45

56
from dojo.models import Finding
67

@@ -64,17 +65,18 @@ def get_items(self, vulnerable, test):
6465
out_of_scope=False,
6566
static_finding=True,
6667
dynamic_finding=False,
67-
vuln_id_from_tool=associated_vuln["Id"],
68+
vuln_id_from_tool=associated_vuln.get("Id", associated_vuln.get("ID")),
6869
references="\n".join(references),
6970
)
70-
7171
finding.unsaved_vulnerability_ids = vulnerability_ids
72-
72+
cvss_vector = associated_vuln["CvssVector"]
7373
# CVSSv3 vector
74-
if associated_vuln["CvssVector"]:
74+
if cvss_vector and cvss_vector.startswith("CVSS:3."):
7575
finding.cvssv3 = CVSS3(
7676
associated_vuln["CvssVector"]).clean_vector()
77-
77+
elif cvss_vector and cvss_vector.startswith("CVSS:4."):
78+
finding.cvssv4 = CVSS4(
79+
associated_vuln["CvssVector"]).clean_vector()
7880
# do we have a CWE?
7981
if associated_vuln["Title"].startswith("CWE-"):
8082
cwe = (associated_vuln["Title"]

helm/defectdojo/Chart.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@ dependencies:
3434
# description: Critical bug
3535
annotations:
3636
artifacthub.io/prerelease: "true"
37-
artifacthub.io/changes: ""
37+
artifacthub.io/changes: |
38+
- kind: fixed
39+
description: Broken rendering of media PVC
40+
- kind: fixed
41+
description: Typo in description of digests

helm/defectdojo/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,11 +674,11 @@ A Helm chart for Kubernetes to install DefectDojo
674674
| host | string | `"defectdojo.default.minikube.local"` | Primary hostname of instance |
675675
| imagePullPolicy | string | `"Always"` | |
676676
| imagePullSecrets | string | `nil` | When using a private registry, name of the secret that holds the registry secret (eg deploy token from gitlab-ci project) Create secrets as: kubectl create secret docker-registry defectdojoregistrykey --docker-username=registry_username --docker-password=registry_password --docker-server='https://index.docker.io/v1/' |
677-
| images.django.image.digest | string | `""` | Prefix "sha@" is expected in this place |
677+
| images.django.image.digest | string | `""` | Prefix "sha256:" is expected in this place |
678678
| images.django.image.registry | string | `""` | |
679679
| images.django.image.repository | string | `"defectdojo/defectdojo-django"` | |
680680
| images.django.image.tag | string | `""` | If empty, use appVersion. Another possible values are: latest, X.X.X, X.X.X-debian, X.X.X-alpine (where X.X.X is version of DD). For dev builds (only for testing purposes): nightly-dev, nightly-dev-debian, nightly-dev-alpine. To see all, check https://hub.docker.com/r/defectdojo/defectdojo-django/tags. |
681-
| images.nginx.image.digest | string | `""` | Prefix "sha@" is expected in this place |
681+
| images.nginx.image.digest | string | `""` | Prefix "sha256:" is expected in this place |
682682
| images.nginx.image.registry | string | `""` | |
683683
| images.nginx.image.repository | string | `"defectdojo/defectdojo-nginx"` | |
684684
| images.nginx.image.tag | string | `""` | If empty, use appVersion. Another possible values are: latest, X.X.X, X.X.X-alpine (where X.X.X is version of DD). For dev builds (only for testing purposes): nightly-dev, nightly-dev-alpine. To see all, check https://hub.docker.com/r/defectdojo/defectdojo-nginx/tags. |

0 commit comments

Comments
 (0)