diff --git a/.github/workflows/test-helm-chart.yml b/.github/workflows/test-helm-chart.yml
index 75cf1186411..b7d30cece1b 100644
--- a/.github/workflows/test-helm-chart.yml
+++ b/.github/workflows/test-helm-chart.yml
@@ -33,7 +33,7 @@ jobs:
helm dependency update ./helm/defectdojo
- name: Set up chart-testing
- uses: helm/chart-testing-action@e6669bcd63d7cb57cb4380c33043eebe5d111992 # v2.6.1
+ uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0
with:
yamale_version: 4.0.4
yamllint_version: 1.35.1
diff --git a/docs/assets/images/DD-Architecture.drawio b/docs/assets/images/DD-Architecture.drawio
deleted file mode 100644
index d7adcfb2153..00000000000
--- a/docs/assets/images/DD-Architecture.drawio
+++ /dev/null
@@ -1 +0,0 @@
-7Vtbc9o6EP41PJZBvgGPARKaaZLmJJmT9FHYwig1FpVlLv31R7Llq7gYysU9Q8hM0EqW5G+/lXZXSkPvT5dDCmeTR+Igr6G1nGVDHzQ0DRia1hC/LWcVSzqWHgtcih3ZKBO84t9ICltSGmIHBYWGjBCP4VlRaBPfRzYryCClZFFsNiZecdQZdJEieLWhp0rfscMmUgqsblbxFWF3IofuaO24YgqTxvJNggl0yCIn0m8bep8SwuJv02UfeQK8BJf4ubsNtenEKPJZlQd+Db7ffx1M6bfpYAjmd2/hJ11+kZOdQy+UL9zQLI/31xuJKbOVxMH6FYp59sbEZ1+CSEs3vAEfn2u6l9Xzb674O0Bjro0B+SRJf3xio6RWApL2rlES+g4SEwW8ejHBDL3OoC1qF5xXXDZhU09WQ2pLnhhiRtjz+sQjNOpJH5viI2cqm3Fg+FMedn1eoLGuenNEGeZ6vpFyRsQwAR8V+y4vm1npRao36TY3XPwjmjJKfqJcTS/6pC+b15NUnZgBWuZEUm9DRKaI0RVvktQmHFqVyouMku1ENsmx0UiEUJqBm/adMYV/kWTZgzhAIc7T8P7p4880m9MZsI4EnVWCzlKhA+ugs06GnKGAhBy+5sgioWxCXOJD7zaT9jIYBZezNg9E0DYC7xMxtpLowZCRIrRoidlH7vsP0VXTlKXBUvYcFVZJwefv+5E1FMUf+brssaiUPFdZjQEJqY22YCU3Dwapi9g2TOWmIoDcygqKPMjwvLi4H13FmmIc4fvr8L52xqHXzjh0BbkBZHAEA1R78Azj0uAZCnj8KRTN+Z3Qn4jWDkOztLHpF8fQ3IxhD0FWOwStTt0QtBQEFdBgMIt99TFeCux6M4J9hujtnAMRSLBSf1lsKQ4MJun2l0O06Hb5xBebpQdHyHsmAWaYCNfORqLznM/3UGowIoyR6UanMHEd03741GbiVaZLV0Q9Tfg7pKgZBlFlWcklB9UYiM9xlK91raLyVd0bbVX15qlU39mteuQ7NyIsy7S1xknJHJPU3djipDh3WEwzKgXcVWDJALYHgwDbiVg2W2eI+zpgmzwjsMMzOtwTAhUdnJzqzTVWn8gq+0FyhGdhoDnitUurTqtEqfh95FP5oLTUkQ66zW7+p+iPlMOX2BFUuo3ImoJwOH+7V/6eir9avfirlxzf9v+Cv0CNyrcROOPX0TgMqnP4UA4eL7qUwcbO6LJe3DWOxt1yR/qZ2aqGyQezdZ+0RmV+Okdg674r8/nZbdSM3e2maeYWVLPAUU3rNM3D6F5e8w1wZrqbKrvPl/crLudgq4FcPu8Hjk3e8+T9gJq+eoGjEWaP/yi6v3TioJx60S6eOACdixrIIYlxUDCPzFpObiDmpexj/dpqdkvxYHltrbpIKx2VcxWnXqTVEPB6rlXx0KOlQHc99agInRq3XfeN6uipccTVZitCpzosV5utCJ162vaIgkBcJ0pu0NDkvktPHFLQ2oFaQ1O+Hr/9MYQVzt92ZlU25/Nk0jufLFnn2R6cLhGlZ0QxB0OcpqW+974x7Ebd7nSZJX41yYfsmWD+W3J/mnrx8LpnV4TuGqJUgO4JeW/9Bzj/92X1+jgOPmwK3tZcWrz3McPQ4y9ev+25jN9ZLxitxW/NTlL3m4tnSNBso9rO3eboFxf/2gQNL2aX4ePm2b8U6Lf/AQ==
\ No newline at end of file
diff --git a/docs/assets/images/DD-Architecture.png b/docs/assets/images/DD-Architecture.png
new file mode 100644
index 00000000000..ae776df9609
Binary files /dev/null and b/docs/assets/images/DD-Architecture.png differ
diff --git a/docs/assets/images/beta-classic-uis.png b/docs/assets/images/beta-classic-uis.png
new file mode 100644
index 00000000000..4e6a98fcd49
Binary files /dev/null and b/docs/assets/images/beta-classic-uis.png differ
diff --git a/docs/assets/images/beta-ui-overview.png b/docs/assets/images/beta-ui-overview.png
new file mode 100644
index 00000000000..14ef167956b
Binary files /dev/null and b/docs/assets/images/beta-ui-overview.png differ
diff --git a/docs/assets/images/program_insights.png b/docs/assets/images/program_insights.png
new file mode 100644
index 00000000000..ba08f445ac7
Binary files /dev/null and b/docs/assets/images/program_insights.png differ
diff --git a/docs/assets/svgs/.gitkeep b/docs/assets/svgs/.gitkeep
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/docs/assets/svgs/DD-Architecture.svg b/docs/assets/svgs/DD-Architecture.svg
deleted file mode 100644
index 4ebf0f92aee..00000000000
--- a/docs/assets/svgs/DD-Architecture.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/docs/content/en/about_defectdojo/ui_pro_vs_os.md b/docs/content/en/about_defectdojo/ui_pro_vs_os.md
new file mode 100644
index 00000000000..7b596850cb2
--- /dev/null
+++ b/docs/content/en/about_defectdojo/ui_pro_vs_os.md
@@ -0,0 +1,53 @@
+---
+title: "🎨 Beta UI Features"
+description: "Working with different UIs in DefectDojo"
+draft: "false"
+weight: 4
+pro-feature: true
+---
+
+Note: The Beta UI and associated features are only available in DefectDojo Pro.
+
+In late 2023, DefectDojo Inc. released a new UI for DefectDojo Pro, which has since been in Beta for Pro customers to test and experiment with.
+
+The Beta UI brings the following enhancements to DefectDojo:
+
+- Modern and sleek design, built using Vue.js
+- Optimized data delivery and load times, especially for large datasets
+- Access to new Pro features, including [API Connectors](/en/connecting_your_tools/connectors/about_connectors/), [Universal Importer](/en/connecting_your_tools/external_tools/), and Pro Metrics views
+- Improved UI workflows: better filtering, dashboards, and navigation
+
+## Switching To The Beta UI
+
+To access the Beta UI, open your User Options menu from the top-right hand corner. You can also switch back to the Classic UI from the same menu.
+
+![image](images/beta-classic-uis.png)
+
+## Navigational Changes
+
+![image](images/beta-ui-overview.png)
+
+1. The **Sidebar** has been reorganized: Pro Metrics and the Homepage can be found in the first section.
+
+2. Import methods can be found in the **Import** section: set up [API Connectors](/en/connecting_your_tools/connectors/about_connectors/), use the Import Scan form to [Add Findings](/en/connecting_your_tools/import_scan_files/import_scan_ui/), or use [Smart Upload](/en/connecting_your_tools/import_scan_files/smart_upload/) to handle infrastructure scanning tools.
+
+3. The **Manage** section allows you to view different objects in the [Product Hierarchy](/en/working_with_findings/organizing_engagements_tests/product_hierarchy/), with views for Product Types, Products, Engagements, Tests, Findings, Risk Acceptances, Endpoints and Components.
+
+4. The **Settings** section allows you to configure your DefectDojo instance, including your License, Cloud Settings, Users, Feature Configuration and admin-level Enterprise Settings.
+
+The Enterprise settings section contains the System Settings, Jira Instances, Deduplication Settings, SAML, OAuth, Login and MFA forms.
+
+5. The beta UI also has a **new table format** to help with navigation. This table is used with all [Product Hierarchy](/en/working_with_findings/organizing_engagements_tests/product_hierarchy/). Each column can be clicked on to apply a relevant filter, and columns can be reordered to present data however you like.
+
+6. The table also has a **"Toggle Columns"** menu which can add or remove columns from the table.
+
+## New Dashboards
+
+New metrics visualizations are included in the Beta UI. All of these reports can be filtered and exported as PDF to share them with a wider audience.
+
+![image](images/program_insights.png)
+
+- The **Executive Insights** dashboard displays the current state of your Products and Product Types.
+- **Program Insights** dashboard displays the effectiveness of your security team and the cost savings associated with separating duplicates and false positives from actionable Findings.
+- **Remediation Insights** displays your effectiveness at remediating Findings.
+- **Tool Insights** displays the effectiveness of your tool suite (and Connectors pipelines) at detecting and reporting vulnerabilities.
diff --git a/docs/content/en/api/api-v2-docs.md b/docs/content/en/api/api-v2-docs.md
index 263a790f77a..b1ae1b8d890 100644
--- a/docs/content/en/api/api-v2-docs.md
+++ b/docs/content/en/api/api-v2-docs.md
@@ -5,9 +5,6 @@ draft: false
weight: 2
---
-
-
-
DefectDojo\'s API is created using [Django Rest
Framework](http://www.django-rest-framework.org/). The documentation of
each endpoint is available within each DefectDojo installation at
diff --git a/docs/content/en/changelog/changelog.md b/docs/content/en/changelog/changelog.md
index be48f1b4c1b..c386bdb6c03 100644
--- a/docs/content/en/changelog/changelog.md
+++ b/docs/content/en/changelog/changelog.md
@@ -7,12 +7,26 @@ Here are the release notes for **DefectDojo Pro (Cloud Version)**. These release
For Open Source release notes, please see the [Releases page on GitHub](https://github.com/DefectDojo/django-DefectDojo/releases), or alternatively consult the Open Source [upgrade notes](../../open_source/upgrading/upgrading_guide).
+## Jan 13, 2025: v2.42.1
+
+- **(API)** Pro users can now specify the fields they want to return in a given API payload. For example, this request will only return the title, severity and description fields for each Finding. (Pro)
+```
+curl -X 'GET' \
+ 'https://localhost/api/v2/findings/?response_fields=title,severity,description' \
+ -H 'accept: application/json'
+```
+
+## Jan 6, 2025: v2.42.0
+
+- **(API)** `/test_reimport` results can now be ordered via id, created, modified, version, branch_tag, build_id, and commit_hash.
+- **(Jira)** When a Risk Acceptance expires, linked Jira Group issues will now be updated to reflect the status change.
+
## Dec 31, 2024: v2.41.4
- **(API)** 'Force To Active / Verified' flag is no longer required when calling `/import-scan`, `/reimport-scan` endponts: a value of True now forces to Active, False now forces to Inactive, while setting a value of none (or not using the flag) will use the tool's status.
-- **(Beta UI)** Added ability to regenerate / copy your API token
-- **(Beta UI)** Fixed bug preventing date / planned remediation dates from being added via Bulk Edit
-- **(Import)** Added fields for EPSS score and percentile to Generic Findings Import parser
+- **(Beta UI)** Added ability to regenerate / copy your API token.
+- **(Beta UI)** Fixed bug preventing date / planned remediation dates from being added via Bulk Edit.
+- **(Import)** Added fields for EPSS score and percentile to Generic Findings Import parser.
## Dec 24, 2024: v2.41.3
diff --git a/docs/content/en/customize_dojo/notifications/configure_system_notifs.md b/docs/content/en/customize_dojo/notifications/configure_system_notifs.md
index 04ff29f635e..cc09adb3a45 100644
--- a/docs/content/en/customize_dojo/notifications/configure_system_notifs.md
+++ b/docs/content/en/customize_dojo/notifications/configure_system_notifs.md
@@ -20,4 +20,23 @@ Both an account’s Personal Notifications and the global System Notifications c
![image](images/Configure_System_&_Personal_Notifications_2.png)
-To set destinations for system wide email notifications (Email, Slack or MS Teams), see our [Guide](../email_slack_teams).
\ No newline at end of file
+To set destinations for system wide email notifications (Email, Slack or MS Teams), see our [Guide](../email_slack_teams).
+
+## Template Notifications
+
+Superusers also have access to a "Template" form. The Template Form allows you to set the default Personal Notifications that are enabled for any new user.
+
+## Where System Notifications Are Sent
+
+System notifications will be sent to:
+- the single email address specified in System Settings (if enabled)
+- any DefectDojo users with accounts and appropriate RBAC permissions
+- the System-wide Slack or Teams account.
+
+As with any notification in DefectDojo, System Notifications will only be sent to users that have access to the relevant data. So even if Product Notifications are set up System-Wide, users will only receive notifications for the Products that they have access to view.
+
+This restriction does not apply to System Notifications that are sent to a specific Email or Slack channel.
+
+See our guide on [Role-Based Access Control](../../user_management/about_perms_and_roles/) for more information on RBAC and setting permissions.
+
+However, the connected System Email, Slack and Teams accounts cannot apply RBAC as they are not associated with a specific DefectDojo user. **All selected system-wide notifications will be sent to these locations, so you should ensure that these channels can only be accessed by specific people in your organization.**
\ No newline at end of file
diff --git a/docs/content/en/open_source/archived_docs/usage/models.md b/docs/content/en/open_source/archived_docs/usage/models.md
index 9a9e68fce3c..f08996d96dc 100644
--- a/docs/content/en/open_source/archived_docs/usage/models.md
+++ b/docs/content/en/open_source/archived_docs/usage/models.md
@@ -3,9 +3,10 @@ title: "Core data classes"
description: "DefectDojo is made to be flexible to conform to your program, rather than making your team conform to the tool."
draft: false
weight: 1
+exclude_search: true
---
-{{ readFile "/docs/assets/svgs/DD-Hierarchy.svg" | safeHTML }}
+![image](images/dd-hierarchy.png)
## Product Type
diff --git a/docs/content/en/open_source/installation/architecture.md b/docs/content/en/open_source/installation/architecture.md
index 9a315959653..f998751ac21 100644
--- a/docs/content/en/open_source/installation/architecture.md
+++ b/docs/content/en/open_source/installation/architecture.md
@@ -5,7 +5,7 @@ draft: false
weight: 1
---
-{{ readFile "/docs/assets/svgs/DD-Architecture.svg" | safeHTML }}
+![image](images/dd-architecture.png)
## NGINX
diff --git a/docs/content/en/open_source/integrations b/docs/content/en/open_source/integrations
deleted file mode 100644
index 307f1029a0a..00000000000
--- a/docs/content/en/open_source/integrations
+++ /dev/null
@@ -1,129 +0,0 @@
----
-title: "Authentication via LDAP"
-description: "Authenticate users using LDAP"
-draft: false
-weight: 4
----
-
-## LDAP Authentication
-
-Out of the box Defect Dojo does not support LDAP authentication.
-
-*However*, since Defect Dojo is built using Django, it isn't too difficult to add support for LDAP.
-So long as you don't mind building your own Docker images...
-
-We will need to modify a grand total of 4-5 files, depending on how you want to pass Dojo your LDAP secrets.
-
- - Dockerfile.django-*
- - Dockerfile.nginx-*
- - requirements.txt
- - settings.dist.py
- - docker-compose.yml *(Optional)*
-
-
-#### Dockerfile modifications
-
-In both Dockerfile.django and Dockerfile.nginx, you want to add the following lines to the apt-get install layers:
-
-```bash
-libldap2-dev \
-libsasl2-dev \
-ldap-utils \
-```
-
-
-#### requirements.txt
-
-Please check for the latest version of these requirements at the time of implementation on pypi.org and use those if you can.
-
-- [https://pypi.org/project/python-ldap/](python-ldap)
-- [https://pypi.org/project/django-auth-ldap/](django-auth-ldap)
-
-Otherwise add the following to requirements.txt:
-
-```python
-python-ldap==3.4.2
-django-auth-ldap==4.1.0
-```
-
-
-#### settings.dist.py
-
-Find the settings file (hint: `/dojo/settings/settings.dist.py`) and add the following:
-
-At the top of the file:
-```python
-import ldap
-from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
-```
-
-Then further down add LDAP settings to the env dict:
-```python
-# LDAP
-DD_LDAP_SERVER_URI=(str, 'ldap://ldap.example.com'),
-DD_LDAP_BIND_DN=(str, ''),
-DD_LDAP_BIND_PASSWORD=(str, ''),
-```
-
-Then under the env dict add:
-```python
-AUTH_LDAP_SERVER_URI = env('DD_LDAP_SERVER_URI')
-AUTH_LDAP_BIND_DN = env('DD_LDAP_BIND_DN')
-AUTH_LDAP_BIND_PASSWORD = env('DD_LDAP_BIND_PASSWORD')
-AUTH_LDAP_USER_SEARCH = LDAPSearch(
- "ou=Groups,dc=example,dc=com", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"
-)
-
-AUTH_LDAP_USER_ATTR_MAP = {
- "first_name": "givenName",
- "last_name": "sn",
- "email": "mail",
-}
-```
-Please make sure to customise all of the LDAP search variables to match your company's configuration.
-
-
-For additional group controls you can add:
-```python
-# Set up the basic group parameters.
-AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
- "dc=example,dc=com",
- ldap.SCOPE_SUBTREE,
- "(objectClass=groupOfNames)",
-)
-AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr="cn")
-
-# Simple group restrictions
-AUTH_LDAP_REQUIRE_GROUP = "cn=DD_USER_ACTIVE,ou=Groups,dc=example,dc=com"
-
-AUTH_LDAP_USER_FLAGS_BY_GROUP = {
- "is_active": "cn=DD_USER_ACTIVE,ou=Groups,dc=example,dc=com",
- "is_staff": "cn=DD_USER_STAFF,ou=Groups,dc=example,dc=com",
- "is_superuser": "cn=DD_USER_ADMIN,ou=Groups,dc=example,dc=com",
-}
-```
-
-Then also add `'django_auth_ldap.backend.LDAPBackend'` to the `AUTHENTICATION_BACKENDS` variable, for example:
-```python
-AUTHENTICATION_BACKENDS = (
- 'django_auth_ldap.backend.LDAPBackend',
- 'django.contrib.auth.backends.RemoteUserBackend',
- 'django.contrib.auth.backends.ModelBackend',
-)
-```
-
-Read the docs for Django Authentication with LDAP here: https://django-auth-ldap.readthedocs.io/en/latest/
-
-#### docker-compose.yml
-
-In order to pass the variables to the settings.dist.py file via docker, it's a good idea to add these to the docker compose file.
-
-You can do this by adding the following variables to the environment section for the uwsgi image:
-```yaml
-DD_LDAP_SERVER_URI: "${DD_LDAP_SERVER_URI:-ldap://ldap.example.com}"
-DD_LDAP_BIND_DN: "${DD_LDAP_BIND_DN:-}"
-DD_LDAP_BIND_PASSWORD: "${DD_LDAP_BIND_PASSWORD:-}"
-```
-
-Alternatively you can set these values in a local_settings.py file.
-
diff --git a/docs/content/en/open_source/upgrading/2.42.md b/docs/content/en/open_source/upgrading/2.42.md
index c815a7794d3..918ffdb901c 100644
--- a/docs/content/en/open_source/upgrading/2.42.md
+++ b/docs/content/en/open_source/upgrading/2.42.md
@@ -1,7 +1,7 @@
---
title: 'Upgrading to DefectDojo Version 2.42.x'
toc_hide: true
-weight: -20241104
+weight: -20241202
description: No special instructions.
---
There are no special instructions for upgrading to 2.42.x. Check the [Release Notes](https://github.com/DefectDojo/django-DefectDojo/releases/tag/2.42.0) for the contents of the release.
diff --git a/docs/content/en/share_your_findings/jira_integration/_index.md b/docs/content/en/share_your_findings/jira_integration/_index.md
index c9cc3b07e3d..fc88e4fa784 100644
--- a/docs/content/en/share_your_findings/jira_integration/_index.md
+++ b/docs/content/en/share_your_findings/jira_integration/_index.md
@@ -1,5 +1,5 @@
---
-title: "Connect To Jira"
+title: "Send Findings To Jira"
description: "Send DefectDojo Findings to one or more Jira Projects"
summary: ""
date: 2023-09-07T16:06:50+02:00
diff --git a/docs/content/en/share_your_findings/jira_integration/add_jira_to_product.md b/docs/content/en/share_your_findings/jira_integration/add_jira_to_product.md
index 2d26e695d69..a56b5d06f5e 100644
--- a/docs/content/en/share_your_findings/jira_integration/add_jira_to_product.md
+++ b/docs/content/en/share_your_findings/jira_integration/add_jira_to_product.md
@@ -37,19 +37,19 @@ Jira settings are located near the bottom of the Product Settings page.
![image](images/Add_a_Connected_Jira_Project_to_a_Product_2.png)
-#### **Jira Instance**
+### Jira Instance
If you have multiple instances of Jira set up, for separate products or teams within your organization, you can indicate which Jira Project you want DefectDojo to create Issues in. Select a Project from the drop\-down menu.
If this menu doesn't list any Jira instances, confirm that those Projects are connected in your global Jira Configuration for DefectDojo \- yourcompany.defectdojo.com/jira.
-#### **Project key**
+### Project key
This is the key of the Project that you want to use with DefectDojo. The Project Key for a given project can be found in the URL.
![image](images/Add_a_Connected_Jira_Project_to_a_Product_3.png)
-#### **Issue template**
+### Issue template
Here you can determine how much DefectDojo metadata you want to send to Jira. Select one of two options:
@@ -65,7 +65,7 @@ Here is an example of a **jira\_full** Issue:
![image](images/Add_a_Connected_Jira_Project_to_a_Product_5.png)
-#### **Component**
+### Component
If you manage your Jira project using Components, you can assign the appropriate Component for DefectDojo here.
@@ -87,19 +87,23 @@ Select the relevant labels that you want the Issue to be created with in Jira, e
![image](images/Add_a_Connected_Jira_Project_to_a_Product_6.png)
-#### **Default assignee**
+### Default assignee
The name of the default assignee in Jira. If left blank, DefectDojo will follow the default behaviour in your Jira Project when creating Issues.
-#### Checkbox options
+## Additional Jira Options
-![image](images/Add_a_Connected_Jira_Project_to_a_Product_7.png)
+### Enable Connection With Jira Project
-#### **Add vulnerability Id as a Jira label**
+Jira integrations can be removed from your instance only if no related Issues have been created. If Issues have been created, there is no way to completely remove a Jira Instance from DefectDojo.
+
+However, you can disable your Jira integration by disabling it at the Product level. This will not delete or change any existing Jira tickets created by DefectDojo, but will disable any further updates.
+
+### Add Vulnerability Id as a Jira label
This allows you to add the Vulnerability ID data as a Jira Label automatically. Vulnerability IDs are added to Findings from individual security tools \- these may be Common Vulnerabilities and Exposures (CVE) IDs or a different format, specific to the tool reporting the Finding.
-#### **Enable engagement epic mapping**
+### Enable Engagement Epic Mapping
In DefectDojo, Engagements represent a collection of work. Each Engagement contains one or more tests, which contain one or more Findings which need to be mitigated. Epics in Jira work in a similar way, and this checkbox allows you to push Engagements to Jira as Epics.
@@ -110,21 +114,21 @@ In DefectDojo, Engagements represent a collection of work. Each Engagement conta
![image](images/Add_a_Connected_Jira_Project_to_a_Product_9.png)
-#### **Push All Issues**
+### Push All Issues
If checked, DefectDojo will automatically push any Active and Verified Findings to Jira as Issues. If left unchecked, all Findings will need to be pushed to Jira manually.
-#### **Push notes**
+### Push Notes
If enabled, Jira comments will populate on the associated Finding in DefectDojo, under Notes on the issue(screenshot), and vice versa; Notes on Findings will be added to the associated Jira Issue as Comments.
-#### **Send SLA notifications as comment?**
+### Send SLA Notifications As Comments
If enabled, any Issue which breaches DefectDojo’s Service Level Agreement rules will have comments added to the Jira issue indicating this. These comments will be posted daily until the Issue is resolved.
Service Level Agreements can be configured under **Configuration \> SLA Configuration** in DefectDojo and assigned to each Product.
-#### **Send Risk Acceptance expiration notifications as comment?**
+### Send Risk Acceptance Expiration Notifications As Comment?
If enabled, any Issue where the associated DefectDojo Risk Acceptance expires will have a comment added to the Jira issue indicating this. These comments will be posted daily until the Issue is resolved.
diff --git a/docs/content/en/share_your_findings/jira_integration/connect_to_jira.md b/docs/content/en/share_your_findings/jira_integration/connect_to_jira.md
index 100a7125ea5..7e16921542b 100644
--- a/docs/content/en/share_your_findings/jira_integration/connect_to_jira.md
+++ b/docs/content/en/share_your_findings/jira_integration/connect_to_jira.md
@@ -149,6 +149,14 @@ If this doesn’t work correctly, it could be due to a Firewall issue on your Ji
* DefectDojo's Firewall Rules include a checkbox for **Jira Cloud,** which needs to be enabled before DefectDojo can receive Webhook messages from Jira.
+## Disconnecting from Jira
+
+Jira integrations can be removed from your instance only if no related Issues have been created. If Issues have been created, there is no way to completely remove a Jira Instance from DefectDojo.
+
+However, you can disable your Jira integration by disabling it at the Product level. From the **Edit Product** form (Classic UI) or from the **Jira Product Settings** (Beta UI) you can uncheck the "Enable Connection With Jira Project" option. This will not delete or change any existing Jira tickets created by DefectDojo, but will disable any further updates.
+
+See our guide on [Adding Jira To a Product](../jira_integration/add_jira_to_product) for more information on Product-level settings.
+
## Next steps
* Now that you've set up your Jira Configuration, **[link it to one or more of your Products](../add_jira_to_product)** to have your Findings populate into Jira.
diff --git a/docs/content/en/share_your_findings/jira_integration/troubleshooting_jira.md b/docs/content/en/share_your_findings/jira_integration/troubleshooting_jira.md
index bcb8fbfe044..88a95811760 100644
--- a/docs/content/en/share_your_findings/jira_integration/troubleshooting_jira.md
+++ b/docs/content/en/share_your_findings/jira_integration/troubleshooting_jira.md
@@ -1,6 +1,6 @@
---
title: "Troubleshooting Jira errors"
-description: "Set up a Jira Configuration in DefectDojo - step 1 of working with Jira"
+description: "Fixing issues with a Jira integration"
---
Here are some common issues with the Jira integration, and ways to address them.
diff --git a/docs/content/en/share_your_findings/pro_reports/using_the_report_builder.md b/docs/content/en/share_your_findings/pro_reports/using_the_report_builder.md
index 524183a1c26..70982a0dafb 100644
--- a/docs/content/en/share_your_findings/pro_reports/using_the_report_builder.md
+++ b/docs/content/en/share_your_findings/pro_reports/using_the_report_builder.md
@@ -1,6 +1,7 @@
---
title: "Using the Report Builder"
description: "Build and publish custom reports for external audiences, or your own records"
+weight: 1
---
DefectDojo allows you to create Custom Reports for external audiences, which summarize the Findings or Endpoints that you wish to report on. Custom Reports can include branding and boilerplate text, and can also be used as **[Templates](https://docs.defectdojo.com/en/pro_reports/working-with-generated-reports/)** for future reports.
@@ -45,6 +46,32 @@ Widgets are content elements of a report which can be added by dragging and drop
* Widgets can also be collapsed by clicking on the grey header, for ease in navigation through a report builder.
* The Findings Widget, WYSIWYG Widget and the Endpoints widget can be used more than once.
+For more information about Report Widgets, see our [Report Widget index](./#report-widget-index).
+
+## Step 3: Publish and view your Report
+
+Once you have finished building your report, you can generate it by clicking the green ‘**Run’** button at the bottom of the **Report Format** section.
+
+This will automatically take you to the Generated Reports page, and your report will begin to generate in the background. You can check on the Status of your report by reading the Status column next to it, and refreshing the page periodically.
+
+Once your report has generated, you can view it by either clicking on the **Status** (which will be set to ‘Complete: View Report’), or by opening the **⋮** menu next to your report and selecting **View Report**.
+
+![image](images/Using_the_Report_Builder_14.png)
+
+## Step 4: Exporting a Report
+
+Only DefectDojo users will have access to Reports stored in the software, but Reports are set up in a way where they can be exported or printed easily.
+
+The easiest method to use is to Print To PDF \- with an HTML Report open, open a **Print** dialog in your browser and set **Save To PDF** as the **Print Destination**.
+
+![image](images/Using_the_Report_Builder_15.png)
+
+## Report formatting suggestions
+
+* WYSIWYG sections can be used to contextualize or summarize Finding lists. We recommend using this widget throughout your report in between Findings or Vulnerable Endpoints widgets.
+
+## Report Widget Index
+
### Cover Page Widget
The Cover Page Widget allows you to set a Heading, Sub heading and additional metadata for your report. You can only have a single Cover Page for a given Report.
@@ -124,26 +151,4 @@ Select the parameters for the Endpoints you wish to include here and click the *
This Widget will render a light grey horizontal line to divide between sections.
-![image](images/Using_the_Report_Builder_13.png)
-
-## Step 3: Publishing and viewing your Report
-
-Once you have finished building your report, you can generate it by clicking the green ‘**Run’** button at the bottom of the **Report Format** section.
-
-This will automatically take you to the Generated Reports page, and your report will begin to generate in the background. You can check on the Status of your report by reading the Status column next to it, and refreshing the page periodically.
-
-Once your report has generated, you can view it by either clicking on the **Status** (which will be set to ‘Complete: View Report’), or by opening the **⋮** menu next to your report and selecting **View Report**.
-
-![image](images/Using_the_Report_Builder_14.png)
-
-## Step 4: Exporting a Report
-
-Only DefectDojo users will have access to Reports stored in the software, but Reports are set up in a way where they can be exported or printed easily.
-
-The easiest method to use is to Print To PDF \- with an HTML Report open, open a **Print** dialog in your browser and set **Save To PDF** as the **Print Destination**.
-
-![image](images/Using_the_Report_Builder_15.png)
-
-## Report formatting suggestions
-
-* WYSIWYG sections can be used to contextualize or summarize Finding lists. We recommend using this widget throughout your report in between Findings or Vulnerable Endpoints widgets.
+![image](images/Using_the_Report_Builder_13.png)
\ No newline at end of file
diff --git a/docs/content/en/share_your_findings/pro_reports/working_with_generated_reports.md b/docs/content/en/share_your_findings/pro_reports/working_with_generated_reports.md
index fc49e0c8cd3..a63f07cf01f 100644
--- a/docs/content/en/share_your_findings/pro_reports/working_with_generated_reports.md
+++ b/docs/content/en/share_your_findings/pro_reports/working_with_generated_reports.md
@@ -1,68 +1,48 @@
---
-title: "Working with Generated Reports"
+title: "Templates and Historical Reports"
description: "Use a report as a template, or re-run an existing report with updated data"
+weight: 2
---
Once you have created one or more **Reports** in DefectDojo you can take further actions, including:
-
* Using a report as a template for subsequent reports
-* Re\-running a report with updated data
-* Deleting an old or unused reportsa
-
-![image](images/Working_with_Generated_Reports.png)
-# Use a report as a Template
+* Re-running a report with updated data
+* Deleting an old or unused report
-DefectDojo allows you to easily create Report templates with your team logo, boilerplate text and a standardized content order.
+![image](images/Working_with_Generated_Reports.png)
+## Use a report as a Template
+DefectDojo allows you to easily create Report templates with your team logo, boilerplate text and a standardized content order.
If you want to change the way a report is set up, or create a new one with a similar layout, you can re\-open the Report Builder by selecting **View Template** from the **â‹®** menu next to the report you wish to use as a template.
-
-
There are two places where you can find a Report Template to use:
-
1. From the **Generated Reports** page, where you can see a list of completed reports
2. From the **Report Templates** page, where you can see a list of previously run reports, including reports which were deleted from the **Generated Reports** page.
Both of these pages can be found in the 📄 **Reports** tab on the sidebar.
-
-
![image](images/Working_with_Generated_Reports_2.png)
-To access the **Report Templates** page, open 📄**Reports \> Report Templates** from the sidebar. From that table, you can open the report builder by clicking the **⋮** menu next to the report you wish to use as a template.
-
+To access the **Report Templates** page, open 📄**Reports \> Report Templates** from the sidebar. From that table, you can open the report builder by clicking the **⋮** menu next to the report you wish to use as a template.
Every time you make changes to a template or previous report, the result will be saved as a **new** report under Generated Reports so that you don't lose the older version. If you like, the older version can be deleted.
-
-
-
-# Re\-Running a Report
-
+## Re\-Running a Report
DefectDojo Reports are ‘frozen in time’ \- to keep your records consistent, they do not update automatically when DefectDojo experiences data changes.
-
-
However, if you want to create an updated version of a previously created report, you can do so by selecting **Re\-run Report** from the **â‹®** menu next to the report you wish to generate.
-
-
Selecting this option will create a new report in the **Generated Reports** list, with a different **Created** timestamp to indicate that the report was run at a separate time.
-
-
![image](images/Working_with_Generated_Reports_3.png)
-# Deleting a Report
-
+## Deleting a Report
If you no longer need a report, you can delete it by selecting **Delete Report** from the **â‹®** menu next to the report you wish to delete. Note that this will only remove the report from the **Generated Reports** list \- a record of the report will still exist under **Report Templates** if you want to re\-run it.
-
-
diff --git a/docs/package-lock.json b/docs/package-lock.json
index 12994fca578..a4b2aa3a367 100644
--- a/docs/package-lock.json
+++ b/docs/package-lock.json
@@ -4717,9 +4717,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.0.7",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz",
- "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==",
+ "version": "6.0.10",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.10.tgz",
+ "integrity": "sha512-MEszunEcMo6pFsfXN1GhCFQqnE25tWRH0MA4f0Q7uanACi4y1Us+ZGpTMnITwCTnYzB2b9cpmnelTlxgTBmaBA==",
"dev": true,
"license": "MIT",
"dependencies": {
diff --git a/dojo/api_v2/serializers.py b/dojo/api_v2/serializers.py
index 38a36159425..1ee3a000d30 100644
--- a/dojo/api_v2/serializers.py
+++ b/dojo/api_v2/serializers.py
@@ -2301,7 +2301,7 @@ def setup_common_context(self, data: dict) -> dict:
"""
context = dict(data)
# update some vars
- context["scan"] = data.pop("file")
+ context["scan"] = data.pop("file", None)
if context.get("auto_create_context"):
environment = Development_Environment.objects.get_or_create(name=data.get("environment", "Development"))[0]
diff --git a/dojo/db_migrations/0219_system_settings_enforce_verified_status_jira_and_more.py b/dojo/db_migrations/0219_system_settings_enforce_verified_status_jira_and_more.py
new file mode 100644
index 00000000000..839ce662885
--- /dev/null
+++ b/dojo/db_migrations/0219_system_settings_enforce_verified_status_jira_and_more.py
@@ -0,0 +1,33 @@
+# Generated by Django 5.1.4 on 2025-01-10 16:01
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dojo', '0218_system_settings_enforce_verified_status_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='system_settings',
+ name='enforce_verified_status_jira',
+ field=models.BooleanField(default=True, help_text='When enabled, findings must have a verified status to be pushed to jira.', verbose_name='Enforce Verified Status - Jira'),
+ ),
+ migrations.AddField(
+ model_name='system_settings',
+ name='enforce_verified_status_metrics',
+ field=models.BooleanField(default=True, help_text='When enabled, findings must have a verified status to be counted in metric calculations, be included in reports, and filters.', verbose_name='Enforce Verified Status - Metrics'),
+ ),
+ migrations.AddField(
+ model_name='system_settings',
+ name='enforce_verified_status_product_grading',
+ field=models.BooleanField(default=True, help_text="When enabled, findings must have a verified status to be considered as part of a product's grading.", verbose_name='Enforce Verified Status - Product Grading'),
+ ),
+ migrations.AlterField(
+ model_name='system_settings',
+ name='enforce_verified_status',
+ field=models.BooleanField(default=True, help_text='When enabled, features such as product grading, jira integration, metrics, and reports will only interact with verified findings. This setting will override individually scoped verified toggles.', verbose_name='Enforce Verified Status - Globally'),
+ ),
+ ]
diff --git a/dojo/filters.py b/dojo/filters.py
index b4c452c2fea..daa73375945 100644
--- a/dojo/filters.py
+++ b/dojo/filters.py
@@ -21,6 +21,7 @@
CharFilter,
DateFilter,
DateFromToRangeFilter,
+ DateTimeFilter,
FilterSet,
ModelChoiceFilter,
ModelMultipleChoiceFilter,
@@ -1411,6 +1412,15 @@ class ApiProductFilter(DojoFilter):
)
+class PercentageRangeFilter(RangeFilter):
+ def filter(self, qs, value):
+ if value is not None:
+ start = value.start / decimal.Decimal("100.0") if value.start else None
+ stop = value.stop / decimal.Decimal("100.0") if value.stop else None
+ value = slice(start, stop)
+ return super().filter(qs, value)
+
+
class ApiFindingFilter(DojoFilter):
# BooleanFilter
active = BooleanFilter(field_name="active")
@@ -1456,13 +1466,30 @@ class ApiFindingFilter(DojoFilter):
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")
+ mitigated_on = DateTimeFilter(field_name="mitigated", lookup_expr="exact", method="filter_mitigated_on")
+ mitigated_before = DateTimeFilter(field_name="mitigated", lookup_expr="lt")
+ mitigated_after = DateTimeFilter(field_name="mitigated", lookup_expr="gt", label="Mitigated After", method="filter_mitigated_after")
# NumberInFilter
cwe = NumberInFilter(field_name="cwe", lookup_expr="in")
defect_review_requested_by = NumberInFilter(field_name="defect_review_requested_by", lookup_expr="in")
endpoints = NumberInFilter(field_name="endpoints", lookup_expr="in")
+ epss_score = PercentageRangeFilter(
+ field_name="epss_score",
+ label="EPSS score range",
+ help_text=(
+ "The range of EPSS score percentages to filter on; the min input is a lower bound, "
+ "the max is an upper bound. Leaving one empty will skip that bound (e.g., leaving "
+ "the min bound input empty will filter only on the max bound -- filtering on "
+ '"less than or equal"). Leading 0 required.'
+ ))
+ epss_percentile = PercentageRangeFilter(
+ field_name="epss_percentile",
+ label="EPSS percentile range",
+ help_text=(
+ "The range of EPSS percentiles to filter on; the min input is a lower bound, the max "
+ "is an upper bound. Leaving one empty will skip that bound (e.g., leaving the min bound "
+ 'input empty will filter only on the max bound -- filtering on "less than or equal"). Leading 0 required.'
+ ))
found_by = NumberInFilter(field_name="found_by", lookup_expr="in")
id = NumberInFilter(field_name="id", lookup_expr="in")
last_reviewed_by = NumberInFilter(field_name="last_reviewed_by", lookup_expr="in")
@@ -1544,6 +1571,20 @@ class Meta:
exclude = ["url", "thread_id", "notes", "files",
"line", "cve"]
+ def filter_mitigated_after(self, queryset, name, value):
+ if value.hour == 0 and value.minute == 0 and value.second == 0:
+ value = value.replace(hour=23, minute=59, second=59)
+
+ return queryset.filter(mitigated__gt=value)
+
+ def filter_mitigated_on(self, queryset, name, value):
+ if value.hour == 0 and value.minute == 0 and value.second == 0:
+ # we have a simple date without a time, lets get a range from this morning to tonight at 23:59:59:999
+ nextday = value + timedelta(days=1)
+ return queryset.filter(mitigated__gte=value, mitigated__lt=nextday)
+
+ return queryset.filter(mitigated=value)
+
class PercentageFilter(NumberFilter):
def __init__(self, *args, **kwargs):
@@ -1564,15 +1605,6 @@ def filter_percentage(self, queryset, name, value):
return queryset.filter(**lookup_kwargs)
-class PercentageRangeFilter(RangeFilter):
- def filter(self, qs, value):
- if value is not None:
- start = value.start / decimal.Decimal("100.0") if value.start else None
- stop = value.stop / decimal.Decimal("100.0") if value.stop else None
- value = slice(start, stop)
- return super().filter(qs, value)
-
-
class FindingFilterHelper(FilterSet):
title = CharFilter(lookup_expr="icontains")
date = DateRangeFilter(field_name="date", label="Date Discovered")
@@ -1587,9 +1619,9 @@ class FindingFilterHelper(FilterSet):
duplicate = ReportBooleanFilter()
is_mitigated = ReportBooleanFilter()
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")
+ mitigated_on = DateTimeFilter(field_name="mitigated", lookup_expr="exact", label="Mitigated On", method="filter_mitigated_on")
+ mitigated_before = DateTimeFilter(field_name="mitigated", lookup_expr="lt", label="Mitigated Before")
+ mitigated_after = DateTimeFilter(field_name="mitigated", lookup_expr="gt", label="Mitigated After", method="filter_mitigated_after")
planned_remediation_date = DateRangeOmniFilter()
planned_remediation_version = CharFilter(lookup_expr="icontains", label=_("Planned remediation version"))
file_path = CharFilter(lookup_expr="icontains")
@@ -1705,6 +1737,20 @@ def set_date_fields(self, *args: list, **kwargs: dict):
self.form.fields["mitigated_after"].widget = date_input_widget
self.form.fields["cwe"].choices = cwe_options(self.queryset)
+ def filter_mitigated_after(self, queryset, name, value):
+ if value.hour == 0 and value.minute == 0 and value.second == 0:
+ value = value.replace(hour=23, minute=59, second=59)
+
+ return queryset.filter(mitigated__gt=value)
+
+ def filter_mitigated_on(self, queryset, name, value):
+ if value.hour == 0 and value.minute == 0 and value.second == 0:
+ # we have a simple date without a time, lets get a range from this morning to tonight at 23:59:59:999
+ nextday = value + timedelta(days=1)
+ return queryset.filter(mitigated__gte=value, mitigated__lt=nextday)
+
+ return queryset.filter(mitigated=value)
+
class FindingFilterWithoutObjectLookups(FindingFilterHelper, FindingTagStringFilter):
test__engagement__product__prod_type = NumberFilter(widget=HiddenInput())
diff --git a/dojo/forms.py b/dojo/forms.py
index 3837b4d3933..04ed0d424d7 100644
--- a/dojo/forms.py
+++ b/dojo/forms.py
@@ -3074,7 +3074,7 @@ def clean(self):
elif self.cleaned_data.get("push_to_jira", None):
active = self.finding_form["active"].value()
verified = self.finding_form["verified"].value()
- if not active or (not verified and get_system_setting("enforce_verified_status", True)):
+ if not active or (not verified and (get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_jira", True))):
logger.debug("Findings must be active and verified to be pushed to JIRA")
error_message = "Findings must be active and verified to be pushed to JIRA"
self.add_error("push_to_jira", ValidationError(error_message, code="not_active_or_verified"))
diff --git a/dojo/jira_link/helper.py b/dojo/jira_link/helper.py
index 8aff8972401..a557a05a3c1 100644
--- a/dojo/jira_link/helper.py
+++ b/dojo/jira_link/helper.py
@@ -146,7 +146,7 @@ def can_be_pushed_to_jira(obj, form=None):
logger.debug("can_be_pushed_to_jira: %s, %s, %s", active, verified, severity)
- isenforced = get_system_setting("enforce_verified_status", True)
+ isenforced = get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_jira", True)
if not active or (not verified and isenforced):
logger.debug("Findings must be active and verified, if enforced by system settings, to be pushed to JIRA")
@@ -1116,7 +1116,6 @@ def get_issuetype_fields(
except JIRAError as e:
e.text = f"Jira API call 'createmeta' failed with status: {e.status_code} and message: {e.text}"
raise
-
project = None
try:
project = meta["projects"][0]
diff --git a/dojo/management/commands/jira_async_updates.py b/dojo/management/commands/jira_async_updates.py
index a49ae04050a..222671daa75 100644
--- a/dojo/management/commands/jira_async_updates.py
+++ b/dojo/management/commands/jira_async_updates.py
@@ -22,7 +22,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
findings = Finding.objects.exclude(jira_issue__isnull=True)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_jira", True):
findings = findings.filter(verified=True, active=True)
else:
findings = findings.filter(active=True)
diff --git a/dojo/management/commands/push_to_jira_update.py b/dojo/management/commands/push_to_jira_update.py
index 164bc8e9704..d70a4b96b21 100644
--- a/dojo/management/commands/push_to_jira_update.py
+++ b/dojo/management/commands/push_to_jira_update.py
@@ -23,7 +23,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
findings = Finding.objects.exclude(jira_issue__isnull=True)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_jira", True):
findings = findings.filter(verified=True, active=True)
else:
findings = findings.filter(active=True)
diff --git a/dojo/metrics/utils.py b/dojo/metrics/utils.py
index 9a4b9f6bb04..cbe40b85bcf 100644
--- a/dojo/metrics/utils.py
+++ b/dojo/metrics/utils.py
@@ -109,7 +109,7 @@ def finding_queries(
weekly_counts = query_counts_for_period(MetricsPeriod.WEEK, weeks_between)
top_ten = get_authorized_products(Permissions.Product_View)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
top_ten = top_ten.filter(engagement__test__finding__verified=True)
top_ten = top_ten.filter(engagement__test__finding__false_p=False,
diff --git a/dojo/metrics/views.py b/dojo/metrics/views.py
index 592899bcdc9..4b037bcbd75 100644
--- a/dojo/metrics/views.py
+++ b/dojo/metrics/views.py
@@ -197,7 +197,7 @@ def simple_metrics(request):
date__year=now.year,
)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
total = total.filter(verified=True)
total = total.distinct()
@@ -308,7 +308,7 @@ def product_type_counts(request):
then=Value(1)),
output_field=IntegerField())))["total"]
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
overall_in_pt = Finding.objects.filter(date__lt=end_date,
verified=True,
false_p=False,
@@ -509,7 +509,7 @@ def product_tag_counts(request):
then=Value(1)),
output_field=IntegerField())))["total"]
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
overall_in_pt = Finding.objects.filter(date__lt=end_date,
verified=True,
false_p=False,
@@ -685,7 +685,7 @@ def view_engineer(request, eid):
raise PermissionDenied
now = timezone.now()
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
findings = Finding.objects.filter(reporter=user, verified=True)
else:
findings = Finding.objects.filter(reporter=user)
diff --git a/dojo/models.py b/dojo/models.py
index 99074a9cf3b..ff34cde034a 100644
--- a/dojo/models.py
+++ b/dojo/models.py
@@ -5,6 +5,7 @@
import os
import re
import warnings
+from contextlib import suppress
from datetime import datetime
from pathlib import Path
from uuid import uuid4
@@ -363,10 +364,32 @@ class System_Settings(models.Model):
enforce_verified_status = models.BooleanField(
default=True,
- verbose_name=_("Enforce Verified Status"),
- help_text=_("When enabled, features such as product grading, jira "
- "integration, metrics, and reports will only interact "
- "with verified findings.",
+ verbose_name=_("Enforce Verified Status - Globally"),
+ help_text=_(
+ "When enabled, features such as product grading, jira "
+ "integration, metrics, and reports will only interact "
+ "with verified findings. This setting will override "
+ "individually scoped verified toggles.",
+ ),
+ )
+ enforce_verified_status_jira = models.BooleanField(
+ default=True,
+ verbose_name=_("Enforce Verified Status - Jira"),
+ help_text=_("When enabled, findings must have a verified status to be pushed to jira."),
+ )
+ enforce_verified_status_product_grading = models.BooleanField(
+ default=True,
+ verbose_name=_("Enforce Verified Status - Product Grading"),
+ help_text=_(
+ "When enabled, findings must have a verified status to be considered as part of a product's grading.",
+ ),
+ )
+ enforce_verified_status_metrics = models.BooleanField(
+ default=True,
+ verbose_name=_("Enforce Verified Status - Metrics"),
+ help_text=_(
+ "When enabled, findings must have a verified status to be counted in metric calculations, "
+ "be included in reports, and filters.",
),
)
@@ -1236,7 +1259,7 @@ def open_findings(self, start_date=None, end_date=None):
date__range=[start_date,
end_date])
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
findings = findings.filter(verified=True)
critical = findings.filter(severity="Critical").count()
@@ -1553,7 +1576,7 @@ def unaccepted_open_findings(self):
from dojo.utils import get_system_setting
findings = Finding.objects.filter(risk_accepted=False, active=True, duplicate=False, test__engagement=self)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
findings = findings.filter(verified=True)
return findings
@@ -1575,7 +1598,10 @@ def delete(self, *args, **kwargs):
import dojo.finding.helper as helper
helper.prepare_duplicates_for_delete(engagement=self)
super().delete(*args, **kwargs)
- calculate_grade(self.product)
+ with suppress(Product.DoesNotExist):
+ # Suppressing a potential issue created from async delete removing
+ # related objects in a separate task
+ calculate_grade(self.product)
def inherit_tags(self, potentially_existing_tags):
# get a copy of the tags to be inherited
@@ -2123,7 +2149,7 @@ def copy(self, engagement=None):
def unaccepted_open_findings(self):
from dojo.utils import get_system_setting
findings = Finding.objects.filter(risk_accepted=False, active=True, duplicate=False, test=self)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
findings = findings.filter(verified=True)
return findings
@@ -2185,7 +2211,10 @@ def hash_code_allows_null_cwe(self):
def delete(self, *args, **kwargs):
logger.debug("%d test delete", self.id)
super().delete(*args, **kwargs)
- calculate_grade(self.engagement.product)
+ with suppress(Engagement.DoesNotExist, Product.DoesNotExist):
+ # Suppressing a potential issue created from async delete removing
+ # related objects in a separate task
+ calculate_grade(self.engagement.product)
@property
def statistics(self):
@@ -2745,14 +2774,17 @@ def delete(self, *args, **kwargs):
import dojo.finding.helper as helper
helper.finding_delete(self)
super().delete(*args, **kwargs)
- calculate_grade(self.test.engagement.product)
+ with suppress(Test.DoesNotExist, Engagement.DoesNotExist, Product.DoesNotExist):
+ # Suppressing a potential issue created from async delete removing
+ # related objects in a separate task
+ calculate_grade(self.test.engagement.product)
# only used by bulk risk acceptance api
@classmethod
def unaccepted_open_findings(cls):
from dojo.utils import get_system_setting
results = cls.objects.filter(active=True, duplicate=False, risk_accepted=False)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
results = results.filter(verified=True)
return results
diff --git a/dojo/reports/views.py b/dojo/reports/views.py
index 061476efe1b..4bcd7386769 100644
--- a/dojo/reports/views.py
+++ b/dojo/reports/views.py
@@ -88,7 +88,7 @@ def get_endpoints(self, request: HttpRequest):
finding__duplicate=False,
finding__out_of_scope=False,
)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
endpoints = endpoints.filter(finding__active=True)
endpoints = endpoints.distinct()
@@ -194,7 +194,7 @@ def report_endpoints(request):
finding__duplicate=False,
finding__out_of_scope=False,
)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
endpoints = endpoints.filter(finding__active=True)
endpoints = endpoints.distinct()
@@ -271,7 +271,7 @@ def product_endpoint_report(request, pid):
finding__duplicate=False,
finding__out_of_scope=False)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
endpoint_ids = endpoints.filter(finding__active=True).values_list("id", flat=True)
endpoint_ids = endpoints.values_list("id", flat=True)
diff --git a/dojo/reports/widgets.py b/dojo/reports/widgets.py
index 7439a4bb8f3..f0559d23098 100644
--- a/dojo/reports/widgets.py
+++ b/dojo/reports/widgets.py
@@ -378,7 +378,7 @@ def report_widget_factory(json_data=None, request=None, user=None, finding_notes
finding__duplicate=False,
finding__out_of_scope=False,
)
- if get_system_setting("enforce_verified_status", True):
+ if get_system_setting("enforce_verified_status", True) or get_system_setting("enforce_verified_status_metrics", True):
endpoints = endpoints.filter(finding__verified=True)
endpoints = endpoints.distinct()
diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py
index ed1ee76c5c9..7d1513f13a6 100644
--- a/dojo/settings/settings.dist.py
+++ b/dojo/settings/settings.dist.py
@@ -1763,6 +1763,7 @@ def saml2_attrib_map_format(dict):
"RHEA": "https://access.redhat.com/errata/",
"FEDORA": "https://bodhi.fedoraproject.org/updates/",
"ALSA": "https://osv.dev/vulnerability/", # e.g. https://osv.dev/vulnerability/ALSA-2024:0827
+ "ALBA": "https://osv.dev/vulnerability/", # e.g. https://osv.dev/vulnerability/ALBA-2019:3411
"USN": "https://ubuntu.com/security/notices/", # e.g. https://ubuntu.com/security/notices/USN-6642-1
"DLA": "https://security-tracker.debian.org/tracker/", # e.g. https://security-tracker.debian.org/tracker/DLA-3917-1
"DSA": "https://security-tracker.debian.org/tracker/", # e.g. https://security-tracker.debian.org/tracker/DSA-5791-1
diff --git a/dojo/templates/dojo/notifications.html b/dojo/templates/dojo/notifications.html
index 81fac49d5cc..9a87197c35e 100644
--- a/dojo/templates/dojo/notifications.html
+++ b/dojo/templates/dojo/notifications.html
@@ -162,7 +162,7 @@