Skip to content

Commit 5ee7049

Browse files
authored
Merge pull request #533 from aaronweaver/master
Grading for Products
2 parents 5706e30 + 44047a3 commit 5ee7049

File tree

20 files changed

+234
-40
lines changed

20 files changed

+234
-40
lines changed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ You can also log in as a product owner / non-staff user:
3535

3636
For additional documentation you can visit our [Read the Docs site](https://defectdojo.readthedocs.io/).
3737

38-
# One-Click Installations
39-
40-
Deploy to Docker Cloud. (__Login first to Docker Cloud before clicking the install button.__)
41-
42-
[![Deploy to Docker Cloud](https://files.cloud.docker.com/images/deploy-to-dockercloud.svg)](https://cloud.docker.com/stack/deploy/?repo=https://github.com/aaronweaver/docker-DefectDojo)
43-
4438
# Installation Options
4539

4640
### [Debian, Ubuntu (16.04.2+) or RHEL-based Install Script](https://defectdojo.readthedocs.io/en/latest/getting-started.html#install-script)

docs/upgrading.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,20 @@ Upgrading to 1.2.4 requires:
153153
1. ./manage.py makemigrations
154154
./manage.py migrate
155155
./manage.py loaddata dojo/fixtures/objects_review.json
156+
157+
158+
Upgrading to DefectDojo Version 1.2.8
159+
------------------------------------
160+
161+
New feature: Product Grading (Overall Product Health)
162+
Upgrading to 1.2.8 requires:
163+
164+
1. ./manage.py makemigrations
165+
./manage.py migrate
166+
./manage.py system_settings
167+
168+
2. ./manage.py collectstatic --noinput
169+
170+
3. pip install asteval
171+
172+
4. Complete

dojo/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Django starts so that shared_task will use this app.
55
from .celery import app as celery_app # noqa
66

7-
__version__ = '1.2.5'
7+
__version__ = '1.2.8'
88
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
99
__docs__ = 'http://defectdojo.readthedocs.io/'
1010
__demo__ = 'http://defectdojo.pythonanywhere.com/'

dojo/fixtures/system_settings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77
"enable_jira": false,
88
"s_finding_severity_naming": false,
99
"url_prefix": "",
10-
"time_zone": "UTC"
10+
"time_zone": "UTC",
11+
"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",
12+
"product_grade_a": 90,
13+
"product_grade_b": 80,
14+
"product_grade_c": 70,
15+
"product_grade_d": 60,
16+
"product_grade_f": 59
1117
}
1218
}
1319
]

dojo/forms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,7 @@ class Meta:
12491249
class UserContactInfoForm(forms.ModelForm):
12501250
class Meta:
12511251
model = UserContactInfo
1252-
exclude = ['user']
1252+
exclude = ['user', 'slack_user_id']
12531253

12541254

12551255
def get_years():
@@ -1466,7 +1466,7 @@ class Meta:
14661466
class SystemSettingsForm(forms.ModelForm):
14671467
class Meta:
14681468
model = System_Settings
1469-
exclude = ['']
1469+
exclude = ['product_grade']
14701470

14711471
class NotificationsForm(forms.ModelForm):
14721472

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from django.core.management.base import BaseCommand
2+
from dojo.models import System_Settings
3+
4+
class Command(BaseCommand):
5+
help = 'Updates product grade calculation'
6+
7+
def handle(self, *args, **options):
8+
code = """def grade_product(crit, high, med, low):
9+
health=100
10+
if crit > 0:
11+
health = 40
12+
health = health - ((crit - 1) * 5)
13+
if high > 0:
14+
if health == 100:
15+
health = 60
16+
health = health - ((high - 1) * 3)
17+
if med > 0:
18+
if health == 100:
19+
health = 80
20+
health = health - ((med - 1) * 2)
21+
if low > 0:
22+
if health == 100:
23+
health = 95
24+
health = health - low
25+
26+
if health < 5:
27+
health = 5
28+
29+
return health
30+
"""
31+
system_settings = System_Settings.objects.get(id=1)
32+
system_settings.product_grade = code
33+
system_settings.save()

