Skip to content

Commit 1facfed

Browse files
committed
v3 labels
1 parent 927e261 commit 1facfed

95 files changed

Lines changed: 6468 additions & 536 deletions

File tree

Some content is hidden

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

.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
@@ -85,6 +85,7 @@
8585
get_authorized_jira_issues,
8686
get_authorized_jira_projects,
8787
)
88+
from dojo.labels import get_labels
8889
from dojo.models import (
8990
Announcement,
9091
Answer,
@@ -179,6 +180,9 @@
179180
logger = logging.getLogger(__name__)
180181

181182

183+
labels = get_labels()
184+
185+
182186
def schema_with_prefetch() -> dict:
183187
return {
184188
"list": extend_schema(
@@ -2725,7 +2729,7 @@ def report_generate(request, obj, options):
27252729
if type(obj).__name__ == "Product_Type":
27262730
product_type = obj
27272731

2728-
report_name = "Product Type Report: " + str(product_type)
2732+
report_name = labels.ORG_REPORT_WITH_NAME_TITLE % {"name": str(product_type)}
27292733

27302734
findings = report_finding_filter_class(
27312735
request.GET,
@@ -2754,7 +2758,7 @@ def report_generate(request, obj, options):
27542758
elif type(obj).__name__ == "Product":
27552759
product = obj
27562760

2757-
report_name = "Product Report: " + str(product)
2761+
report_name = labels.ASSET_REPORT_WITH_NAME_TITLE % {"name": str(product)}
27582762

27592763
findings = report_finding_filter_class(
27602764
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:
@@ -1777,8 +1797,7 @@ class AddEndpointForm(forms.Form):
17771797
"Each must be valid.",
17781798
widget=forms.widgets.Textarea(attrs={"rows": "15", "cols": "400"}))
17791799
product = forms.CharField(required=True,
1780-
widget=forms.widgets.HiddenInput(), help_text="The product this endpoint should be "
1781-
"associated with.")
1800+
widget=forms.widgets.HiddenInput())
17821801
tags = TagField(required=False,
17831802
help_text="Add tags that help describe this endpoint. "
17841803
"Choose from the list or add new tags. Press Enter key to add.")
@@ -1788,7 +1807,10 @@ def __init__(self, *args, **kwargs):
17881807
if "product" in kwargs:
17891808
product = kwargs.pop("product")
17901809
super().__init__(*args, **kwargs)
1791-
self.fields["product"] = forms.ModelChoiceField(queryset=get_authorized_products(Permissions.Endpoint_Add))
1810+
self.fields["product"] = forms.ModelChoiceField(
1811+
queryset=get_authorized_products(Permissions.Endpoint_Add),
1812+
label=labels.ASSET_LABEL,
1813+
help_text=labels.ASSET_ENDPOINT_HELP)
17921814
if product is not None:
17931815
self.fields["product"].initial = product.id
17941816

@@ -2195,6 +2217,7 @@ class Add_Product_GroupForm(forms.ModelForm):
21952217
def __init__(self, *args, **kwargs):
21962218
super().__init__(*args, **kwargs)
21972219
self.fields["product"].disabled = True
2220+
self.fields["product"].label = labels.ASSET_LABEL
21982221
current_groups = Product_Group.objects.filter(product=self.initial["product"]).values_list("group", flat=True)
21992222
authorized_groups = get_authorized_groups(Permissions.Group_View)
22002223
authorized_groups = authorized_groups.exclude(id__in=current_groups)
@@ -2206,13 +2229,14 @@ class Meta:
22062229

22072230

22082231
class Add_Product_Group_GroupForm(forms.ModelForm):
2209-
products = forms.ModelMultipleChoiceField(queryset=Product.objects.none(), required=True, label="Products")
2232+
products = forms.ModelMultipleChoiceField(queryset=Product.objects.none(), required=True)
22102233

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

22182242
class Meta:
@@ -2225,6 +2249,7 @@ class Edit_Product_Group_Form(forms.ModelForm):
22252249
def __init__(self, *args, **kwargs):
22262250
super().__init__(*args, **kwargs)
22272251
self.fields["product"].disabled = True
2252+
self.fields["product"].label = labels.ASSET_LABEL
22282253
self.fields["group"].disabled = True
22292254

22302255
class Meta:
@@ -2248,20 +2273,22 @@ def __init__(self, *args, **kwargs):
22482273
authorized_groups = authorized_groups.exclude(id__in=current_groups)
22492274
self.fields["groups"].queryset = authorized_groups
22502275
self.fields["product_type"].disabled = True
2276+
self.fields["product_type"].label = labels.ORG_LABEL
22512277

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

22562282

22572283
class Add_Product_Type_Group_GroupForm(forms.ModelForm):
2258-
product_types = forms.ModelMultipleChoiceField(queryset=Product_Type.objects.none(), required=True, label="Product Types")
2284+
product_types = forms.ModelMultipleChoiceField(queryset=Product_Type.objects.none(), required=True)
22592285

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

22672294
class Meta:
@@ -2274,6 +2301,7 @@ class Edit_Product_Type_Group_Form(forms.ModelForm):
22742301
def __init__(self, *args, **kwargs):
22752302
super().__init__(*args, **kwargs)
22762303
self.fields["product_type"].disabled = True
2304+
self.fields["product_type"].label = labels.ORG_LABEL
22772305
self.fields["group"].disabled = True
22782306

22792307
class Meta:
@@ -2414,6 +2442,7 @@ class Meta:
24142442
def __init__(self, *args, **kwargs):
24152443
super().__init__(*args, **kwargs)
24162444
current_user = get_current_user()
2445+
self.fields["role"].help_text = labels.ASSET_GLOBAL_ROLE_HELP
24172446
if not current_user.is_superuser:
24182447
self.fields["role"].disabled = True
24192448

@@ -2439,6 +2468,7 @@ class ProductTypeCountsForm(ProductCountsFormBase):
24392468
def __init__(self, *args, **kwargs):
24402469
super().__init__(*args, **kwargs)
24412470
self.fields["product_type"].queryset = get_authorized_product_types(Permissions.Product_Type_View)
2471+
self.fields["product_type"].label = labels.ORG_LABEL
24422472

24432473

24442474
class ProductTagCountsForm(ProductCountsFormBase):
@@ -2452,6 +2482,7 @@ def __init__(self, *args, **kwargs):
24522482
prods = get_authorized_products(Permissions.Product_View)
24532483
tags_available_to_user = Product.tags.tag_model.objects.filter(product__in=prods)
24542484
self.fields["product_tag"].queryset = tags_available_to_user
2485+
self.fields["product_tag"].label = labels.ASSET_TAG_LABEL
24552486

24562487

24572488
class APIKeyForm(forms.ModelForm):
@@ -2932,6 +2963,20 @@ def __init__(self, *args, **kwargs):
29322963
super().__init__(*args, **kwargs)
29332964
self.fields["default_group_role"].queryset = get_group_member_roles()
29342965

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

0 commit comments

Comments
 (0)