Skip to content

Commit

Permalink
Merge pull request DefectDojo#2567 from valentijnscholten/1.6.5-into-…
Browse files Browse the repository at this point in the history
…master

merge release/1.6.5 into master
  • Loading branch information
valentijnscholten authored Jun 16, 2020
2 parents 5c561d7 + 51cadfd commit f11d6c0
Show file tree
Hide file tree
Showing 41 changed files with 630 additions and 448 deletions.
14 changes: 8 additions & 6 deletions docker/entrypoint-integration-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,14 @@ else
echo "Error: Ibm AppScan integration test failed"; exit 1
fi

echo "Running Smoke integration test"
if python3 tests/smoke_test.py ; then
echo "Success: Smoke integration tests passed"
else
echo "Error: Smoke integration test failed"; exit 1
fi
# all smoke tests are already covered by other testcases above/below
# test="Smoke integration test"
# echo "Running: $test"
# if python3 tests/smoke_test.py ; then
# success $test
# else
# fail $test
# fi

echo "Running Check Status test"
if python3 tests/check_status.py ; then
Expand Down
2 changes: 1 addition & 1 deletion dojo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Django starts so that shared_task will use this app.
from .celery import app as celery_app # noqa

__version__ = '1.6.2'
__version__ = '1.6.5'
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
__docs__ = 'http://defectdojo.readthedocs.io/'
__demo__ = 'http://defectdojo.pythonanywhere.com/'
24 changes: 16 additions & 8 deletions dojo/finding/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1031,17 +1031,18 @@ def edit_finding(request, fid):
form.initial['tags'] = [tag.name for tag in finding.tags]
form_error = False
jform = None
enabled = False
jira_link_exists = False
push_all_issues_enabled = False

if get_system_setting('enable_jira') and finding.jira_conf_new() is not None:
enabled = finding.test.engagement.product.jira_pkey_set.first().push_all_issues
jform = JIRAFindingForm(enabled=enabled, prefix='jiraform')
push_all_issues_enabled = finding.test.engagement.product.jira_pkey_set.first().push_all_issues
jform = JIRAFindingForm(enabled=push_all_issues_enabled, prefix='jiraform')

try:
jissue = JIRA_Issue.objects.get(finding=finding)
enabled = True
jira_link_exists = True
except:
enabled = False
jira_link_exists = False

try:
gissue = GITHUB_Issue.objects.get(finding=finding)
Expand Down Expand Up @@ -1117,12 +1118,19 @@ def edit_finding(request, fid):

# Push to Jira?
push_to_jira = False
if enabled:
if push_all_issues_enabled:
push_to_jira = True
# elif 'jiraform-push_to_jira' in request.POST:
elif 'jiraform-push_to_jira' in request.POST:
jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled)
jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=True)
if jform.is_valid():
push_to_jira = jform.cleaned_data.get('push_to_jira')
# If we get here, this means the box got checked.
# Currently, the jform is only 1 field, that checkbox.
# Even though its value is 'on' and therefore should be True, it always returns False.
# So putting a band-aid here to fix the issue.
# Someone more knowledgeable can fix it later.
# push_to_jira = jform.cleaned_data.get('push_to_jira')
push_to_jira = True

