diff --git a/docker/entrypoint-integration-tests.sh b/docker/entrypoint-integration-tests.sh index 57951b160b2..1e5df6c5246 100755 --- a/docker/entrypoint-integration-tests.sh +++ b/docker/entrypoint-integration-tests.sh @@ -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 diff --git a/dojo/__init__.py b/dojo/__init__.py index 9d20a5d1383..8ffafc0c487 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -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/' diff --git a/dojo/finding/views.py b/dojo/finding/views.py index 3d407f44086..03fe57962a2 100644 --- a/dojo/finding/views.py +++ b/dojo/finding/views.py @@ -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) @@ -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( diff --git a/dojo/github.py b/dojo/github.py index be40ff024ad..ec005c2f1f5 100644 --- a/dojo/github.py +++ b/dojo/github.py @@ -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: diff --git a/dojo/github_issue_link/urls.py b/dojo/github_issue_link/urls.py index 8df21e210eb..794dda947fa 100644 --- a/dojo/github_issue_link/urls.py +++ b/dojo/github_issue_link/urls.py @@ -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\d+)/delete$', views.delete_github, name='delete_github'), diff --git a/dojo/jira_link/views.py b/dojo/jira_link/views.py index b6391490bd6..3ffbaa366a5 100644 --- a/dojo/jira_link/views.py +++ b/dojo/jira_link/views.py @@ -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: @@ -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] @@ -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('') diff --git a/dojo/models.py b/dojo/models.py index c96b7dd2170..835fff942f1 100755 --- a/dojo/models.py +++ b/dojo/models.py @@ -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') @@ -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 = '' @@ -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, @@ -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 @@ -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) diff --git a/dojo/notifications/helper.py b/dojo/notifications/helper.py index 0d1226314b4..cd25cf90040 100644 --- a/dojo/notifications/helper.py +++ b/dojo/notifications/helper.py @@ -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') @@ -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 @@ -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') @@ -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) @@ -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', @@ -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', @@ -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), @@ -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( @@ -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() diff --git a/dojo/search/views.py b/dojo/search/views.py index 3fe5f2ecb84..4454b1ddc0d 100644 --- a/dojo/search/views.py +++ b/dojo/search/views.py @@ -95,10 +95,7 @@ def simple_search(request): request.user]),)) if "template" in search_operator or search_operator == "": - finding_templates = watson.search(clean_query, models=( - Finding_Template.objects.filter( - authorized_users__in=[ - request.user]),)) + finding_templates = watson.search(clean_query, models=(Finding_Template,)) if "test" in search_operator or search_operator == "": tests = watson.search( @@ -117,10 +114,8 @@ def simple_search(request): Finding.objects.filter( test__engagement__product__authorized_users__in=[ request.user]), tags) - tagged_finding_templates = TaggedItem.objects.get_by_model( - Finding_Template.objects.filter( - authorized_users__in=[ - request.user]), tags) + tagged_finding_templates = TaggedItem.objects.get_by_model(Finding_Template, + tags) tagged_tests = TaggedItem.objects.get_by_model( Test.objects.filter( engagement__product__authorized_users__in=[ diff --git a/dojo/tasks.py b/dojo/tasks.py index f603c53ccfd..cba834bb776 100644 --- a/dojo/tasks.py +++ b/dojo/tasks.py @@ -18,7 +18,10 @@ from dojo.utils import sync_false_history, calculate_grade from dojo.reports.widgets import report_widget_factory from dojo.utils import add_comment, add_epic, add_issue, update_epic, update_issue, \ - close_epic, create_notification, sync_rules, fix_loop_duplicates, rename_whitesource_finding, update_external_issue, add_external_issue, close_external_issue, reopen_external_issue + close_epic, sync_rules, fix_loop_duplicates, \ + rename_whitesource_finding, update_external_issue, add_external_issue, \ + close_external_issue, reopen_external_issue +from dojo.notifications.helper import create_notification import logging diff --git a/dojo/templates/dojo/engagement.html b/dojo/templates/dojo/engagement.html index eedc3b77aa9..905a8ff0aaa 100644 --- a/dojo/templates/dojo/engagement.html +++ b/dojo/templates/dojo/engagement.html @@ -89,7 +89,7 @@

{% include "dojo/paging_snippet.html" with page=products page_size=True %} {% else %} -

No active engagements
+
No active engagements
{% endif %} diff --git a/dojo/templates/dojo/engagements_all.html b/dojo/templates/dojo/engagements_all.html index e9cf5f61c80..c688a5494d8 100644 --- a/dojo/templates/dojo/engagements_all.html +++ b/dojo/templates/dojo/engagements_all.html @@ -100,7 +100,7 @@

{% include "dojo/paging_snippet.html" with page=products page_size=True %} {% else %} -

No engagements found
+
No engagements found
{% endif %} diff --git a/dojo/templates/dojo/findings_list.html b/dojo/templates/dojo/findings_list.html index 47da010bf0f..601721d9ea6 100644 --- a/dojo/templates/dojo/findings_list.html +++ b/dojo/templates/dojo/findings_list.html @@ -374,7 +374,7 @@

{% include "dojo/paging_snippet.html" with page=findings page_size=True%} {% else %} -

No findings found.

+

No findings found.

{% endif %} diff --git a/dojo/templates/dojo/product.html b/dojo/templates/dojo/product.html index fbc348ec682..d657d98f4f5 100644 --- a/dojo/templates/dojo/product.html +++ b/dojo/templates/dojo/product.html @@ -198,14 +198,16 @@

{% if system_settings.enable_jira %} {% for jira_conf in prod.jira_confs %} - - + {% if jira_conf.conf is not None %} + + + {% endif %} {% endfor %} {% endif %} @@ -213,11 +215,13 @@

{% if system_settings.enable_github %} {% for github_conf in prod.github_confs %} - - + {% if github_conf.git_conf is not None %} + + + {% endif %} {% endfor %} {% endif %} @@ -265,7 +269,7 @@

{% include "dojo/paging_snippet.html" with page=prod_list page_size=True %} {% else %} -

No products found.

+

No products found.

