Skip to content

Commit 77834f3

Browse files
committed
v3 labels
1 parent 797bd24 commit 77834f3

File tree

95 files changed

+6468
-536
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+6468
-536
lines changed

.github/workflows/integration-tests.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,15 @@ jobs:
4141
"tests/notifications_test.py",
4242
"tests/tool_config.py",
4343
"openapi-validatator",
44-
44+
# V3 migration
45+
"tests/asset_group_test.py",
46+
"tests/asset_member_test.py",
47+
"tests/asset_test.py",
48+
"tests/organization_group_test.py",
49+
"tests/organization_member_test.py",
50+
"tests/organization_test.py",
51+
# v2; can be removed after v3 migration complete
52+
"tests/report_builder_test_v2.py",
4553
]
4654
os: [alpine, debian]
4755
fail-fast: false

dojo/api_v2/views.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
get_authorized_jira_issues,
8585
get_authorized_jira_projects,
8686
)
87+
from dojo.labels import get_labels
8788
from dojo.models import (
8889
Announcement,
8990
Answer,
@@ -178,6 +179,9 @@
178179
logger = logging.getLogger(__name__)
179180

180181

182+
labels = get_labels()
183+
184+
181185
def schema_with_prefetch() -> dict:
182186
return {
183187
"list": extend_schema(
@@ -2746,7 +2750,7 @@ def report_generate(request, obj, options):
27462750
if type(obj).__name__ == "Product_Type":
27472751
product_type = obj
27482752

2749-
report_name = "Product Type Report: " + str(product_type)
2753+
report_name = labels.ORG_REPORT_WITH_NAME_TITLE % {"name": str(product_type)}
27502754

27512755
findings = report_finding_filter_class(
27522756
request.GET,
@@ -2775,7 +2779,7 @@ def report_generate(request, obj, options):
27752779
elif type(obj).__name__ == "Product":
27762780
product = obj
27772781

2778-
report_name = "Product Report: " + str(product)
2782+
report_name = labels.ASSET_REPORT_WITH_NAME_TITLE % {"name": str(product)}
27792783

27802784
findings = report_finding_filter_class(
27812785
request.GET,

dojo/context_processors.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.conf import settings
66

77
from dojo.models import Alerts, System_Settings, UserAnnouncement
8+
from dojo.labels import get_labels
89

910

1011
def globalize_vars(request):
@@ -74,3 +75,9 @@ def session_expiry_notification(request):
7475
return {
7576
"session_notify_time": notify_time,
7677
}
78+
79+
80+
def labels(request):
81+
return {
82+
"labels": get_labels(),
83+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.1.11 on 2025-08-22 12:49
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('dojo', '0242_file_upload_cleanup'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='system_settings',
15+
name='enable_v3_migration',
16+
field=models.BooleanField(default=True, help_text='Whether to use features and labels associated with V3.', verbose_name='Enable V3 Migration'),
17+
),
18+
]

dojo/filters.py

Lines changed: 282 additions & 117 deletions
Large diffs are not rendered by default.

dojo/forms.py

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from dojo.engagement.queries import get_authorized_engagements
3838
from dojo.finding.queries import get_authorized_findings
3939
from dojo.group.queries import get_authorized_groups, get_group_member_roles
40+
from dojo.labels import get_labels
4041
from dojo.models import (
4142
EFFORT_FOR_FIXING_CHOICES,
4243
SEVERITY_CHOICES,
@@ -118,6 +119,8 @@
118119

119120
logger = logging.getLogger(__name__)
120121

122+
labels = get_labels()
123+
121124
RE_DATE = re.compile(r"(\d{4})-(\d\d?)-(\d\d?)$")
122125

123126
FINDING_STATUS = (("verified", "Verified"),
@@ -244,6 +247,11 @@ class Product_TypeForm(forms.ModelForm):
244247
description = forms.CharField(widget=forms.Textarea(attrs={}),
245248
required=False)
246249

250+
def __init__(self, *args, **kwargs):
251+
super().__init__(*args, **kwargs)
252+
self.fields["critical_product"].label = labels.ORG_CRITICAL_PRODUCT_LABEL
253+
self.fields["key_product"].label = labels.ORG_KEY_PRODUCT_LABEL
254+
247255
class Meta:
248256
model = Product_Type
249257
fields = ["name", "description", "critical_product", "key_product"]
@@ -280,6 +288,7 @@ def __init__(self, *args, **kwargs):
280288
self.fields["users"].queryset = Dojo_User.objects.exclude(
281289
Q(is_superuser=True)
282290
| Q(id__in=current_members)).exclude(is_active=False).order_by("first_name", "last_name")
291+
self.fields["product_type"].label = labels.ORG_LABEL
283292
self.fields["product_type"].disabled = True
284293

285294
class Meta:
@@ -288,13 +297,14 @@ class Meta:
288297

289298

290299
class Add_Product_Type_Member_UserForm(forms.ModelForm):
291-
product_types = forms.ModelMultipleChoiceField(queryset=Product_Type.objects.none(), required=True, label="Product Types")
300+
product_types = forms.ModelMultipleChoiceField(queryset=Product_Type.objects.none(), required=True)
292301

293302
def __init__(self, *args, **kwargs):
294303
super().__init__(*args, **kwargs)
295304
current_members = Product_Type_Member.objects.filter(user=self.initial["user"]).values_list("product_type", flat=True)
296305
self.fields["product_types"].queryset = get_authorized_product_types(Permissions.Product_Type_Member_Add_Owner) \
297306
.exclude(id__in=current_members)
307+
self.fields["product_types"].label = labels.ORG_PLURAL_LABEL
298308
self.fields["user"].disabled = True
299309

300310
class Meta:
@@ -306,6 +316,7 @@ class Delete_Product_Type_MemberForm(Edit_Product_Type_MemberForm):
306316
def __init__(self, *args, **kwargs):
307317
super().__init__(*args, **kwargs)
308318
self.fields["role"].disabled = True
319+
self.fields["product_type"].label = labels.ORG_LABEL
309320

310321

311322
class Test_TypeForm(forms.ModelForm):
@@ -331,8 +342,7 @@ class ProductForm(forms.ModelForm):
331342
description = forms.CharField(widget=forms.Textarea(attrs={}),
332343
required=True)
333344

334-
prod_type = forms.ModelChoiceField(label="Product Type",
335-
queryset=Product_Type.objects.none(),
345+
prod_type = forms.ModelChoiceField(queryset=Product_Type.objects.none(),
336346
required=True)
337347

338348
sla_configuration = forms.ModelChoiceField(label="SLA Configuration",
@@ -347,6 +357,10 @@ class ProductForm(forms.ModelForm):
347357
def __init__(self, *args, **kwargs):
348358
super().__init__(*args, **kwargs)
349359
self.fields["prod_type"].queryset = get_authorized_product_types(Permissions.Product_Type_Add_Product)
360+
self.fields["prod_type"].label = labels.ORG_LABEL
361+
self.fields["product_manager"].label = labels.ASSET_MANAGER_LABEL
362+
self.fields["enable_product_tag_inheritance"].label = labels.ASSET_TAG_INHERITANCE_ENABLE_LABEL
363+
self.fields["enable_product_tag_inheritance"].help_text = labels.ASSET_TAG_INHERITANCE_ENABLE_HELP
350364
if prod_type_id := kwargs.get("instance", Product()).prod_type_id: # we are editing existing instance
351365
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)
352366

@@ -415,6 +429,7 @@ class Edit_Product_MemberForm(forms.ModelForm):
415429
def __init__(self, *args, **kwargs):
416430
super().__init__(*args, **kwargs)
417431
self.fields["product"].disabled = True
432+
self.fields["product"].label = labels.ASSET_LABEL
418433
self.fields["user"].queryset = Dojo_User.objects.order_by("first_name", "last_name")
419434
self.fields["user"].disabled = True
420435

@@ -429,6 +444,7 @@ class Add_Product_MemberForm(forms.ModelForm):
429444
def __init__(self, *args, **kwargs):
430445
super().__init__(*args, **kwargs)
431446
self.fields["product"].disabled = True
447+
self.fields["product"].label = labels.ASSET_LABEL
432448
current_members = Product_Member.objects.filter(product=self.initial["product"]).values_list("user", flat=True)
433449
self.fields["users"].queryset = Dojo_User.objects.exclude(
434450
Q(is_superuser=True)
@@ -440,13 +456,14 @@ class Meta:
440456

441457

442458
class Add_Product_Member_UserForm(forms.ModelForm):
443-
products = forms.ModelMultipleChoiceField(queryset=Product.objects.none(), required=True, label="Products")
459+
products = forms.ModelMultipleChoiceField(queryset=Product.objects.none(), required=True)
444460

445461
def __init__(self, *args, **kwargs):
446462
super().__init__(*args, **kwargs)
447463
current_members = Product_Member.objects.filter(user=self.initial["user"]).values_list("product", flat=True)
448464
self.fields["products"].queryset = get_authorized_products(Permissions.Product_Member_Add_Owner) \
449465
.exclude(id__in=current_members)
466+
self.fields["products"].label = labels.ASSET_PLURAL_LABEL
450467
self.fields["user"].disabled = True
451468

452469
class Meta:
@@ -608,6 +625,9 @@ def __init__(self, *args, **kwargs):
608625
choices.insert(0, ("", "---------"))
609626
self.fields["group_by"].choices = choices
610627

628+
self.fields["close_old_findings_product_scope"].label = labels.ASSET_FINDINGS_CLOSE_LABEL
629+
self.fields["close_old_findings_product_scope"].help_text = labels.ASSET_FINDINGS_CLOSE_HELP
630+
611631
self.endpoints_to_add_list = []
612632

613633
def clean(self):
@@ -1003,9 +1023,8 @@ class EngForm(forms.ModelForm):
10031023
))
10041024
description = forms.CharField(widget=forms.Textarea(attrs={}),
10051025
required=False, help_text="Description of the engagement and details regarding the engagement.")
1006-
product = forms.ModelChoiceField(label="Product",
1007-
queryset=Product.objects.none(),
1008-
required=True)
1026+
product = forms.ModelChoiceField(queryset=Product.objects.none(),
1027+
required=True)
10091028
target_start = forms.DateField(widget=forms.TextInput(
10101029
attrs={"class": "datepicker", "autocomplete": "off"}))
10111030
target_end = forms.DateField(widget=forms.TextInput(
@@ -1037,6 +1056,7 @@ def __init__(self, *args, **kwargs):
10371056
self.fields["lead"].queryset = get_authorized_users(Permissions.Engagement_View).filter(is_active=True)
10381057

10391058
self.fields["product"].queryset = get_authorized_products(Permissions.Engagement_Add)
1059+
self.fields["product"].label = labels.ASSET_LABEL
10401060

10411061
# Don't show CICD fields on a interactive engagement
10421062
if cicd is False:
@@ -1778,8 +1798,7 @@ class AddEndpointForm(forms.Form):
17781798
"Each must be valid.",
17791799
widget=forms.widgets.Textarea(attrs={"rows": "15", "cols": "400"}))
17801800
product = forms.CharField(required=True,
1781-
widget=forms.widgets.HiddenInput(), help_text="The product this endpoint should be "
1782-
"associated with.")
1801+
widget=forms.widgets.HiddenInput())
17831802
tags = TagField(required=False,
17841803
help_text="Add tags that help describe this endpoint. "
17851804
"Choose from the list or add new tags. Press Enter key to add.")
@@ -1789,7 +1808,10 @@ def __init__(self, *args, **kwargs):
17891808
if "product" in kwargs:
17901809
product = kwargs.pop("product")
17911810
super().__init__(*args, **kwargs)
1792-
self.fields["product"] = forms.ModelChoiceField(queryset=get_authorized_products(Permissions.Endpoint_Add))
1811+
self.fields["product"] = forms.ModelChoiceField(
1812+
queryset=get_authorized_products(Permissions.Endpoint_Add),
1813+
label=labels.ASSET_LABEL,
1814+
help_text=labels.ASSET_ENDPOINT_HELP)
17931815
if product is not None:
17941816
self.fields["product"].initial = product.id
17951817

@@ -2196,6 +2218,7 @@ class Add_Product_GroupForm(forms.ModelForm):
21962218
def __init__(self, *args, **kwargs):
21972219
super().__init__(*args, **kwargs)
21982220
self.fields["product"].disabled = True
2221+
self.fields["product"].label = labels.ASSET_LABEL
21992222
current_groups = Product_Group.objects.filter(product=self.initial["product"]).values_list("group", flat=True)
22002223
authorized_groups = get_authorized_groups(Permissions.Group_View)
22012224
authorized_groups = authorized_groups.exclude(id__in=current_groups)
@@ -2207,13 +2230,14 @@ class Meta:
22072230

22082231

22092232
class Add_Product_Group_GroupForm(forms.ModelForm):
2210-
products = forms.ModelMultipleChoiceField(queryset=Product.objects.none(), required=True, label="Products")
2233+
products = forms.ModelMultipleChoiceField(queryset=Product.objects.none(), required=True)
22112234

22122235
def __init__(self, *args, **kwargs):
22132236
super().__init__(*args, **kwargs)
22142237
current_members = Product_Group.objects.filter(group=self.initial["group"]).values_list("product", flat=True)
22152238
self.fields["products"].queryset = get_authorized_products(Permissions.Product_Member_Add_Owner) \
22162239
.exclude(id__in=current_members)
2240+
self.fields["products"].label = labels.ASSET_PLURAL_LABEL
22172241
self.fields["group"].disabled = True
22182242

22192243
class Meta:
@@ -2226,6 +2250,7 @@ class Edit_Product_Group_Form(forms.ModelForm):
22262250
def __init__(self, *args, **kwargs):
22272251
super().__init__(*args, **kwargs)
22282252
self.fields["product"].disabled = True
2253+
self.fields["product"].label = labels.ASSET_LABEL
22292254
self.fields["group"].disabled = True
22302255

22312256
class Meta:
@@ -2249,20 +2274,22 @@ def __init__(self, *args, **kwargs):
22492274
authorized_groups = authorized_groups.exclude(id__in=current_groups)
22502275
self.fields["groups"].queryset = authorized_groups
22512276
self.fields["product_type"].disabled = True
2277+
self.fields["product_type"].label = labels.ORG_LABEL
22522278

22532279
class Meta:
22542280
model = Product_Type_Group
22552281
fields = ["product_type", "groups", "role"]
22562282

22572283

22582284
class Add_Product_Type_Group_GroupForm(forms.ModelForm):
2259-
product_types = forms.ModelMultipleChoiceField(queryset=Product_Type.objects.none(), required=True, label="Product Types")
2285+
product_types = forms.ModelMultipleChoiceField(queryset=Product_Type.objects.none(), required=True)
22602286

22612287
def __init__(self, *args, **kwargs):
22622288
super().__init__(*args, **kwargs)
22632289
current_members = Product_Type_Group.objects.filter(group=self.initial["group"]).values_list("product_type", flat=True)
22642290
self.fields["product_types"].queryset = get_authorized_product_types(Permissions.Product_Type_Member_Add_Owner) \
22652291
.exclude(id__in=current_members)
2292+
self.fields["product_types"].label = labels.ORG_PLURAL_LABEL
22662293
self.fields["group"].disabled = True
22672294

22682295
class Meta:
@@ -2275,6 +2302,7 @@ class Edit_Product_Type_Group_Form(forms.ModelForm):
22752302
def __init__(self, *args, **kwargs):
22762303
super().__init__(*args, **kwargs)
22772304
self.fields["product_type"].disabled = True
2305+
self.fields["product_type"].label = labels.ORG_LABEL
22782306
self.fields["group"].disabled = True
22792307

22802308
class Meta:
@@ -2415,6 +2443,7 @@ class Meta:
24152443
def __init__(self, *args, **kwargs):
24162444
super().__init__(*args, **kwargs)
24172445
current_user = get_current_user()
2446+
self.fields["role"].help_text = labels.ASSET_GLOBAL_ROLE_HELP
24182447
if not current_user.is_superuser:
24192448
self.fields["role"].disabled = True
24202449

@@ -2440,6 +2469,7 @@ class ProductTypeCountsForm(ProductCountsFormBase):
24402469
def __init__(self, *args, **kwargs):
24412470
super().__init__(*args, **kwargs)
24422471
self.fields["product_type"].queryset = get_authorized_product_types(Permissions.Product_Type_View)
2472+
self.fields["product_type"].label = labels.ORG_LABEL
24432473

24442474

24452475
class ProductTagCountsForm(ProductCountsFormBase):
@@ -2453,6 +2483,7 @@ def __init__(self, *args, **kwargs):
24532483
prods = get_authorized_products(Permissions.Product_View)
24542484
tags_available_to_user = Product.tags.tag_model.objects.filter(product__in=prods)
24552485
self.fields["product_tag"].queryset = tags_available_to_user
2486+
self.fields["product_tag"].label = labels.ASSET_TAG_LABEL
24562487

24572488

24582489
class APIKeyForm(forms.ModelForm):
@@ -2933,6 +2964,20 @@ def __init__(self, *args, **kwargs):
29332964
super().__init__(*args, **kwargs)
29342965
self.fields["default_group_role"].queryset = get_group_member_roles()
29352966

2967+
self.fields["enable_product_tracking_files"].label = labels.SETTINGS_TRACKED_FILES_ENABLE_LABEL
2968+
self.fields["enable_product_tracking_files"].help_text = labels.SETTINGS_TRACKED_FILES_ENABLE_HELP
2969+
2970+
self.fields[
2971+
"enforce_verified_status_product_grading"].label = labels.SETTINGS_ASSET_GRADING_ENFORCE_VERIFIED_LABEL
2972+
self.fields[
2973+
"enforce_verified_status_product_grading"].help_text = labels.SETTINGS_ASSET_GRADING_ENFORCE_VERIFIED_HELP
2974+
2975+
self.fields["enable_product_grade"].label = labels.SETTINGS_ASSET_GRADING_ENABLE_LABEL
2976+
self.fields["enable_product_grade"].help_text = labels.SETTINGS_ASSET_GRADING_ENABLE_HELP
2977+
2978+
self.fields["enable_product_tag_inheritance"].label = labels.SETTINGS_ASSET_TAG_INHERITANCE_ENABLE_LABEL
2979+
self.fields["enable_product_tag_inheritance"].help_text = labels.SETTINGS_ASSET_TAG_INHERITANCE_ENABLE_HELP
2980+
29362981
def clean(self):
29372982
cleaned_data = super().clean()
29382983
enable_jira_value = cleaned_data.get("enable_jira")

0 commit comments

Comments
 (0)