if 'githubform-push_to_github' in request.POST:
gform = GITHUBFindingForm(
Expand Down
1 change: 0 additions & 1 deletion dojo/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ def add_external_issue_github(find, prod, eng):
eng = Engagement.objects.get(test=find.test)
prod = Product.objects.get(engagement=eng)
github_product_key = GITHUB_PKey.objects.get(product=prod)
github_conf = github_product_key.git_conf_id
logger.info('Create issue with github profile: ' + str(github_conf) + ' on product: ' + str(github_product_key))

try:
Expand Down
2 changes: 1 addition & 1 deletion dojo/github_issue_link/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from . import views

urlpatterns = [
url(r'^webhook', views.webhook, name='web_hook'),
url(r'^github-webhook', views.webhook, name='github_web_hook'),
url(r'^github/add', views.new_github, name='add_github'),
url(r'^github/(?P<tid>\d+)/delete$', views.delete_github,
name='delete_github'),
Expand Down
7 changes: 5 additions & 2 deletions dojo/jira_link/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def webhook(request):

if request.method == 'POST':
parsed = json.loads(request.body.decode('utf-8'))
if 'issue' in list(parsed.keys()):
if parsed.get('webhookEvent') == 'jira:issue_updated':
jid = parsed['issue']['id']
jissue = get_object_or_404(JIRA_Issue, jira_id=jid)
if jissue.finding is not None:
Expand Down Expand Up @@ -89,7 +89,7 @@ def webhook(request):
eng.status = 'Completed'
eng.save()
"""
else:
if parsed.get('webhookEvent') == 'comment_created':
comment_text = parsed['comment']['body']
commentor = parsed['comment']['updateAuthor']['displayName']
jid = parsed['comment']['self'].split('/')[7]
Expand All @@ -102,6 +102,9 @@ def webhook(request):
finding.notes.add(new_note)
finding.jira_change = timezone.now()
finding.save()

if parsed.get('webhookEvent') not in ['comment_created', 'jira:issue_updated']:
logger.info('Unrecognized JIRA webhook event received: {}'.format(parsed.get('webhookEvent')))
return HttpResponse('')


Expand Down
22 changes: 10 additions & 12 deletions dojo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1570,7 +1570,11 @@ def remove_from_any_risk_acceptance(self):

def duplicate_finding_set(self):
if self.duplicate:
return Finding.objects.get(id=self.duplicate_finding.id).original_finding.all().order_by('title')
if self.duplicate_finding is not None:
return Finding.objects.get(
id=self.duplicate_finding.id).original_finding.all().order_by('title')
else:
return []
else:
return self.original_finding.all().order_by('title')

Expand Down Expand Up @@ -1729,7 +1733,6 @@ def jira_conf_new(self):
return self.test.engagement.product.jira_pkey_set.all()[0].conf
except:
return None
pass

def long_desc(self):
long_desc = ''
Expand All @@ -1747,10 +1750,10 @@ def long_desc(self):

for e in self.endpoints.all():
long_desc += str(e) + '\n\n'
long_desc += '*Description*: \n' + self.description + '\n\n'
long_desc += '*Mitigation*: \n' + self.mitigation + '\n\n'
long_desc += '*Impact*: \n' + self.impact + '\n\n'
long_desc += '*References*:' + self.references
long_desc += '*Description*: \n' + str(self.description) + '\n\n'
long_desc += '*Mitigation*: \n' + str(self.mitigation) + '\n\n'
long_desc += '*Impact*: \n' + str(self.impact) + '\n\n'
long_desc += '*References*:' + str(self.references)
return long_desc

def save(self, dedupe_option=True, false_history=False, rules_option=True,
Expand All @@ -1763,12 +1766,6 @@ def save(self, dedupe_option=True, false_history=False, rules_option=True,
self.jira_change = timezone.now()
if not jira_issue_exists:
self.jira_creation = timezone.now()
# If the product has "Push_all_issues" enabled,
# then we're pushing this to JIRA no matter what
if not push_to_jira:
# only if there is a JIRA configuration
push_to_jira = self.jira_conf_new() and \
self.jira_conf_new().jira_pkey_set.first().push_all_issues

if self.pk is None:
# We enter here during the first call from serializers.py
Expand Down Expand Up @@ -2890,6 +2887,7 @@ def enable_disable_auditlog(enable=True):
admin.site.register(System_Settings, System_SettingsAdmin)
admin.site.register(CWE)
admin.site.register(Regulation)
admin.site.register(Notifications)

# Watson
watson.register(Product)
Expand Down
124 changes: 71 additions & 53 deletions dojo/notifications/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,28 @@


def create_notification(event=None, *args, **kwargs):
# System notifications
try:
system_notifications = Notifications.objects.get(user=None)
except Exception:
system_notifications = Notifications()

logger.debug('creating system notifications')
process_notifications(event, system_notifications, *args, **kwargs)

if 'recipients' in kwargs:
# mimic existing code so that when recipients is specified, no other personal notifications are sent.
# mimic existing code so that when recipients is specified, no other system or personal notifications are sent.
logger.debug('creating notifications for recipients')
for recipient_notifications in Notifications.objects.filter(user__username__in=kwargs['recipients'], user__is_active=True):
for recipient_notifications in Notifications.objects.filter(user__username__in=kwargs['recipients'], user__is_active=True, product=None):
# kwargs.update({'user': recipient_notifications.user})
process_notifications(event, recipient_notifications, *args, **kwargs)
else:
logger.debug('creating system notifications')
# send system notifications to all admin users

# System notifications
try:
system_notifications = Notifications.objects.get(user=None)
except Exception:
system_notifications = Notifications()

admin_users = Dojo_User.objects.filter(is_staff=True)
for admin_user in admin_users:
system_notifications.user = admin_user
process_notifications(event, system_notifications, *args, **kwargs)

# Personal but global notifications
# only retrieve users which have at least one notification type enabled for this event type.
logger.debug('creating personal notifications')
Expand Down Expand Up @@ -71,8 +77,8 @@ def create_notification_message(event, user, notification_type, *args, **kwargs)
try:
notification = render_to_string(template, kwargs)
except Exception as e:
logger.exception(e)
create_description(event)
logger.debug('template not found or not implemented yet: %s', template)
create_description(event, *args, **kwargs)
notification = render_to_string('notifications/other.tpl', kwargs)

return notification
Expand All @@ -87,9 +93,9 @@ def process_notifications(event, notifications=None, *args, **kwargs):

sync = 'initiator' in kwargs and hasattr(kwargs['initiator'], 'usercontactinfo') and kwargs['initiator'].usercontactinfo.block_execution

logger.debug('sync: %s', sync)
logger.debug('sync: %s %s', sync, notifications.user)
logger.debug('sending notifications ' + ('synchronously' if sync else 'asynchronously'))
logger.debug(vars(notifications))
# logger.debug(vars(notifications))

slack_enabled = get_system_setting('enable_slack_notifications')
hipchat_enabled = get_system_setting('enable_hipchat_notifications')
Expand All @@ -115,7 +121,6 @@ def process_notifications(event, notifications=None, *args, **kwargs):
else:
send_mail_notification(event, notifications.user, *args, **kwargs)

print(getattr(notifications, event, None))
if 'alert' in getattr(notifications, event, None):
if not sync:
send_alert_notification_task.delay(event, notifications.user, *args, **kwargs)
Expand All @@ -125,25 +130,25 @@ def process_notifications(event, notifications=None, *args, **kwargs):

def send_slack_notification(event, user=None, *args, **kwargs):
from dojo.utils import get_system_setting, get_slack_user_id
if user is not None:
if hasattr(user, 'usercontactinfo') and user.usercontactinfo.slack_username is not None:
slack_user_id = user.usercontactinfo.slack_user_id
if user.usercontactinfo.slack_user_id is None:
# Lookup the slack userid
slack_user_id = get_slack_user_id(
user.usercontactinfo.slack_username)
slack_user_save = UserContactInfo.objects.get(user_id=user.id)
slack_user_save.slack_user_id = slack_user_id
slack_user_save.save()

channel = '@%s' % slack_user_id
try:
if user is not None:
if hasattr(user, 'usercontactinfo') and user.usercontactinfo.slack_username is not None:
slack_user_id = user.usercontactinfo.slack_user_id
if user.usercontactinfo.slack_user_id is None:
# Lookup the slack userid
slack_user_id = get_slack_user_id(
user.usercontactinfo.slack_username)
slack_user_save = UserContactInfo.objects.get(user_id=user.id)
slack_user_save.slack_user_id = slack_user_id
slack_user_save.save()

channel = '@%s' % slack_user_id
else:
# user has no slack username, skip
return
else:
# user has no slack username, skip
return
else:
channel = get_system_setting('slack_channel')
channel = get_system_setting('slack_channel')

try:
res = requests.request(
method='POST',
url='https://slack.com/api/chat.postMessage',
Expand All @@ -161,11 +166,11 @@ def send_slack_notification(event, user=None, *args, **kwargs):

def send_hipchat_notification(event, user=None, *args, **kwargs):
from dojo.utils import get_system_setting
if user:
# HipChat doesn't seem to offer direct message functionality, so no HipChat PM functionality here...
return

try:
if user:
# HipChat doesn't seem to offer direct message functionality, so no HipChat PM functionality here...
return

# We use same template for HipChat as for slack
res = requests.request(
method='POST',
Expand All @@ -185,16 +190,17 @@ def send_hipchat_notification(event, user=None, *args, **kwargs):

def send_mail_notification(event, user=None, *args, **kwargs):
from dojo.utils import get_system_setting
try:

if user:
address = user.email
else:
address = get_system_setting('mail_notifications_to')
if user:
address = user.email
else:
address = get_system_setting('mail_notifications_to')

subject = '%s notification' % get_system_setting('team_name')
if 'title' in kwargs:
subject += ': %s' % kwargs['title']

subject = '%s notification' % get_system_setting('team_name')
if 'title' in kwargs:
subject += ': %s' % kwargs['title']
try:
email = EmailMessage(
subject,
create_notification_message(event, user, 'mail', *args, **kwargs),
Expand All @@ -214,18 +220,28 @@ def send_mail_notification(event, user=None, *args, **kwargs):


def send_alert_notification(event, user=None, *args, **kwargs):
icon = kwargs.get('icon', 'info-circle')
alert = Alerts(
user_id=user,
title=kwargs.get('title'),
description=create_notification_message(event, user, 'alert', *args, **kwargs),
url=kwargs.get('url', reverse('alerts')),
icon=icon,
source=Notifications._meta.get_field(event).verbose_name.title())
alert.save()
print('sending alert notification')
try:
icon = kwargs.get('icon', 'info-circle')
alert = Alerts(
user_id=user,
title=kwargs.get('title')[:100],
description=create_notification_message(event, user, 'alert', *args, **kwargs),
url=kwargs.get('url', reverse('alerts')),
icon=icon[:25],
source=Notifications._meta.get_field(event).verbose_name.title()[:100]
)
# relative urls will fail validation
alert.clean_fields(exclude=['url'])
alert.save()
except Exception as e:
logger.exception(e)
log_alert(e, *args, **kwargs)
pass


def log_alert(e, *args, **kwargs):
# no try catch here, if this fails we need to show an error
users = Dojo_User.objects.filter(is_superuser=True)
for user in users:
alert = Alerts(
Expand All @@ -235,4 +251,6 @@ def log_alert(e, *args, **kwargs):
description="%s" % e,
icon="exclamation-triangle",
source="Notifications")
# relative urls will fail validation
alert.clean_fields(exclude=['url'])
alert.save()
Loading

0 comments on commit f11d6c0

Please sign in to comment.