{% endif %} diff --git a/dojo/tools/npm_audit/parser.py b/dojo/tools/npm_audit/parser.py index c0b95339f4c..a09b7bb60ac 100644 --- a/dojo/tools/npm_audit/parser.py +++ b/dojo/tools/npm_audit/parser.py @@ -23,9 +23,16 @@ def parse_json(self, json_output): tree = json.loads(str(data, 'utf-8')) except: tree = json.loads(data) - subtree = tree.get('advisories') except: - raise Exception("Invalid format") + raise Exception("Invalid format, unable to parse json.") + + if tree.get('error'): + error = tree.get('error') + code = error['code'] + summary = error['summary'] + raise ValueError('npm audit report contains errors: %s, %s', code, summary) + + subtree = tree.get('advisories') return subtree @@ -54,12 +61,15 @@ def get_item(item_node, test): severity = 'Info' paths = '' - for finding in item_node['findings']: - paths += "\n - " + str(finding['version']) + ":" + str(','.join(finding['paths'][:25])) - if len(finding['paths']) > 25: + component_version = None + for npm_finding in item_node['findings']: + # use first version as component_version + component_version = npm_finding['version'] if not component_version else component_version + paths += "\n - " + str(npm_finding['version']) + ":" + str(','.join(npm_finding['paths'][:25])) + if len(npm_finding['paths']) > 25: paths += "\n - ..... (list of paths truncated after 25 paths)" - finding = Finding(title=item_node['title'] + " - " + "(" + item_node['module_name'] + ", " + item_node['vulnerable_versions'] + ")", + dojo_finding = Finding(title=item_node['title'] + " - " + "(" + item_node['module_name'] + ", " + item_node['vulnerable_versions'] + ")", test=test, severity=severity, file_path=item_node['findings'][0]['paths'][0], @@ -75,6 +85,8 @@ def get_item(item_node, test): cve=item_node['cves'][0] if (len(item_node['cves']) > 0) else None, mitigation=item_node['recommendation'], references=item_node['url'], + component_name=item_node['module_name'], + component_version=component_version, active=False, verified=False, false_p=False, @@ -85,4 +97,4 @@ def get_item(item_node, test): static_finding=True, dynamic_finding=False) - return finding + return dojo_finding diff --git a/dojo/tools/qualys/parser.py b/dojo/tools/qualys/parser.py index 36a053299ba..cd1eb4f545f 100644 --- a/dojo/tools/qualys/parser.py +++ b/dojo/tools/qualys/parser.py @@ -229,7 +229,7 @@ def issue_r(raw_row, vuln): def qualys_parser(qualys_xml_file): - parser = etree.XMLParser(remove_blank_text=True, no_network=True, recover=True) + parser = etree.XMLParser(resolve_entities=False, remove_blank_text=True, no_network=True, recover=True) d = etree.parse(qualys_xml_file, parser) r = d.xpath('//ASSET_DATA_REPORT/HOST_LIST/HOST') master_list = [] diff --git a/dojo/tools/qualys_webapp/parser.py b/dojo/tools/qualys_webapp/parser.py index 7bb95d71acb..d94df3d92f5 100644 --- a/dojo/tools/qualys_webapp/parser.py +++ b/dojo/tools/qualys_webapp/parser.py @@ -140,7 +140,7 @@ def issue_r(raw_row, vuln, test, issueType): def qualys_webapp_parser(qualys_xml_file, test): - parser = etree.XMLParser(remove_blank_text=True, no_network=True, recover=True) + parser = etree.XMLParser(resolve_entities=False, remove_blank_text=True, no_network=True, recover=True) d = etree.parse(qualys_xml_file, parser) right = d.xpath('/WAS_WEBAPP_REPORT/RESULTS/WEB_APPLICATION/VULNERABILITY_LIST/VULNERABILITY') diff --git a/dojo/unittests/scans/npm_audit_sample/empty_with_error.json b/dojo/unittests/scans/npm_audit_sample/empty_with_error.json new file mode 100644 index 00000000000..5a697518e13 --- /dev/null +++ b/dojo/unittests/scans/npm_audit_sample/empty_with_error.json @@ -0,0 +1,7 @@ +{ + "error": { + "code": "ENOAUDIT", + "summary": "Your configured registry (https://registry.npmjs.org/) may not support audit requests, or the audit endpoint may be temporarily unavailable.", + "detail": "" + } +} \ No newline at end of file diff --git a/dojo/unittests/test_npm_audit_scan_parser.py b/dojo/unittests/test_npm_audit_scan_parser.py index c6908c2d45a..f50a3ff8ed2 100644 --- a/dojo/unittests/test_npm_audit_scan_parser.py +++ b/dojo/unittests/test_npm_audit_scan_parser.py @@ -20,9 +20,22 @@ def test_npm_audit_parser_with_one_criticle_vuln_has_one_findings(self): parser = NpmAuditParser(testfile, Test()) testfile.close() self.assertEqual(1, len(parser.items)) + self.assertEqual('growl', parser.items[0].component_name) + self.assertEqual('1.9.2', parser.items[0].component_version) def test_npm_audit_parser_with_many_vuln_has_many_findings(self): testfile = open("dojo/unittests/scans/npm_audit_sample/many_vuln.json") parser = NpmAuditParser(testfile, Test()) testfile.close() self.assertEqual(5, len(parser.items)) + # ordering seems to be different in travis compared to local, so disable for now + # self.assertEqual('mime', parser.items[4].component_name) + # self.assertEqual('1.3.4', parser.items[4].component_version) + + def test_npm_audit_parser_empty_with_error(self): + with self.assertRaises(ValueError) as context: + testfile = open("dojo/unittests/scans/npm_audit_sample/empty_with_error.json") + parser = NpmAuditParser(testfile, Test()) + testfile.close() + self.assertTrue('npm audit report contains errors:' in str(context.exception)) + self.assertTrue('ENOAUDIT' in str(context.exception)) diff --git a/dojo/utils.py b/dojo/utils.py index 5bd785a1245..4bdf48c5c3d 100644 --- a/dojo/utils.py +++ b/dojo/utils.py @@ -73,7 +73,7 @@ def sync_false_history(new_finding, *args, **kwargs): if total_findings.count() > 0: new_finding.false_p = True new_finding.active = False - new_finding.verified = False + new_finding.verified = True super(Finding, new_finding).save(*args, **kwargs) @@ -1325,86 +1325,86 @@ def reopen_external_issue(find, note, external_issue_provider): def add_issue(find, push_to_jira): eng = Engagement.objects.get(test=find.test) prod = Product.objects.get(engagement=eng) + jira_minimum_threshold = Finding.get_number_severity(System_Settings.objects.get().jira_minimum_severity) if push_to_jira: if JIRA_PKey.objects.filter(product=prod).count() == 0: - log_jira_alert('Finding cannot be pushed to jira as there is no jira configuration for this product.', find) + logger.error("Finding {} cannot be pushed to JIRA as there is no JIRA configuration for this product.".format(find.id)) + log_jira_alert('Finding cannot be pushed to JIRA as there is no JIRA configuration for this product.', find) return jpkey = JIRA_PKey.objects.get(product=prod) jira_conf = jpkey.conf if 'Active' in find.status() and 'Verified' in find.status(): - if ((jpkey.push_all_issues and Finding.get_number_severity( - System_Settings.objects.get().jira_minimum_severity) >= - Finding.get_number_severity(find.severity))): - log_jira_alert( - 'Finding below jira_minimum_severity threshold.', find) + if jira_minimum_threshold > Finding.get_number_severity(find.severity): + log_jira_alert('Finding below the minimum jira severity threshold.', find) + logger.warn("Finding {} is below the minimum jira severity threshold.".format(find.id)) + logger.warn("The JIRA issue will NOT be created.") + return - else: - logger.debug('Trying to create a new JIRA issue') - try: - JIRAError.log_to_tempfile = False - jira = JIRA( - server=jira_conf.url, - basic_auth=(jira_conf.username, jira_conf.password)) - if jpkey.component: - new_issue = jira.create_issue( - project=jpkey.project_key, - summary=find.title, - components=[ - { - 'name': jpkey.component - }, - ], - description=jira_long_description( - find.long_desc(), find.id, - jira_conf.finding_text), - issuetype={'name': jira_conf.default_issue_type}, - priority={ - 'name': jira_conf.get_priority(find.severity) - }) - else: - new_issue = jira.create_issue( - project=jpkey.project_key, - summary=find.title, - description=jira_long_description( - find.long_desc(), find.id, - jira_conf.finding_text), - issuetype={'name': jira_conf.default_issue_type}, - priority={ - 'name': jira_conf.get_priority(find.severity) - }) - j_issue = JIRA_Issue( - jira_id=new_issue.id, jira_key=new_issue, finding=find) - j_issue.save() - # Moving this to the save function - # find.jira_creation = timezone.now() - # find.jira_change = find.jira_creation - # find.save() - issue = jira.issue(new_issue.id) - - # Add labels (security & product) - add_labels(find, new_issue) - # Upload dojo finding screenshots to Jira - for pic in find.images.all(): - jira_attachment( - jira, issue, - settings.MEDIA_ROOT + pic.image_large.name) - - # if jpkey.enable_engagement_epic_mapping: - # epic = JIRA_Issue.objects.get(engagement=eng) - # issue_list = [j_issue.jira_id,] - # jira.add_issues_to_epic(epic_id=epic.jira_id, issue_keys=[str(j_issue.jira_id)], ignore_epics=True) - except JIRAError as e: - log_jira_alert(e.text, find) + logger.debug('Trying to create a new JIRA issue for finding {}...'.format(find.id)) + try: + JIRAError.log_to_tempfile = False + jira = JIRA( + server=jira_conf.url, + basic_auth=(jira_conf.username, jira_conf.password)) + if jpkey.component: + logger.debug('... with a component') + new_issue = jira.create_issue( + project=jpkey.project_key, + summary=find.title, + components=[ + { + 'name': jpkey.component + }, + ], + description=jira_long_description( + find.long_desc(), find.id, + jira_conf.finding_text), + issuetype={'name': jira_conf.default_issue_type}, + priority={ + 'name': jira_conf.get_priority(find.severity) + }) + else: + logger.debug('... with no component') + new_issue = jira.create_issue( + project=jpkey.project_key, + summary=find.title, + description=jira_long_description( + find.long_desc(), find.id, + jira_conf.finding_text), + issuetype={'name': jira_conf.default_issue_type}, + priority={ + 'name': jira_conf.get_priority(find.severity) + }) + + j_issue = JIRA_Issue( + jira_id=new_issue.id, jira_key=new_issue, finding=find) + j_issue.save() + issue = jira.issue(new_issue.id) + + # Add labels (security & product) + add_labels(find, new_issue) + + # Upload dojo finding screenshots to Jira + for pic in find.images.all(): + jira_attachment( + jira, issue, + settings.MEDIA_ROOT + pic.image_large.name) + + # if jpkey.enable_engagement_epic_mapping: + # epic = JIRA_Issue.objects.get(engagement=eng) + # issue_list = [j_issue.jira_id,] + # jira.add_issues_to_epic(epic_id=epic.jira_id, issue_keys=[str(j_issue.jira_id)], ignore_epics=True) + except JIRAError as e: + logger.error(e.text, find) + log_jira_alert(e.text, find) else: - log_jira_alert("Finding not active or not verified.", - find) + logger.warning("A Finding needs to be both Active and Verified to be pushed to JIRA.", find) def jira_attachment(jira, issue, file, jira_filename=None): - basename = file if jira_filename is None: basename = os.path.basename(file) @@ -1638,21 +1638,24 @@ def send_review_email(request, user, finding, users, new_note): def process_notifications(request, note, parent_url, parent_title): regex = re.compile(r'(?:\A|\s)@(\w+)\b') + usernames_to_check = set([un.lower() for un in regex.findall(note.entry)]) + users_to_notify = [ User.objects.filter(username=username).get() for username in usernames_to_check if User.objects.filter(is_active=True, username=username).exists() ] # is_staff also? - user_posting = request.user + if len(note.entry) > 200: note.entry = note.entry[:200] note.entry += "..." + create_notification( event='user_mentioned', section=parent_title, note=note, - user=request.user, + initiator=request.user, title='%s jotted a note' % request.user, url=parent_url, icon='commenting', diff --git a/setup.py b/setup.py index c85a5943d31..e4a81e10c59 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setup( name='DefectDojo', - version='1.6.2', + version='1.6.5', author='Greg Anderson', description="Tool for managing vulnerability engagements", install_requires=[ diff --git a/setup/scripts/common/prompt.sh b/setup/scripts/common/prompt.sh index 87455b1a7dd..730264fe477 100644 --- a/setup/scripts/common/prompt.sh +++ b/setup/scripts/common/prompt.sh @@ -329,6 +329,21 @@ prompt_for_config_vals() { esac done + # Sanity check answers, and exit if DB does not yet exist and DBTYPE is not mysql + if [ ! "$DB_TYPE" = "MySQL" ] && [ "$DB_EXISTS" = false ]; then + echo "" + echo "##############################################################################" + echo "# AN ERROR HAS OCCURED #" + echo "##############################################################################" + echo "" + echo " You answered that the $DB_TYPE doesn't already exist" + echo " This installer currently can only create MySQL databases." + echo " Please create a database manually and re-run this installer" + echo " Exiting..." + echo "" + exit 1 + fi + # Sanity check answers, and exit if DB is remote and doesn't exists aka beyond the scope of this installer # Case 1: Remote database + database doesn't exist if [ "$DB_LOCAL" = false ] && [ "$DB_EXISTS" = false ]; then @@ -488,3 +503,12 @@ prompt_for_config_vals() { echo "==============================================================================" echo "" } + +print_eol_message() { + echo + echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + echo " The setup.bash installation method will be EOL on 2020-12-31 " + echo " A likely successor will be godojo (https://github.com/mtesauro/godojo) " + echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + echo +} diff --git a/setup/setup.bash b/setup/setup.bash index f83d47f7ad8..9a0329cff70 100755 --- a/setup/setup.bash +++ b/setup/setup.bash @@ -31,6 +31,9 @@ LIB_PATH="$SETUP_BASE/scripts/common" . "$LIB_PATH/common-os.sh" # Determine what OS the installer is running on . "$LIB_PATH/install-dojo.sh" # Complete an install of Dojo based on previously run code +# Print the EOL message +print_eol_message + # Read command-line arguments, if any and set/override config defaults as needed # Function in ./scripts/common/cmd-args.sh read_cmd_args diff --git a/tests/Endpoint_unit_test.py b/tests/Endpoint_unit_test.py index 1b078fb8c3d..3d289f5d1f1 100644 --- a/tests/Endpoint_unit_test.py +++ b/tests/Endpoint_unit_test.py @@ -1,6 +1,5 @@ from selenium.webdriver.support.ui import Select import unittest -import re import sys from base_test_class import BaseTestCase from Product_unit_test import ProductTest @@ -27,9 +26,9 @@ def test_create_endpoint(self): # submit driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Endpoint added successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Endpoint added successfully')) def test_edit_endpoint(self): # Login to the site. Password will have to be modified @@ -53,9 +52,9 @@ def test_edit_endpoint(self): # "Click" the submit button to complete the transaction driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the product has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Endpoint updated successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Endpoint updated successfully')) def test_delete_endpoint(self): # Login to the site. Password will have to be modified @@ -72,9 +71,9 @@ def test_delete_endpoint(self): # "Click" the delete button to complete the transaction driver.find_element_by_css_selector("button.btn.btn-danger").click() # Query the site to determine if the product has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Endpoint and relationships removed.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Endpoint and relationships removed.')) def suite(): diff --git a/tests/Engagement_unit_test.py b/tests/Engagement_unit_test.py index ee60d9c47b9..bf21870e118 100644 --- a/tests/Engagement_unit_test.py +++ b/tests/Engagement_unit_test.py @@ -1,6 +1,5 @@ from selenium.webdriver.support.ui import Select import unittest -import re import sys from base_test_class import BaseTestCase from Product_unit_test import ProductTest @@ -27,8 +26,8 @@ def test_add_new_engagement(self): driver.find_element_by_id('id_test_strategy').send_keys("http://localhost:5000") Select(driver.find_element_by_id("id_status")).select_by_visible_text("In Progress") driver.find_element_by_css_selector("input[value='Done']").click() - EngagementTXT = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', EngagementTXT)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) def test_edit_created_new_engagement(self): driver = self.login_page() @@ -42,8 +41,8 @@ def test_edit_created_new_engagement(self): driver.find_element_by_id("id_name").send_keys("edited test engagement") Select(driver.find_element_by_id("id_status")).select_by_visible_text("In Progress") driver.find_element_by_css_selector("input[value='Done']").click() - EngagementTXT = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement updated successfully.', EngagementTXT)) + + self.assertTrue(self.is_success_message_present(text='Engagement updated successfully.')) def test_close_new_engagement(self): driver = self.login_page() @@ -53,8 +52,8 @@ def test_close_new_engagement(self): driver.find_element_by_link_text("edited test engagement").click() driver.find_element_by_id("dropdownMenu1").click() driver.find_element_by_link_text("Close Engagement").click() - EngagementTXT = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement closed successfully.', EngagementTXT)) + + self.assertTrue(self.is_success_message_present(text='Engagement closed successfully.')) def test_delete_new_closed_engagement(self): driver = self.login_page() @@ -65,8 +64,8 @@ def test_delete_new_closed_engagement(self): driver.find_element_by_id("dropdownMenu1").click() driver.find_element_by_link_text('Delete Engagement').click() driver.find_element_by_name('delete_name').click() - EngagementTXT = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement and relationships removed.', EngagementTXT)) + + self.assertTrue(self.is_success_message_present(text='Engagement and relationships removed.')) def test_new_ci_cd_engagement(self): driver = self.login_page() @@ -80,8 +79,8 @@ def test_new_ci_cd_engagement(self): driver.find_element_by_id("id_name").send_keys("\ttest new ci/cd engagement") driver.find_element_by_id('id_deduplication_on_engagement').get_attribute('checked') driver.find_element_by_css_selector("input[value='Done']").click() - EngagementTXT = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', EngagementTXT)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) def suite(): diff --git a/tests/Environment_unit_test.py b/tests/Environment_unit_test.py index 5246e6094d8..52653fdbf4e 100644 --- a/tests/Environment_unit_test.py +++ b/tests/Environment_unit_test.py @@ -1,5 +1,4 @@ import unittest -import re import sys import os from base_test_class import BaseTestCase @@ -25,8 +24,8 @@ def test_create_environment(self): driver.find_element_by_id("id_name").clear() driver.find_element_by_id("id_name").send_keys("environment test") driver.find_element_by_css_selector("input.btn.btn-primary").click() - productTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Environment added successfully.', productTxt)) + + self.assertTrue(self.is_success_message_present(text='Environment added successfully.')) def test_edit_environment(self): driver = self.login_page() @@ -35,16 +34,16 @@ def test_edit_environment(self): driver.find_element_by_id("id_name").clear() driver.find_element_by_id("id_name").send_keys("Edited environment test") driver.find_element_by_css_selector("input.btn.btn-primary").click() - productTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Environment updated successfully.', productTxt)) + + self.assertTrue(self.is_success_message_present(text='Environment updated successfully.')) def test_delete_environment(self): driver = self.login_page() driver.get(self.base_url + "dev_env") driver.find_element_by_link_text("Edited environment test").click() driver.find_element_by_css_selector("input.btn.btn-danger").click() - productTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Environment deleted successfully.', productTxt)) + + self.assertTrue(self.is_success_message_present(text='Environment deleted successfully.')) def suite(): diff --git a/tests/Finding_unit_test.py b/tests/Finding_unit_test.py index 363067a87d2..a4d516fa2c0 100644 --- a/tests/Finding_unit_test.py +++ b/tests/Finding_unit_test.py @@ -1,10 +1,9 @@ from selenium.webdriver.support.ui import Select from selenium.webdriver.common.keys import Keys import unittest -import re import sys import os -from base_test_class import BaseTestCase +from base_test_class import BaseTestCase, on_exception_html_source_logger from Product_unit_test import ProductTest, WaitForPageLoad dir_path = os.path.dirname(os.path.realpath(__file__)) @@ -43,7 +42,7 @@ def test_edit_finding(self): # login to site, password set to fetch from environ driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -58,9 +57,9 @@ def test_edit_finding(self): # "Click" the Done button to Edit the finding driver.find_element_by_xpath("//input[@name='_Finished']").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Finding saved successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Finding saved successfully')) def test_add_image(self): # print("\n\nDebug Print Log: testing 'add image' \n") @@ -69,7 +68,7 @@ def test_add_image(self): # login to site, password set to fetch from environ driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -84,15 +83,15 @@ def test_add_image(self): with WaitForPageLoad(driver, timeout=50): driver.find_element_by_css_selector("button.btn.btn-success").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Images updated successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Images updated successfully')) def test_mark_finding_for_review(self): # login to site, password set to fetch from environ driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -113,15 +112,15 @@ def test_mark_finding_for_review(self): # Click 'Mark for reveiw' driver.find_element_by_name("submit").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Finding marked for review and reviewers notified.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Finding marked for review and reviewers notified.')) def test_clear_review_from_finding(self): # login to site, password set to fetch from environ driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on `Clear Review` link text @@ -135,15 +134,15 @@ def test_clear_review_from_finding(self): # Click 'Clear reveiw' button driver.find_element_by_name("submit").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Finding review has been updated successfully.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Finding review has been updated successfully.')) def test_delete_image(self): # login to site, password set to fetch from environ driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -155,14 +154,14 @@ def test_delete_image(self): # Save selection(s) for image deletion driver.find_element_by_css_selector("button.btn.btn-success").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Images updated successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Images updated successfully')) def test_close_finding(self): driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -174,14 +173,14 @@ def test_close_finding(self): # click 'close Finding' submission button driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Finding closed.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Finding closed.')) def test_make_finding_a_template(self): driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -189,10 +188,9 @@ def test_make_finding_a_template(self): # Click on `Make Finding a Template` driver.find_element_by_link_text("Make Finding a Template").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Finding template added successfully. You may edit it here.', productTxt) or - re.search(r'A finding template with that title already exists.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Finding template added successfully. You may edit it here.')) def test_apply_template_to_a_finding(self): driver = self.login_page() @@ -200,6 +198,7 @@ def test_apply_template_to_a_finding(self): print("\nListing findings \n") driver.get(self.base_url + "finding") self.assertNoConsoleErrors() + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -224,10 +223,11 @@ def test_apply_template_to_a_finding(self): driver.find_element_by_name('_Finished').click() self.assertNoConsoleErrors() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'App Vulnerable to XSS', productTxt)) + self.assertTrue(self.is_text_present_on_page(text='App Vulnerable to XSS')) + @on_exception_html_source_logger def test_delete_finding_template(self): driver = self.login_page() # Navigate to All Finding page @@ -239,14 +239,14 @@ def test_delete_finding_template(self): # Click 'Yes' on Alert popup driver.switch_to.alert.accept() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Finding Template deleted successfully.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Finding Template deleted successfully.')) def test_import_scan_result(self): driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'Finding' dropdown menubar @@ -262,11 +262,11 @@ def test_import_scan_result(self): with WaitForPageLoad(driver, timeout=50): driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # print("\n\nDebug Print Log: findingTxt fetched: {}\n".format(productTxt)) # print("Checking for '.*ZAP Scan processed, a total of 4 findings were processed.*'") # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'ZAP Scan processed, a total of 4 findings were processed', productTxt)) + self.assertTrue(self.is_success_message_present(text='ZAP Scan processed, a total of 4 findings were processed')) def test_delete_finding(self): # The Name of the Finding created by test_add_product_finding => 'App Vulnerable to XSS' @@ -274,7 +274,9 @@ def test_delete_finding(self): # login to site, password set to fetch from environ driver = self.login_page() # Navigate to All Finding page - driver.get(self.base_url + "finding") + # driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) + # Select and click on the particular finding to edit driver.find_element_by_link_text("App Vulnerable to XSS").click() # Click on the 'dropdownMenu1 button' @@ -284,9 +286,10 @@ def test_delete_finding(self): # Click 'Yes' on Alert popup driver.switch_to.alert.accept() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Finding deleted successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Finding deleted successfully')) + # check that user was redirect back to url where it came from based on return_url def add_finding_tests_to_suite(suite, jira=False, github=False): @@ -295,6 +298,8 @@ def add_finding_tests_to_suite(suite, jira=False, github=False): if github: suite.addTest(FindingTest('enable_github')) + # suite.addTest(FindingTest('test_delete_finding_template')) + # Add each test the the suite to be run # success and failure is output by the test suite.addTest(ProductTest('test_create_product')) @@ -315,8 +320,7 @@ def add_finding_tests_to_suite(suite, jira=False, github=False): suite.addTest(FindingTest('test_import_scan_result')) suite.addTest(FindingTest('test_delete_finding')) - # skip because it is failing in chrome 83 (but working in chrome 81 and earlier), only on 1.6.0 release branch to get the release out. - # suite.addTest(FindingTest('test_delete_finding_template')) + suite.addTest(FindingTest('test_delete_finding_template')) suite.addTest(ProductTest('test_delete_product')) return suite diff --git a/tests/Import_scanner_unit_test.py b/tests/Import_scanner_unit_test.py index 37babbccecd..9f0967fade4 100644 --- a/tests/Import_scanner_unit_test.py +++ b/tests/Import_scanner_unit_test.py @@ -52,7 +52,6 @@ def test_check_test_file(self): def test_check_for_doc(self): driver = self.driver driver.get('https://defectdojo.readthedocs.io/en/latest/integrations.html') - integration_text = driver.find_element_by_tag_name("BODY").text integration_index = integration_text.index('Integrations') + len('Integrations') + 1 usage_index = integration_text.index('Usage Examples') - len('Models') - 2 diff --git a/tests/Note_type_unit_test.py b/tests/Note_type_unit_test.py index 6af49da7b9d..fb06be47b82 100644 --- a/tests/Note_type_unit_test.py +++ b/tests/Note_type_unit_test.py @@ -1,5 +1,4 @@ import unittest -import re import sys from base_test_class import BaseTestCase @@ -17,8 +16,8 @@ def test_create_note_type(self): driver.find_element_by_id("id_description").send_keys("Test note type description") driver.find_element_by_id("id_is_single").click() driver.find_element_by_css_selector("input.btn.btn-primary").click() - NoteTypeTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Note Type added successfully.', NoteTypeTxt)) + + self.assertTrue(self.is_success_message_present(text='Note Type added successfully.')) def test_edit_note_type(self): driver = self.login_page() @@ -27,24 +26,24 @@ def test_edit_note_type(self): driver.find_element_by_id("id_name").clear() driver.find_element_by_id("id_name").send_keys("Edited test note type") driver.find_element_by_css_selector("input.btn.btn-primary").click() - NoteTypeTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Note type updated successfully.', NoteTypeTxt)) + + self.assertTrue(self.is_success_message_present(text='Note type updated successfully.')) def test_disable_note_type(self): driver = self.login_page() driver.get(self.base_url + "note_type") driver.find_element_by_link_text("Disable Note Type").click() driver.find_element_by_css_selector("input.btn.btn-danger").click() - NoteTypeTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Note type Disabled successfully.', NoteTypeTxt)) + + self.assertTrue(self.is_success_message_present(text='Note type Disabled successfully.')) def test_enable_note_type(self): driver = self.login_page() driver.get(self.base_url + "note_type") driver.find_element_by_link_text("Enable Note Type").click() driver.find_element_by_css_selector("input.btn.btn-success").click() - NoteTypeTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Note type Enabled successfully.', NoteTypeTxt)) + + self.assertTrue(self.is_success_message_present(text='Note type Enabled successfully.')) def suite(): diff --git a/tests/Product_type_unit_test.py b/tests/Product_type_unit_test.py index 498433d6a83..eed31cded99 100644 --- a/tests/Product_type_unit_test.py +++ b/tests/Product_type_unit_test.py @@ -1,11 +1,11 @@ import unittest -import re import sys -from base_test_class import BaseTestCase +from base_test_class import BaseTestCase, on_exception_html_source_logger class ProductTypeTest(BaseTestCase): + @on_exception_html_source_logger def test_create_product_type(self): print("\n\nDebug Print Log: testing 'create product type' \n") driver = self.login_page() @@ -16,8 +16,8 @@ def test_create_product_type(self): driver.find_element_by_id("id_name").send_keys("product test type") driver.find_element_by_id("id_critical_product").click() driver.find_element_by_css_selector("input.btn.btn-primary").click() - productTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Product type added successfully.', productTxt)) + + self.assertTrue(self.is_success_message_present(text='Product type added successfully.')) def test_edit_product_type(self): print("\n\nDebug Print Log: testing 'edit product type' \n") @@ -27,8 +27,8 @@ def test_edit_product_type(self): driver.find_element_by_id("id_name").clear() driver.find_element_by_id("id_name").send_keys("Edited product test type") driver.find_element_by_css_selector("input.btn.btn-primary").click() - productTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Product type updated successfully.', productTxt)) + + self.assertTrue(self.is_success_message_present(text='Product type updated successfully.')) def test_delete_product_type(self): print("\n\nDebug Print Log: testing 'delete product type' \n") @@ -37,8 +37,8 @@ def test_delete_product_type(self): # TODO this assumes the first product_type in the list is the one that we just created (and can safely be deleted) driver.find_element_by_link_text("Edit Product Type").click() driver.find_element_by_css_selector("input.btn.btn-danger").click() - productTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Product type Deleted successfully.', productTxt)) + + self.assertTrue(self.is_success_message_present(text='Product type Deleted successfully.')) def suite(): diff --git a/tests/Product_unit_test.py b/tests/Product_unit_test.py index 91ace2fedd9..a8260e3506c 100644 --- a/tests/Product_unit_test.py +++ b/tests/Product_unit_test.py @@ -1,7 +1,6 @@ from selenium.webdriver.support.ui import Select from selenium.webdriver.common.keys import Keys import unittest -import re import sys import time from base_test_class import BaseTestCase, on_exception_html_source_logger @@ -57,11 +56,11 @@ def test_create_product(self): # "Click" the submit button to complete the transaction driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the product has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure # Also confirm success even if Product is returned as already exists for test sake - self.assertTrue(re.search(r'Product added successfully', productTxt) or - re.search(r'Product with this Name already exists.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Product added successfully') or + self.is_success_message_present(text='Product with this Name already exists.')) @on_exception_html_source_logger def test_list_products(self): @@ -90,10 +89,10 @@ def test_edit_product_description(self): # "Click" the submit button to complete the transaction driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the product has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Product updated successfully', productTxt) or - re.search(r'Product with this Name already exists.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Product updated successfully') or + self.is_success_message_present(text='Product with this Name already exists.')) @on_exception_html_source_logger def test_add_product_engagement(self): @@ -129,9 +128,9 @@ def test_add_product_engagement(self): # "Click" the Done button to Add the engagement driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the product has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert of the query to dtermine status of failure - self.assertTrue(re.search(r'Engagement added successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Engagement added successfully')) @on_exception_html_source_logger def test_add_product_finding(self): @@ -171,9 +170,9 @@ def test_add_product_finding(self): with WaitForPageLoad(driver, timeout=30): driver.find_element_by_xpath("//input[@name='_Finished']").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert to the query to dtermine status of failure - self.assertTrue(re.search(r'App Vulnerable to XSS', productTxt)) + self.assertTrue(self.is_text_present_on_page(text='App Vulnerable to XSS')) @on_exception_html_source_logger def test_add_product_endpoints(self): @@ -195,9 +194,9 @@ def test_add_product_endpoints(self): # submit driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Endpoint added successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Endpoint added successfully')) @on_exception_html_source_logger def test_add_product_custom_field(self): @@ -222,11 +221,11 @@ def test_add_product_custom_field(self): # submit driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure # Also confirm success even if variable is returned as already exists for test sake - self.assertTrue(re.search(r'Metadata added successfully', productTxt) or - re.search(r'A metadata entry with the same name exists already for this object.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Metadata added successfully') or + self.is_success_message_present(text='A metadata entry with the same name exists already for this object.')) @on_exception_html_source_logger def test_edit_product_custom_field(self): @@ -248,10 +247,10 @@ def test_edit_product_custom_field(self): # submit driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine success or failure - self.assertTrue(re.search(r'Metadata edited successfully', productTxt) or - re.search(r'A metadata entry with the same name exists already for this object.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Metadata edited successfully') or + self.is_success_message_present(text='A metadata entry with the same name exists already for this object.')) @on_exception_html_source_logger def test_add_product_tracking_files(self): @@ -276,9 +275,9 @@ def test_add_product_tracking_files(self): # submit driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Added Tracked File to a Product', productTxt)) + self.assertTrue(self.is_success_message_present(text='Added Tracked File to a Product')) @on_exception_html_source_logger def test_edit_product_tracking_files(self): @@ -302,9 +301,9 @@ def test_edit_product_tracking_files(self): # submit driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the Tracking file has been updated - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Tool Product Configuration Successfully Updated', productTxt)) + self.assertTrue(self.is_success_message_present(text='Tool Product Configuration Successfully Updated')) @on_exception_html_source_logger def delete_product_if_exists(self): @@ -331,9 +330,33 @@ def test_delete_product(self): # "Click" the delete button to complete the transaction driver.find_element_by_css_selector("button.btn.btn-danger").click() # Query the site to determine if the product has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to determine status of failure - self.assertTrue(re.search(r'Product and relationships removed.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Product and relationships removed.')) + + @on_exception_html_source_logger + def test_product_notifications_change(self): + # Login to the site. Password will have to be modified + # to match an admin password in your own container + driver = self.login_page() + self.goto_product_overview(driver) + # Select the specific product to delete + driver.find_element_by_link_text("QA Test").click() + + driver.find_element_by_xpath("//input[@name='engagement_added' and @value='mail']").click() + # clicking == ajax call to submit, but I think selenium gets this + + self.assertTrue(self.is_success_message_present(text='Notification settings updated')) + self.assertTrue(driver.find_element_by_xpath("//input[@name='engagement_added' and @value='mail']").is_selected()) + self.assertFalse(driver.find_element_by_xpath("//input[@name='scan_added' and @value='mail']").is_selected()) + self.assertFalse(driver.find_element_by_xpath("//input[@name='test_added' and @value='mail']").is_selected()) + + driver.find_element_by_xpath("//input[@name='scan_added' and @value='mail']").click() + + self.assertTrue(self.is_success_message_present(text='Notification settings updated')) + self.assertTrue(driver.find_element_by_xpath("//input[@name='engagement_added' and @value='mail']").is_selected()) + self.assertTrue(driver.find_element_by_xpath("//input[@name='scan_added' and @value='mail']").is_selected()) + self.assertFalse(driver.find_element_by_xpath("//input[@name='test_added' and @value='mail']").is_selected()) def add_product_tests_to_suite(suite): diff --git a/tests/Test_unit_test.py b/tests/Test_unit_test.py index d0b95207062..e96fed7b5d4 100644 --- a/tests/Test_unit_test.py +++ b/tests/Test_unit_test.py @@ -1,6 +1,5 @@ from selenium.webdriver.support.ui import Select import unittest -import re import sys from base_test_class import BaseTestCase from Product_unit_test import ProductTest @@ -90,15 +89,15 @@ def test_create_test(self): # submit driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the Test has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert on the query to determine success or failure - self.assertTrue(re.search(r'Test added successfully', productTxt)) + self.assertTrue(self.is_success_message_present(text='Test added successfully')) def test_edit_test(self): # Login to the site. driver = self.login_page() # Navigate to the engagement page - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) # Select a previously created engagement title driver.find_element_by_partial_link_text("Quick Security Testing").click() # "Click" the dropdown button to see options @@ -110,15 +109,15 @@ def test_edit_test(self): # "Click" the submit button to complete the transaction driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the Test has been updated - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Test saved.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Test saved.')) def test_add_note(self): # Login to the site. driver = self.login_page() # Navigate to the engagement page - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) # Select a previously created engagement title driver.find_element_by_partial_link_text("Quick Security Testing").click() # "Click" the dropdown button to see options @@ -131,16 +130,16 @@ def test_add_note(self): # "Click" the submit button to complete the transaction driver.find_element_by_xpath("//input[@value='Add Note']").click() # Query the site to determine if the Test has been updated - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Note added successfully.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Note added successfully.')) def test_delete_test(self): # Login to the site. Password will have to be modified # to match an admin password in your own container driver = self.login_page() # Navigate to the engagement page - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) # Select a previously created engagement title driver.find_element_by_partial_link_text("Quick Security Testing").click() # "Click" the dropdown button to see options @@ -153,9 +152,9 @@ def test_delete_test(self): # "Click" the delete button to complete the transaction driver.find_element_by_css_selector("button.btn.btn-danger").click() # Query the site to determine if the product has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'Test and relationships removed.', productTxt)) + self.assertTrue(self.is_success_message_present(text='Test and relationships removed.')) def suite(): diff --git a/tests/User_unit_test.py b/tests/User_unit_test.py index 7a1ec65b5f8..b5245ab1736 100644 --- a/tests/User_unit_test.py +++ b/tests/User_unit_test.py @@ -1,6 +1,5 @@ # from selenium.webdriver.support.ui import Select import unittest -import re import sys from base_test_class import BaseTestCase @@ -36,10 +35,10 @@ def test_create_user(self): # "Click" the submit button to complete the transaction driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the user has been created - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'User added successfully, you may edit if necessary.', productTxt) or - re.search(r'A user with that username already exists.', productTxt)) + self.assertTrue(self.is_success_message_present(text='User added successfully, you may edit if necessary.') or + self.is_success_message_present(text='A user with that username already exists.')) def test_user_edit_permissions(self): # Login to the site. Password will have to be modified @@ -65,9 +64,9 @@ def test_user_edit_permissions(self): # "Click" the submit button to complete the transaction driver.find_element_by_css_selector("input.btn.btn-primary").click() # Query the site to determine if the User permission has been changed - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'User saved successfully.', productTxt)) + self.assertTrue(self.is_success_message_present(text='User saved successfully.')) def test_user_delete(self): # Login to the site. Password will have to be modified @@ -91,9 +90,29 @@ def test_user_delete(self): # confirm deletion, by clicking delete a second time driver.find_element_by_css_selector("button.btn.btn-danger").click() # Query the site to determine if the User has been deleted - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert ot the query to dtermine status of failure - self.assertTrue(re.search(r'User and relationships removed.', productTxt)) + self.assertTrue(self.is_success_message_present(text='User and relationships removed.')) + + def test_user_notifications_change(self): + # Login to the site. Password will have to be modified + # to match an admin password in your own container + driver = self.login_page() + + wait = WebDriverWait(driver, 5) + actions = ActionChains(driver) + configuration_menu = driver.find_element_by_id('menu_configuration') + actions.move_to_element(configuration_menu).perform() + wait.until(EC.visibility_of_element_located((By.LINK_TEXT, "Notifications"))).click() + + driver.find_element_by_xpath("//input[@name='product_added' and @value='mail']").click() + driver.find_element_by_xpath("//input[@name='scan_added' and @value='mail']").click() + + driver.find_element_by_css_selector("input.btn.btn-primary").click() + + self.assertTrue(self.is_success_message_present(text='Settings saved')) + self.assertTrue(driver.find_element_by_xpath("//input[@name='product_added' and @value='mail']").is_selected()) + self.assertTrue(driver.find_element_by_xpath("//input[@name='scan_added' and @value='mail']").is_selected()) def suite(): diff --git a/tests/base_test_class.py b/tests/base_test_class.py index bdb019a2711..a419ac7b939 100644 --- a/tests/base_test_class.py +++ b/tests/base_test_class.py @@ -3,11 +3,12 @@ from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait +from selenium.common.exceptions import NoAlertPresentException import unittest import os import re - +# import time dd_driver = None dd_driver_options = None @@ -31,6 +32,7 @@ def setUpClass(cls): # the next 2 maybe needed in some scenario's for example on WSL or other headless situations dd_driver_options.add_argument("--no-sandbox") # dd_driver_options.add_argument("--disable-dev-shm-usage") + dd_driver_options.add_argument("--disable-gpu") # on windows sometimes chrome can't start with certain gpu driver versions, even in headless mode # start maximized or at least with sufficient with because datatables will hide certain controls when the screen is too narrow dd_driver_options.add_argument("--window-size=1280,768") @@ -45,7 +47,8 @@ def setUpClass(cls): # change path of chromedriver according to which directory you have chromedriver. print('starting chromedriver with options: ', vars(dd_driver_options), desired) dd_driver = webdriver.Chrome('chromedriver', chrome_options=dd_driver_options, desired_capabilities=desired) - dd_driver.implicitly_wait(30) + # best practice is only use explicit waits + dd_driver.implicitly_wait(1) cls.driver = dd_driver cls.base_url = os.environ['DD_BASE_URL'] @@ -65,28 +68,20 @@ def login_page(self): driver.find_element_by_id("id_password").clear() driver.find_element_by_id("id_password").send_keys(os.environ['DD_ADMIN_PASSWORD']) driver.find_element_by_css_selector("button.btn.btn-success").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertFalse(re.search(r'Please enter a correct username and password', text)) + + self.assertFalse(self.is_element_by_css_selector_present('.alert-danger', 'Please enter a correct username and password')) return driver def goto_product_overview(self, driver): driver.get(self.base_url + "product") - body = driver.find_element_by_tag_name("BODY").text - # print('BODY:') - # print(body) - # print('re.search:', re.search(r'No products found', body)) - - if re.search(r'No products found', body): - return driver - - # wait for product_wrapper div as datatables javascript modifies the DOM on page load. - WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.ID, "products_wrapper"))) + self.wait_for_datatable_if_content("no_products", "products_wrapper") def goto_active_engagements_overview(self, driver): # return self.goto_engagements_internal(driver, 'engagement') # engagement overview doesn't seem to have the datatables yet modifying the DOM # https://github.com/DefectDojo/django-DefectDojo/issues/2173 driver.get(self.base_url + 'engagement') + # self.goto_engagements_internal(driver, 'engagement') return driver def goto_all_engagements_overview(self, driver): @@ -94,17 +89,62 @@ def goto_all_engagements_overview(self, driver): def goto_engagements_internal(self, driver, rel_url): driver.get(self.base_url + rel_url) - body = driver.find_element_by_tag_name("BODY").text - # print('BODY:') - # print(body) - # print('re.search:', re.search(r'No products found', body)) + self.wait_for_datatable_if_content("no_engagements", "engagements_wrapper") + return driver - if re.search(r'No engagements found', body): - return driver + def goto_all_findings_list(self, driver): + driver.get(self.base_url + "finding") + self.wait_for_datatable_if_content("no_findings", "open_findings_wrapper") - # wait for engagements_wrapper div as datatables javascript modifies the DOM on page load. - WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.ID, "engagements_wrapper"))) - return driver + def wait_for_datatable_if_content(self, no_content_id, wrapper_id): + no_content = None + try: + no_content = self.driver.find_element_by_id(no_content_id) + except: + pass + + if no_content is None: + # wait for product_wrapper div as datatables javascript modifies the DOM on page load. + WebDriverWait(self.driver, 30).until(EC.presence_of_element_located((By.ID, wrapper_id))) + + def is_element_by_css_selector_present(self, selector, text=None): + elems = self.driver.find_elements_by_css_selector(selector) + if len(elems) == 0: + # print('no elements!') + return False + + if text is None: + return True + + for elem in elems: + print(elem.text) + if text in elem.text: + # print('contains!') + return True + + # print('text mismatch!') + return False + + def is_success_message_present(self, text=None): + return self.is_element_by_css_selector_present('.alert-success', text=text) + + def is_error_message_present(self, text=None): + return self.is_element_by_css_selector_present('.alert-danger', text=text) + + def is_text_present_on_page(self, text): + # DEBUG: couldn't find: Product type added successfully. path: //*[contains(text(),'Product type added successfully.')] + # can't get this xpath to work + # path = "//*[contains(text(), '" + text + "')]" + # elems = self.driver.find_elements_by_xpath(path) + # if len(elems) == 0: + # print("DEBUG: couldn't find: ", text, "path: ", path) + + body = self.driver.find_element_by_tag_name("body") + return re.search(text, body.text) + + def element_exists_by_id(self, id): + elems = self.driver.find_elements_by_id(id) + return len(elems) > 0 def change_system_setting(self, id, enable=True): # we set the admin user (ourselves) to have block_execution checked @@ -156,7 +196,7 @@ def enable_github(self): def is_alert_present(self): try: self.driver.switch_to_alert() - except NoAlertPresentException as e: + except NoAlertPresentException: return False return True @@ -259,7 +299,11 @@ def wrapper(self, *args, **kwargs): return func(self, *args, **kwargs) except Exception as e: - print(self.driver.page_source) + # print(self.driver.page_source) + print("exception url:", self.driver.current_url) + f = open("selenium_page_source.html", "w", encoding='utf-8') + f.writelines(self.driver.page_source) + # time.sleep(30) raise(e) return wrapper diff --git a/tests/chromedriver b/tests/chromedriver deleted file mode 100755 index 11f9d16f4a7..00000000000 Binary files a/tests/chromedriver and /dev/null differ diff --git a/tests/dedupe_unit_test.py b/tests/dedupe_unit_test.py index aa486920e26..229e9ad25de 100644 --- a/tests/dedupe_unit_test.py +++ b/tests/dedupe_unit_test.py @@ -3,7 +3,6 @@ from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException import unittest -import re import sys import os from base_test_class import BaseTestCase, on_exception_html_source_logger @@ -27,7 +26,7 @@ def check_nb_duplicates(self, expected_number_of_duplicates): for i in range(0, 18): time.sleep(5) # wait bit for celery dedupe task which can be slow on travis driver = self.login_page() - driver.get(self.base_url + "finding") + self.goto_all_findings_list(driver) dupe_count = 0 # iterate over the rows of the findings table and concatenates all columns into td.text trs = driver.find_elements_by_xpath('//*[@id="open_findings"]/tbody/tr') @@ -67,23 +66,31 @@ def test_enable_deduplication(self): def test_delete_findings(self): print("removing previous findings...") driver = self.login_page() - driver.get(self.base_url + "finding") - text = driver.find_element_by_tag_name("BODY").text - if 'No findings found.' in text: - return - else: - driver.find_element_by_id("select_all").click() - driver.find_element_by_css_selector("i.fa.fa-trash").click() - try: - WebDriverWait(driver, 1).until(EC.alert_is_present(), - 'Timed out waiting for PA creation ' + - 'confirmation popup to appear.') - driver.switch_to.alert.accept() - except TimeoutException: - self.fail('Confirmation dialogue not shown, cannot delete previous findings') - - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'No findings found.', text)) + driver.get(self.base_url + "finding?page=1") + + if self.element_exists_by_id("no_findings"): + text = driver.find_element_by_id("no_findings").text + if 'No findings found.' in text: + return + + driver.find_element_by_id("select_all").click() + driver.find_element_by_css_selector("i.fa.fa-trash").click() + try: + WebDriverWait(driver, 1).until(EC.alert_is_present(), + 'Timed out waiting for PA creation ' + + 'confirmation popup to appear.') + driver.switch_to.alert.accept() + except TimeoutException: + self.fail('Confirmation dialogue not shown, cannot delete previous findings') + + text = None + if self.element_exists_by_id("no_findings"): + text = driver.find_element_by_id("no_findings").text + + self.assertTrue('No findings found.' in text) + # check that user was redirect back to url where it came from based on return_url + # self.assertTrue(driver.current_url.endswith('page=1')) + # -------------------------------------------------------------------------------------------------------- # Same scanner deduplication - Deduplication on engagement @@ -100,30 +107,30 @@ def test_add_path_test_suite(self): driver.find_element_by_id("id_name").send_keys("Dedupe Path Test") driver.find_element_by_xpath('//*[@id="id_deduplication_on_engagement"]').click() driver.find_element_by_name("_Add Tests").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', text)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) # Add the tests # Test 1 driver.find_element_by_id("id_title").send_keys("Path Test 1") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Bandit Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_name("_Add Another Test").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) # Test 2 driver.find_element_by_id("id_title").send_keys("Path Test 2") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Bandit Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_css_selector("input.btn.btn-primary").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) @on_exception_html_source_logger def test_import_path_tests(self): print("importing reports...") # First test driver = self.login_page() - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Path Test").click() driver.find_element_by_partial_link_text("Path Test 1").click() driver.find_element_by_id("dropdownMenu1").click() @@ -133,11 +140,11 @@ def test_import_path_tests(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_path_1.json") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) # Second test - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Path Test").click() driver.find_element_by_partial_link_text("Path Test 2").click() driver.find_element_by_id("dropdownMenu1").click() @@ -146,8 +153,8 @@ def test_import_path_tests(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_path_2.json") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) @on_exception_html_source_logger def test_check_path_status(self): @@ -171,30 +178,30 @@ def test_add_endpoint_test_suite(self): driver.find_element_by_id("id_name").send_keys("Dedupe Endpoint Test") driver.find_element_by_xpath('//*[@id="id_deduplication_on_engagement"]').click() driver.find_element_by_name("_Add Tests").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', text)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) # Add the tests # Test 1 driver.find_element_by_id("id_title").send_keys("Endpoint Test 1") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Immuniweb Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_name("_Add Another Test").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) # Test 2 driver.find_element_by_id("id_title").send_keys("Endpoint Test 2") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Immuniweb Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_css_selector("input.btn.btn-primary").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) @on_exception_html_source_logger def test_import_endpoint_tests(self): print("Importing reports...") # First test : Immuniweb Scan (dynamic) driver = self.login_page() - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Endpoint Test").click() driver.find_element_by_partial_link_text("Endpoint Test 1").click() driver.find_element_by_id("dropdownMenu1").click() @@ -204,11 +211,11 @@ def test_import_endpoint_tests(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_endpoint_1.xml") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) # Second test : Immuniweb Scan (dynamic) - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Endpoint Test").click() driver.find_element_by_partial_link_text("Endpoint Test 2").click() driver.find_element_by_id("dropdownMenu1").click() @@ -218,8 +225,8 @@ def test_import_endpoint_tests(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_endpoint_2.xml") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) @on_exception_html_source_logger def test_check_endpoint_status(self): @@ -239,30 +246,30 @@ def test_add_same_eng_test_suite(self): driver.find_element_by_id("id_name").send_keys("Dedupe Same Eng Test") driver.find_element_by_xpath('//*[@id="id_deduplication_on_engagement"]').click() driver.find_element_by_name("_Add Tests").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', text)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) # Add the tests # Test 1 driver.find_element_by_id("id_title").send_keys("Same Eng Test 1") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Immuniweb Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_name("_Add Another Test").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) # Test 2 driver.find_element_by_id("id_title").send_keys("Same Eng Test 2") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Generic Findings Import") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_css_selector("input.btn.btn-primary").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) @on_exception_html_source_logger def test_import_same_eng_tests(self): print("Importing reports") # First test : Immuniweb Scan (dynamic) driver = self.login_page() - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Same Eng Test").click() driver.find_element_by_partial_link_text("Same Eng Test 1").click() driver.find_element_by_id("dropdownMenu1").click() @@ -271,11 +278,11 @@ def test_import_same_eng_tests(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_endpoint_1.xml") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) # Second test : Generic Findings Import with Url (dynamic) - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Same Eng Test").click() driver.find_element_by_partial_link_text("Same Eng Test 2").click() driver.find_element_by_id("dropdownMenu1").click() @@ -284,8 +291,8 @@ def test_import_same_eng_tests(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_cross_1.csv") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) @on_exception_html_source_logger def test_check_same_eng_status(self): @@ -311,28 +318,28 @@ def test_add_path_test_suite_checkmarx_scan(self): driver.find_element_by_id("id_name").send_keys("Dedupe on hash_code only") driver.find_element_by_xpath('//*[@id="id_deduplication_on_engagement"]').click() driver.find_element_by_name("_Add Tests").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', text)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) # Add the tests # Test 1 driver.find_element_by_id("id_title").send_keys("Path Test 1") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Checkmarx Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_name("_Add Another Test").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) # Test 2 driver.find_element_by_id("id_title").send_keys("Path Test 2") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Checkmarx Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_css_selector("input.btn.btn-primary").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) def test_import_path_tests_checkmarx_scan(self): # First test driver = self.login_page() - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe on hash_code only").click() driver.find_element_by_partial_link_text("Path Test 1").click() driver.find_element_by_id("dropdownMenu1").click() @@ -342,11 +349,11 @@ def test_import_path_tests_checkmarx_scan(self): # os.path.realpath makes the path canonical driver.find_element_by_id('id_file').send_keys(os.path.realpath(self.relative_path + "/dedupe_scans/multiple_findings.xml")) driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 2 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 2 findings were processed')) # Second test - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe on hash_code only").click() driver.find_element_by_partial_link_text("Path Test 2").click() driver.find_element_by_id("dropdownMenu1").click() @@ -355,8 +362,8 @@ def test_import_path_tests_checkmarx_scan(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(os.path.realpath(self.relative_path + "/dedupe_scans/multiple_findings_line_changed.xml")) driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 2 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 2 findings were processed')) def test_check_path_status_checkmarx_scan(self): # After aggregation, it's only two findings. Both are duplicates even though the line number has changed @@ -378,15 +385,15 @@ def test_add_cross_test_suite(self): driver.find_element_by_id("id_name").send_keys("Dedupe Generic Test") # driver.find_element_by_xpath('//*[@id="id_deduplication_on_engagement"]').click() driver.find_element_by_name("_Add Tests").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', text)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) # Test driver.find_element_by_id("id_title").send_keys("Generic Test") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Generic Findings Import") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_css_selector("input.btn.btn-primary").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) # Create immuniweb engagement self.goto_product_overview(driver) @@ -395,21 +402,21 @@ def test_add_cross_test_suite(self): driver.find_element_by_id("id_name").send_keys("Dedupe Immuniweb Test") # driver.find_element_by_xpath('//*[@id="id_deduplication_on_engagement"]').click() driver.find_element_by_name("_Add Tests").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Engagement added successfully.', text)) + + self.assertTrue(self.is_success_message_present(text='Engagement added successfully.')) # Test driver.find_element_by_id("id_title").send_keys("Immuniweb Test") Select(driver.find_element_by_id("id_test_type")).select_by_visible_text("Immuniweb Scan") Select(driver.find_element_by_id("id_environment")).select_by_visible_text("Development") driver.find_element_by_css_selector("input.btn.btn-primary").click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Test added successfully', text)) + + self.assertTrue(self.is_success_message_present(text='Test added successfully')) def test_import_cross_test(self): print("Importing findings...") # First test : Immuniweb Scan (dynamic) driver = self.login_page() - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Immuniweb Test").click() driver.find_element_by_partial_link_text("Immuniweb Test").click() driver.find_element_by_css_selector("b.fa.fa-ellipsis-v").click() @@ -418,11 +425,11 @@ def test_import_cross_test(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_endpoint_1.xml") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) # Second test : generic scan with url (dynamic) - driver.get(self.base_url + "engagement") + self.goto_active_engagements_overview(driver) driver.find_element_by_partial_link_text("Dedupe Generic Test").click() driver.find_element_by_partial_link_text("Generic Test").click() driver.find_element_by_css_selector("b.fa.fa-ellipsis-v").click() @@ -431,8 +438,8 @@ def test_import_cross_test(self): driver.find_element_by_xpath('//*[@id="base-content"]/form/div[4]/div/div').click() driver.find_element_by_id('id_file').send_keys(self.relative_path + "/dedupe_scans/dedupe_cross_1.csv") driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() - text = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'a total of 3 findings were processed', text)) + + self.assertTrue(self.is_success_message_present(text='a total of 3 findings were processed')) def test_check_cross_status(self): self.check_nb_duplicates(1) diff --git a/tests/ibm_appscan_test.py b/tests/ibm_appscan_test.py index 9544704930f..4e0d3efa461 100644 --- a/tests/ibm_appscan_test.py +++ b/tests/ibm_appscan_test.py @@ -1,6 +1,5 @@ from selenium.webdriver.support.ui import Select import unittest -import re import sys import os from base_test_class import BaseTestCase @@ -33,9 +32,9 @@ def test_import_ibm_app_scan_result(self): # click on upload button driver.find_elements_by_css_selector("button.btn.btn-primary")[1].click() # Query the site to determine if the finding has been added - productTxt = driver.find_element_by_tag_name("BODY").text + # Assert the query to determine status or failure - self.assertTrue(re.search(r'IBM AppScan DAST processed, a total of 27 findings were processed', productTxt)) + self.assertTrue(self.is_success_message_present(text='IBM AppScan DAST processed, a total of 27 findings were processed')) def suite(): diff --git a/tests/local-integration-tests.bat b/tests/local-integration-tests.bat index a72ef00eb00..456d8adb71d 100644 --- a/tests/local-integration-tests.bat +++ b/tests/local-integration-tests.bat @@ -38,6 +38,7 @@ echo "Running Ibm Appscan integration test" python tests/ibm_appscan_test.py if %ERRORLEVEL% NEQ 0 GOTO END +everything in the smoke test is already covered by the other tests echo "Running Smoke integration test" python tests/smoke_test.py if %ERRORLEVEL% NEQ 0 GOTO END diff --git a/tests/local-integration-tests.sh b/tests/local-integration-tests.sh index 6e96c68005c..f18c33ae591 100644 --- a/tests/local-integration-tests.sh +++ b/tests/local-integration-tests.sh @@ -11,7 +11,7 @@ echo "Running Product type integration tests" if python3 tests/Product_type_unit_test.py ; then echo "Success: Product type integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Product type integration test failed."; exit 1 fi @@ -19,7 +19,7 @@ echo "Running Product integration tests" if python3 tests/Product_unit_test.py ; then echo "Success: Product integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Product integration test failed"; exit 1 fi @@ -27,7 +27,7 @@ echo "Running Dedupe integration tests" if python3 tests/dedupe_unit_test.py ; then echo "Success: Dedupe integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Dedupe integration test failed"; exit 1 fi @@ -35,7 +35,7 @@ echo "Running Endpoint integration tests" if python3 tests/Endpoint_unit_test.py ; then echo "Success: Endpoint integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Endpoint integration test failed"; exit 1 fi @@ -43,7 +43,7 @@ echo "Running Engagement integration tests" if python3 tests/Engagement_unit_test.py ; then echo "Success: Engagement integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Engagement integration test failed"; exit 1 fi @@ -51,7 +51,7 @@ echo "Running Environment integration tests" if python3 tests/Environment_unit_test.py ; then echo "Success: Environment integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Environment integration test failed"; exit 1 fi @@ -59,7 +59,7 @@ echo "Running Finding integration tests" if python3 tests/Finding_unit_test.py ; then echo "Success: Finding integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Finding integration test failed"; exit 1 fi @@ -67,7 +67,7 @@ echo "Running Test integration tests" if python3 tests/Test_unit_test.py ; then echo "Success: Test integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Test integration test failed"; exit 1 fi @@ -75,7 +75,7 @@ echo "Running User integration tests" if python3 tests/User_unit_test.py ; then echo "Success: User integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: User integration test failed"; exit 1 fi @@ -83,23 +83,24 @@ echo "Running Ibm Appscan integration test" if python3 tests/ibm_appscan_test.py ; then echo "Success: Ibm AppScan integration tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 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 - docker-compose logs uwsgi --tail=all - echo "Error: Smoke integration test failed"; exit 1 -fi +# everything in the smoke test is already covered by the other tests +# echo "Running Smoke integration test" +# if python3 tests/smoke_test.py ; then +# echo "Success: Smoke integration tests passed" +# else +# docker-compose logs uwsgi --tail=120 +# echo "Error: Smoke integration test failed"; exit 1 +# fi echo "Running Check Status test" if python3 tests/check_status.py ; then echo "Success: check status tests passed" else - docker-compose logs uwsgi --tail=all + docker-compose logs uwsgi --tail=120 echo "Error: Check status tests failed"; exit 1 fi diff --git a/tests/smoke_test.py b/tests/smoke_test.py index 72c1e6d0efe..130a945f826 100644 --- a/tests/smoke_test.py +++ b/tests/smoke_test.py @@ -2,7 +2,6 @@ from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoAlertPresentException import unittest -import re import sys from base_test_class import BaseTestCase @@ -11,8 +10,8 @@ class DojoTests(BaseTestCase): def test_login(self): driver = self.login_page() - loginTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Active Engagements', loginTxt)) + + self.assertTrue(self.is_text_present_on_page(text='Active Engagements')) def test_create_product(self): driver = self.login_page() @@ -25,8 +24,8 @@ def test_create_product(self): driver.find_element_by_id("id_description").send_keys("QA Test 1 Description") Select(driver.find_element_by_id("id_prod_type")).select_by_visible_text("Research and Development") driver.find_element_by_css_selector("input.btn.btn-primary").click() - productTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Product added successfully', productTxt)) + + self.assertTrue(self.is_success_message_present(text='Product added successfully')) def test_engagement(self): driver = self.login_page() @@ -69,8 +68,7 @@ def test_engagement(self): driver.find_element_by_id("id_impact").send_keys("Impact") driver.find_element_by_name("_Finished").click() - findingTxt = driver.find_element_by_tag_name("BODY").text - self.assertTrue(re.search(r'Finding added successfully', findingTxt)) + self.assertTrue(self.is_success_message_present(text='Finding added successfully')) def is_element_present(self, how, what): try: diff --git a/travis/integration_test-script.sh b/travis/integration_test-script.sh index 5024f6fac64..3f65c2f26a1 100644 --- a/travis/integration_test-script.sh +++ b/travis/integration_test-script.sh @@ -31,7 +31,7 @@ export DD_BASE_URL='http://localhost:8080/' function fail() { echo "Error: $1 test failed\n" - docker-compose logs --tail="all" uwsgi + docker-compose logs --tail="120" uwsgi exit 1 }