Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions dojo/db_migrations/0204_jira_project_epic_issue_type_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.1.13 on 2024-03-01 20:39

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dojo', '0203_alter_finding_options_finding_epss_percentile_and_more'),
]

operations = [
migrations.AddField(
model_name='jira_project',
name='epic_issue_type_name',
field=models.CharField(default='Epic', blank=True, help_text='The name of the of structure that represents an Epic', max_length=64),
),
]
15 changes: 10 additions & 5 deletions dojo/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2709,7 +2709,7 @@ class JIRAProjectForm(forms.ModelForm):
class Meta:
model = JIRA_Project
exclude = ['product', 'engagement']
fields = ['inherit_from_product', 'jira_instance', 'project_key', 'issue_template_dir', 'component', 'custom_fields', 'jira_labels', 'default_assignee', 'add_vulnerability_id_to_jira_label', 'push_all_issues', 'enable_engagement_epic_mapping', 'push_notes', 'product_jira_sla_notification', 'risk_acceptance_expiration_notification']
fields = ['inherit_from_product', 'jira_instance', 'project_key', 'issue_template_dir', 'epic_issue_type_name', 'component', 'custom_fields', 'jira_labels', 'default_assignee', 'add_vulnerability_id_to_jira_label', 'push_all_issues', 'enable_engagement_epic_mapping', 'push_notes', 'product_jira_sla_notification', 'risk_acceptance_expiration_notification']

def __init__(self, *args, **kwargs):
from dojo.jira_link import helper as jira_helper
Expand Down Expand Up @@ -2742,6 +2742,7 @@ def __init__(self, *args, **kwargs):
self.fields['jira_instance'].disabled = False
self.fields['project_key'].disabled = False
self.fields['issue_template_dir'].disabled = False
self.fields['epic_issue_type_name'].disabled = False
self.fields['component'].disabled = False
self.fields['custom_fields'].disabled = False
self.fields['default_assignee'].disabled = False
Expand All @@ -2765,6 +2766,7 @@ def __init__(self, *args, **kwargs):
self.initial['jira_instance'] = jira_project_product.jira_instance.id if jira_project_product.jira_instance else None
self.initial['project_key'] = jira_project_product.project_key
self.initial['issue_template_dir'] = jira_project_product.issue_template_dir
self.initial['epic_issue_type_name'] = jira_project_product.epic_issue_type_name
self.initial['component'] = jira_project_product.component
self.initial['custom_fields'] = jira_project_product.custom_fields
self.initial['default_assignee'] = jira_project_product.default_assignee
Expand All @@ -2779,6 +2781,7 @@ def __init__(self, *args, **kwargs):
self.fields['jira_instance'].disabled = True
self.fields['project_key'].disabled = True
self.fields['issue_template_dir'].disabled = True
self.fields['epic_issue_type_name'].disabled = True
self.fields['component'].disabled = True
self.fields['custom_fields'].disabled = True
self.fields['default_assignee'].disabled = True
Expand All @@ -2798,6 +2801,7 @@ def __init__(self, *args, **kwargs):
if self.instance.id:
self.fields['jira_instance'].required = True
self.fields['project_key'].required = True
self.fields['epic_issue_type_name'].required = True

def clean(self):
logger.debug('validating jira project form')
Expand All @@ -2807,17 +2811,18 @@ def clean(self):
if not self.cleaned_data.get('inherit_from_product', False):
jira_instance = self.cleaned_data.get('jira_instance')
project_key = self.cleaned_data.get('project_key')
epic_issue_type_name = self.cleaned_data.get('epic_issue_type_name')

if project_key and jira_instance:
if project_key and jira_instance and epic_issue_type_name:
return cleaned_data

if not project_key and not jira_instance:
if not project_key and not jira_instance and not epic_issue_type_name:
return cleaned_data

if self.target == 'engagement':
raise ValidationError('JIRA Project needs a JIRA Instance and JIRA Project Key, or choose to inherit settings from product')
raise ValidationError('JIRA Project needs a JIRA Instance, JIRA Project Key, and Epic issue type name, or choose to inherit settings from product')
else:
raise ValidationError('JIRA Project needs a JIRA Instance and JIRA Project Key, leave empty to have no JIRA integration setup')
raise ValidationError('JIRA Project needs a JIRA Instance, JIRA Project Key, and Epic issue type name, leave empty to have no JIRA integration setup')