dojo/models.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from django.core.urlresolvers import reverse
2020
from django.core.validators import RegexValidator
2121
from django.db import models
22-
from django.db.models import Q
22+
from django.db.models import Q, Count
2323
from django.utils.timezone import now
2424
from imagekit.models import ImageSpecField
2525
from imagekit.processors import ResizeToCover
@@ -28,7 +28,7 @@
2828
from tagging.registry import register as tag_register
2929
from multiselectfield import MultiSelectField
3030
import hashlib
31-
31+
from django import forms
3232

3333
class System_Settings(models.Model):
3434
enable_deduplication = models.BooleanField(
@@ -99,13 +99,29 @@ class System_Settings(models.Model):
9999
'be displayed.')
100100
false_positive_history = models.BooleanField(default=False)
101101

102-
url_prefix = models.CharField(max_length=300, default='', blank=True)
102+
url_prefix = models.CharField(max_length=300, default='', blank=True, help_text="URL prefix if DefectDojo is installed in it's own virtual subdirectory.")
103103
team_name = models.CharField(max_length=100, default='', blank=True)
104104
time_zone = models.CharField(max_length=50,
105105
choices=[(tz, tz) for tz in all_timezones],
106106
default='UTC', blank=False)
107-
display_endpoint_uri = models.BooleanField(default=False)
107+
display_endpoint_uri = models.BooleanField(default=False, verbose_name="Display Endpoint Full URI", help_text="Displays the full endpoint URI in the endpoint view.")
108+
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.")
109+
product_grade = models.CharField(max_length=800, blank=True)
110+
product_grade_a = models.IntegerField(default=90, verbose_name="Grade A", help_text="Percentage score for an 'A' >=")
111+
product_grade_b = models.IntegerField(default=80, verbose_name="Grade B", help_text="Percentage score for a 'B' >=")
112+
product_grade_c = models.IntegerField(default=70, verbose_name="Grade C", help_text="Percentage score for a 'C' >=")
113+
product_grade_d = models.IntegerField(default=60, verbose_name="Grade D", help_text="Percentage score for a 'D' >=")
114+
product_grade_f = models.IntegerField(default=59, verbose_name="Grade F", help_text="Percentage score for an 'F' <=")
115+
116+
class SystemSettingsFormAdmin(forms.ModelForm):
117+
product_grade = forms.CharField( widget=forms.Textarea )
118+
class Meta:
119+
model = System_Settings
120+
fields = ['product_grade']
108121

122+
class System_SettingsAdmin(admin.ModelAdmin):
123+
form = SystemSettingsFormAdmin
124+
fields = ('product_grade',)
109125

110126
def get_current_date():
111127
return timezone.now().date()
@@ -152,9 +168,10 @@ class UserContactInfo(models.Model):
152168
"Up to 15 digits allowed.")
153169
twitter_username = models.CharField(blank=True, null=True, max_length=150)
154170
github_username = models.CharField(blank=True, null=True, max_length=150)
155-
slack_username = models.CharField(blank=True, null=True, max_length=150)
171+
slack_username = models.CharField(blank=True, null=True, max_length=150, help_text="Email address associated with your slack account", verbose_name="Slack Email Address")
172+
slack_user_id = models.CharField(blank=True, null=True, max_length=25)
156173
hipchat_username = models.CharField(blank=True, null=True, max_length=150)
157-
block_execution = models.BooleanField(default=False)
174+
block_execution = models.BooleanField(default=False, help_text="Instead of async deduping a finding the findings will be deduped synchronously and will 'block' the user until completion.")
158175

159176

