diff --git a/dojo/db_migrations/0255_remove_system_settings_product_grade.py b/dojo/db_migrations/0255_remove_system_settings_product_grade.py new file mode 100644 index 00000000000..c39857bda0a --- /dev/null +++ b/dojo/db_migrations/0255_remove_system_settings_product_grade.py @@ -0,0 +1,17 @@ +# Generated by Django 5.2.9 on 2026-01-09 23:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('dojo', '0254_remove_vulnerability_id_template_model'), + ] + + operations = [ + migrations.RemoveField( + model_name='system_settings', + name='product_grade', + ), + ] diff --git a/dojo/fixtures/defect_dojo_sample_data.json b/dojo/fixtures/defect_dojo_sample_data.json index a9dbc052b5d..fe8b78b2229 100644 --- a/dojo/fixtures/defect_dojo_sample_data.json +++ b/dojo/fixtures/defect_dojo_sample_data.json @@ -814,7 +814,6 @@ "url_prefix": "", "team_name": "", "enable_product_grade": true, - "product_grade": "def grade_product(crit, high, med, low):\r\n health=100\r\n if crit > 0:\r\n health = 40\r\n health = health - ((crit - 1) * 5)\r\n if high > 0:\r\n if health == 100:\r\n health = 60\r\n health = health - ((high - 1) * 3)\r\n if med > 0:\r\n if health == 100:\r\n health = 80\r\n health = health - ((med - 1) * 2)\r\n if low > 0:\r\n if health == 100:\r\n health = 95\r\n health = health - low\r\n\r\n if health < 5:\r\n health = 5\r\n\r\n return health", "product_grade_a": 90, "product_grade_b": 80, "product_grade_c": 70, diff --git a/dojo/fixtures/dojo_testdata.json b/dojo/fixtures/dojo_testdata.json index d5b2d4f4538..26148621eaf 100644 --- a/dojo/fixtures/dojo_testdata.json +++ b/dojo/fixtures/dojo_testdata.json @@ -242,7 +242,6 @@ "mail_notifications_to": "", "enable_jira": false, "enable_product_grade": true, - "product_grade": "def grade_product(crit, high, med, low):\r\n health=100\r\n if crit > 0:\r\n health = 40\r\n health = health - ((crit - 1) * 5)\r\n if high > 0:\r\n if health == 100:\r\n health = 60\r\n health = health - ((high - 1) * 3)\r\n if med > 0:\r\n if health == 100:\r\n health = 80\r\n health = health - ((med - 1) * 2)\r\n if low > 0:\r\n if health == 100:\r\n health = 95\r\n health = health - low\r\n\r\n if health < 5:\r\n health = 5\r\n\r\n return health", "product_grade_a": 90, "product_grade_b": 80, "product_grade_c": 70, diff --git a/dojo/fixtures/system_settings.json b/dojo/fixtures/system_settings.json index 37033d658f0..eca1b4cc1be 100644 --- a/dojo/fixtures/system_settings.json +++ b/dojo/fixtures/system_settings.json @@ -6,7 +6,6 @@ "enable_deduplication": false, "enable_jira": false, "url_prefix": "", - "product_grade": "def grade_product(crit, high, med, low):\r\n health=100\r\n if crit > 0:\r\n health = 40\r\n health = health - ((crit - 1) * 5)\r\n if high > 0:\r\n if health == 100:\r\n health = 60\r\n health = health - ((high - 1) * 3)\r\n if med > 0:\r\n if health == 100:\r\n health = 80\r\n health = health - ((med - 1) * 2)\r\n if low > 0:\r\n if health == 100:\r\n health = 95\r\n health = health - low\r\n\r\n if health < 5:\r\n health = 5\r\n\r\n return health", "product_grade_a": 90, "product_grade_b": 80, "product_grade_c": 70, diff --git a/dojo/forms.py b/dojo/forms.py index a73abb00ce6..b2b39509933 100644 --- a/dojo/forms.py +++ b/dojo/forms.py @@ -3129,7 +3129,7 @@ def clean(self): class Meta: model = System_Settings - exclude = ["product_grade"] + fields = "__all__" class BenchmarkForm(forms.ModelForm): diff --git a/dojo/management/commands/system_settings.py b/dojo/management/commands/system_settings.py deleted file mode 100644 index eace6a7e2b5..00000000000 --- a/dojo/management/commands/system_settings.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.core.management.base import BaseCommand - -from dojo.models import System_Settings - - -class Command(BaseCommand): - help = "Updates product grade calculation" - - def handle(self, *args, **options): - code = """def grade_product(crit, high, med, low): - health=100 - if crit > 0: - health = 40 - health = health - ((crit - 1) * 5) - if high > 0: - if health == 100: - health = 60 - health = health - ((high - 1) * 3) - if med > 0: - if health == 100: - health = 80 - health = health - ((med - 1) * 2) - if low > 0: - if health == 100: - health = 95 - health = health - low - - if health < 5: - health = 5 - - return health - """ - system_settings = System_Settings.objects.get(id=1) - system_settings.product_grade = code - system_settings.save() diff --git a/dojo/models.py b/dojo/models.py index 57ce9c18e72..7ab85e710d9 100644 --- a/dojo/models.py +++ b/dojo/models.py @@ -441,7 +441,6 @@ class System_Settings(models.Model): url_prefix = models.CharField(max_length=300, default="", blank=True, help_text=_("URL prefix if DefectDojo is installed in it's own virtual subdirectory.")) team_name = models.CharField(max_length=100, default="", blank=True) enable_product_grade = models.BooleanField(default=False, verbose_name=_("Enable Product Grading"), help_text=_("Displays a grade letter next to a product to show the overall health.")) - product_grade = models.CharField(max_length=800, blank=True) product_grade_a = models.IntegerField(default=90, verbose_name=_("Grade A"), help_text=_("Percentage score for an " @@ -685,19 +684,6 @@ def clean(self): }) -class SystemSettingsFormAdmin(forms.ModelForm): - product_grade = forms.CharField(widget=forms.Textarea) - - class Meta: - model = System_Settings - fields = ["product_grade"] - - -class System_SettingsAdmin(admin.ModelAdmin): - form = SystemSettingsFormAdmin - fields = ("product_grade",) - - def get_current_date(): return timezone.now().date() @@ -4854,7 +4840,7 @@ def __str__(self): admin.site.register(Tool_Type) admin.site.register(Cred_User) admin.site.register(Cred_Mapping) -admin.site.register(System_Settings, System_SettingsAdmin) +admin.site.register(System_Settings) admin.site.register(SLA_Configuration) admin.site.register(CWE) admin.site.register(Regulation) diff --git a/dojo/utils.py b/dojo/utils.py index 33e99846b81..cba54ac0009 100644 --- a/dojo/utils.py +++ b/dojo/utils.py @@ -20,7 +20,6 @@ import crum import cvss import vobject -from asteval import Interpreter from auditlog.models import LogEntry from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes @@ -1224,6 +1223,26 @@ def get_setting(setting): return getattr(settings, setting) +def grade_product(crit, high, med, low): + health = 100 + if crit > 0: + health = 40 + health -= ((crit - 1) * 5) + if high > 0: + if health == 100: + health = 60 + health -= ((high - 1) * 3) + if med > 0: + if health == 100: + health = 80 + health -= ((med - 1) * 2) + if low > 0: + if health == 100: + health = 95 + health -= low + return max(health, 5) + + @dojo_model_to_id @dojo_async_task(signature=True) @app.task @@ -1276,17 +1295,14 @@ def calculate_grade_internal(product, *args, **kwargs): medium = severity_count["numerical_severity__count"] elif severity_count["severity"] == "Low": low = severity_count["numerical_severity__count"] - aeval = Interpreter() - aeval(system_settings.product_grade) - grade_product = f"grade_product({critical}, {high}, {medium}, {low})" - prod_numeric_grade = aeval(grade_product) - if prod_numeric_grade != product.prod_numeric_grade: - logger.debug("Updating product %s grade from %s to %s", product.id, product.prod_numeric_grade, prod_numeric_grade) - product.prod_numeric_grade = prod_numeric_grade + grade = grade_product(critical, high, medium, low) + if grade != product.prod_numeric_grade: + logger.debug("Updating product %s grade from %s to %s", product.id, product.prod_numeric_grade, grade) + product.prod_numeric_grade = grade super(Product, product).save() else: # Use %s to safely handle None grades without formatter errors - logger.debug("Product %s grade %s is up to date", product.id, prod_numeric_grade) + logger.debug("Product %s grade %s is up to date", product.id, product.prod_numeric_grade) def perform_product_grading(product): diff --git a/unittests/test_importers_performance.py b/unittests/test_importers_performance.py index 1e7b05d8fe5..26ab5d025ce 100644 --- a/unittests/test_importers_performance.py +++ b/unittests/test_importers_performance.py @@ -310,9 +310,9 @@ def test_import_reimport_reimport_performance_pghistory_no_async_with_product_gr self.system_settings(enable_product_grade=True) self._import_reimport_performance( - expected_num_queries1=315, + expected_num_queries1=320, expected_num_async_tasks1=8, - expected_num_queries2=241, + expected_num_queries2=246, expected_num_async_tasks2=19, expected_num_queries3=123, expected_num_async_tasks3=18,