class GITHUBFindingForm(forms.Form):
Expand Down
2 changes: 1 addition & 1 deletion dojo/jira_link/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ def add_epic(engagement, **kwargs):
'summary': epic_name,
'description': epic_name,
'issuetype': {
'name': 'Epic'
'name': getattr(jira_project, "epic_issue_type_name", "Epic"),
},
get_epic_name_field_name(jira_instance): epic_name,
}
Expand Down
1 change: 1 addition & 0 deletions dojo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3890,6 +3890,7 @@ class JIRA_Project(models.Model):
help_text=_("Automatically maintain parity with JIRA. Always create and update JIRA tickets for findings in this Product."))
enable_engagement_epic_mapping = models.BooleanField(default=False,
blank=True)
epic_issue_type_name = models.CharField(max_length=64, blank=True, default="Epic", help_text=_("The name of the of structure that represents an Epic"))
push_notes = models.BooleanField(default=False, blank=True)
product_jira_sla_notification = models.BooleanField(default=False, blank=True, verbose_name=_("Send SLA notifications as comment?"))
risk_acceptance_expiration_notification = models.BooleanField(default=False, blank=True, verbose_name=_("Send Risk Acceptance expiration notifications as comment?"))
Expand Down
10 changes: 8 additions & 2 deletions unittests/dojo_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def get_new_product_with_jira_project_data(self):
'jira-project-form-project_key': 'IFFFNEW',
'jira-project-form-jira_instance': 2,
'jira-project-form-enable_engagement_epic_mapping': 'on',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-push_notes': 'on',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-custom_fields': 'null',
Expand All @@ -170,7 +171,9 @@ def get_new_product_without_jira_project_data(self):
'name': 'new product',
'description': 'new description',
'prod_type': 1,
'sla_configuration': 1
'sla_configuration': 1,
# A value is set by default by the model, so we need to add it here as well
'jira-project-form-epic_issue_type_name': 'Epic',
# 'project_key': 'IFFF',
# 'jira_instance': 2,
# 'enable_engagement_epic_mapping': 'on',
Expand All @@ -186,6 +189,7 @@ def get_product_with_jira_project_data(self, product):
'jira-project-form-project_key': 'IFFF',
'jira-project-form-jira_instance': 2,
'jira-project-form-enable_engagement_epic_mapping': 'on',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-push_notes': 'on',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-custom_fields': 'null',
Expand All @@ -201,6 +205,7 @@ def get_product_with_jira_project_data2(self, product):
'jira-project-form-project_key': 'IFFF2',
'jira-project-form-jira_instance': 2,
'jira-project-form-enable_engagement_epic_mapping': 'on',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-push_notes': 'on',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-custom_fields': 'null',
Expand All @@ -214,7 +219,8 @@ def get_product_with_empty_jira_project_data(self, product):
'description': product.description,
'prod_type': product.prod_type.id,
'sla_configuration': 1,

# A value is set by default by the model, so we need to add it here as well
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-custom_fields': 'null',
# 'project_key': 'IFFF',
# 'jira_instance': 2,
Expand Down
8 changes: 8 additions & 0 deletions unittests/test_jira_config_engagement.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def get_new_engagement_with_jira_project_data(self):
# 'jira-project-form-inherit_from_product': 'on', # absence = False in html forms
'jira-project-form-jira_instance': 2,
'jira-project-form-project_key': 'IUNSEC',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-custom_fields': 'null',
}
Expand All @@ -40,6 +41,7 @@ def get_new_engagement_with_jira_project_data_and_epic_mapping(self):
# 'jira-project-form-inherit_from_product': 'on', # absence = False in html forms
'jira-project-form-jira_instance': 2,
'jira-project-form-project_key': 'IUNSEC',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-enable_engagement_epic_mapping': 'on',
'jira-epic-form-push_to_jira': 'on',
Expand All @@ -56,6 +58,8 @@ def get_new_engagement_without_jira_project_data(self):
'target_end': '2070-12-04',
'status': 'Not Started',
'jira-project-form-inherit_from_product': 'on',
# A value is set by default by the model, so we need to add it here as well
'jira-project-form-epic_issue_type_name': 'Epic',
# 'project_key': 'IFFF',
# 'jira_instance': 2,
# 'enable_engagement_epic_mapping': 'on',
Expand All @@ -75,6 +79,7 @@ def get_engagement_with_jira_project_data(self, engagement):
# 'jira-project-form-inherit_from_product': 'on', # absence = False in html forms
'jira-project-form-jira_instance': 2,
'jira-project-form-project_key': 'ISEC',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-custom_fields': 'null',
}
Expand All @@ -91,6 +96,7 @@ def get_engagement_with_jira_project_data2(self, engagement):
# 'jira-project-form-inherit_from_product': 'on', # absence = False in html forms
'jira-project-form-jira_instance': 2,
'jira-project-form-project_key': 'ISEC2',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-custom_fields': 'null',
}
Expand All @@ -105,6 +111,8 @@ def get_engagement_with_empty_jira_project_data(self, engagement):
'target_end': '2070-12-04',
'status': 'Not Started',
'jira-project-form-inherit_from_product': 'on',
# A value is set by default by the model, so we need to add it here as well
'jira-project-form-epic_issue_type_name': 'Epic',
# 'project_key': 'IFFF',
# 'jira_instance': 2,
# 'enable_engagement_epic_mapping': 'on',
Expand Down
1 change: 1 addition & 0 deletions unittests/test_jira_config_engagement_epic.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def get_new_engagement_with_jira_project_data_and_epic_mapping(self):
'status': 'Not Started',
'jira-project-form-jira_instance': 2,
'jira-project-form-project_key': 'NTEST',
'jira-project-form-epic_issue_type_name': 'Epic',
'jira-project-form-product_jira_sla_notification': 'on',
'jira-project-form-enable_engagement_epic_mapping': 'on',
'jira-epic-form-push_to_jira': 'on',
Expand Down