160177
class Contact(models.Model):
@@ -260,8 +277,8 @@ class Product(models.Model):
260277
They remain in model for backwards compatibility and will be removed
261278
in a future release. prod_manager, tech_contact, manager
262279
263-
The admin script migrate_product_contacts should be used to migrate data
264-
from these fields to their replacements.
280+
The admin script migrate_product_contacts should be used to migrate data
281+
from these fields to their replacements.
265282
./manage.py migrate_product_contacts
266283
'''
267284
prod_manager = models.CharField(default=0, max_length=200) # unused
@@ -281,6 +298,7 @@ class Product(models.Model):
281298
updated = models.DateTimeField(editable=False, null=True, blank=True)
282299
tid = models.IntegerField(default=0, editable=False)
283300
authorized_users = models.ManyToManyField(User, blank=True)
301+
prod_numeric_grade = models.IntegerField(null=True, blank=True)
284302

285303
def __unicode__(self):
286304
return self.name
@@ -838,6 +856,10 @@ def save(self, dedupe_option=True, *args, **kwargs):
838856
else:
839857
self.dyanmic_finding = True
840858
self.found_by.add(self.test.test_type)
859+
860+
from dojo.utils import calculate_grade
861+
calculate_grade(self.test.engagement.product)
862+
841863
super(Finding, self).save(*args, **kwargs)
842864
if (dedupe_option):
843865
system_settings = System_Settings.objects.get()
@@ -861,6 +883,11 @@ def save(self, dedupe_option=True, *args, **kwargs):
861883
else:
862884
async_false_history.delay(self, *args, **kwargs)
863885

886+
def delete(self, *args, **kwargs):
887+
super(Finding, self).delete(*args, **kwargs)
888+
from dojo.utils import calculate_grade
889+
calculate_grade(self.test.engagement.product)
890+
864891
def clean(self):
865892
no_check = ["test", "reporter"]
866893
bigfields = ["description", "mitigation", "references", "impact",
@@ -1203,6 +1230,7 @@ class Notifications(models.Model):
12031230
upcoming_engagement = MultiSelectField(choices=NOTIFICATION_CHOICES, default='alert', blank=True)
12041231
user_mentioned = MultiSelectField(choices=NOTIFICATION_CHOICES, default='alert', blank=True)
12051232
code_review = MultiSelectField(choices=NOTIFICATION_CHOICES, default='alert', blank=True)
1233+
review_requested = MultiSelectField(choices=NOTIFICATION_CHOICES, default='alert', blank=True)
12061234
other = MultiSelectField(choices=NOTIFICATION_CHOICES, default='alert', blank=True)
12071235
user = models.ForeignKey(User, default=None, null=True, editable=False)
12081236

@@ -1462,7 +1490,8 @@ def __unicode__(self):
14621490
admin.site.register(Tool_Type)
14631491
admin.site.register(Cred_User)
14641492
admin.site.register(Cred_Mapping)
1465-
admin.site.register(System_Settings)
1493+
admin.site.register(System_Settings, System_SettingsAdmin)
1494+
14661495

14671496
watson.register(Product)
14681497
watson.register(Test)

dojo/static/dojo/css/dojo.css

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,30 @@ hr.report-page-break:before {
11301130
text-decoration: none;
11311131
}
11321132

1133+
.btn-grade {
1134+
border-radius: 2px;
1135+
border-color: #ddd;
1136+
color: #ffffff;
1137+
padding: 1px 1px 1px 1px;
1138+
text-decoration: none;
1139+
}
1140+
1141+
.A {
1142+
background: #4ec83d;
1143+
}
1144+
.B {
1145+
background: #ffa100;
1146+
}
1147+
.C {
1148+
background: #FFBD33;
1149+
}
1150+
.D {
1151+
background: #cc3300;
1152+
}
1153+
.F {
1154+
background: #ef251e;
1155+
}
1156+
11331157
div.tags .label {
11341158
font-size: 90%;
11351159
display: inline-block;

dojo/templates/403.html

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
<h1>403</h1>
44
<hr/>
55
<h2>
6-
Hey! Listen!
6+
You don't have permission to do that. Contact your administrator for additional accesss.
77
</h2>
8-
<h2>
9-
You don't have permission to do that.
10-
</h2>
11-
<h3>
12-
We're Sorry.
13-
</h3>
14-
{% endblock %}
8+
{% endblock %}

dojo/templates/404.html

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,4 @@ <h1>
88
<h2>
99
...we can't find what you need.
1010
</h2>
11-
<h3>
12-
We're Sorry.
13-
</h3>
14-
{% endblock %}
11+
{% endblock %}

0 commit comments

Comments
 (0)