diff options
-rw-r--r-- | Post/admin.py | 2 | ||||
-rw-r--r-- | Post/createStatistics.py | 1 | ||||
-rw-r--r-- | Post/feed.py | 4 | ||||
-rw-r--r-- | Post/management/commands/culldb.py | 2 | ||||
-rw-r--r-- | Post/migrations/0006_buildfailure_referer.py | 19 | ||||
-rw-r--r-- | Post/models.py | 14 | ||||
-rw-r--r-- | Post/parser.py | 25 | ||||
-rw-r--r-- | Post/purge.py | 27 | ||||
-rw-r--r-- | Post/views.py | 41 | ||||
-rw-r--r-- | README | 2 | ||||
-rwxr-xr-x | manage.py | 2 | ||||
-rw-r--r-- | project/settings.py | 4 | ||||
-rw-r--r-- | project/urls.py | 4 | ||||
-rw-r--r-- | project/wsgi.py | 4 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | templates/error-details.html | 2 | ||||
-rw-r--r-- | templates/latest-errors.html | 2 | ||||
-rwxr-xr-x | test-data/test-send-error.py | 3 |
18 files changed, 125 insertions, 34 deletions
diff --git a/Post/admin.py b/Post/admin.py index f11ff65..43aa9a6 100644 --- a/Post/admin.py +++ b/Post/admin.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT +# # error reporting tool - admin interface definitions # # Copyright (C) 2013 Intel Corporation diff --git a/Post/createStatistics.py b/Post/createStatistics.py index 213927a..09d098e 100644 --- a/Post/createStatistics.py +++ b/Post/createStatistics.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# SPDX-License-Identifier: MIT # Create statistics. Update database. # diff --git a/Post/feed.py b/Post/feed.py index 745ee23..5d57b54 100644 --- a/Post/feed.py +++ b/Post/feed.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT +# # error-reporting-tool - URL definitions # # Copyright (C) 2013 Intel Corporation @@ -25,7 +27,7 @@ class LatestEntriesFeed(Feed): if self.mode == results_mode.SPECIAL_SUBMITTER and hasattr(settings,"SPECIAL_SUBMITTER"): #Special submitter mode see settings.py to enable name = settings.SPECIAL_SUBMITTER['name'] - queryset = BuildFailure.objects.order_by('-BUILD__DATE').filter(BUILD__NAME__istartswith=name)[:self.limit] + queryset = BuildFailure.objects.order_by('-BUILD__DATE').filter(BUILD__NAME__icontains=name)[:self.limit] else: queryset = BuildFailure.objects.order_by('-BUILD__DATE')[:self.limit] diff --git a/Post/management/commands/culldb.py b/Post/management/commands/culldb.py index 698537c..bd70ffc 100644 --- a/Post/management/commands/culldb.py +++ b/Post/management/commands/culldb.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT +# # error-reporting-tool - culldb # # Copyright (C) 2015 Intel Corporation diff --git a/Post/migrations/0006_buildfailure_referer.py b/Post/migrations/0006_buildfailure_referer.py new file mode 100644 index 0000000..5fad048 --- /dev/null +++ b/Post/migrations/0006_buildfailure_referer.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('Post', '0005_build_error_type'), + ] + + operations = [ + migrations.AddField( + model_name='buildfailure', + name='REFERER', + field=models.CharField(default=b'NOT_VISITED', max_length=14, choices=[(b'NO_REFERER', b'no_referer'), (b'OTHER', b'other'), (b'NOT_VISITED', b'not_visited')]), + ), + ] diff --git a/Post/models.py b/Post/models.py index ddf2fc7..b7a913c 100644 --- a/Post/models.py +++ b/Post/models.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT +# # error-reporting-tool - model definitions # # Copyright (C) 2013 Intel Corporation @@ -13,6 +15,7 @@ import Levenshtein class ErrorType(object): RECIPE = 'recipe' + CHECK_LAYER = 'check-layer' CORE = 'core' BITBAKE_SELFTEST = 'bitbake-selftest' OE_SELFTEST = 'oe-selftest' @@ -24,6 +27,7 @@ class InvalidErrorType(Exception): class Build(models.Model): ERROR_TYPE_CHOICES = ( (ErrorType.RECIPE, 'Recipe'), + (ErrorType.CHECK_LAYER, 'check-layer'), (ErrorType.CORE, 'Core'), (ErrorType.BITBAKE_SELFTEST, 'Bitbake selftest'), (ErrorType.OE_SELFTEST, 'OE selftest'), @@ -59,6 +63,16 @@ class BuildFailure(models.Model): ERROR_DETAILS = models.TextField(max_length=int(settings.MAX_UPLOAD_SIZE)) BUILD = models.ForeignKey(Build) LEV_DISTANCE = models.IntegerField(blank=True, null=True) + REFERER_CHOICES = ( + ('NO_REFERER', 'no_referer'), + ('OTHER', 'other'), + ('NOT_VISITED', 'not_visited') + ) + REFERER = models.CharField( + max_length = 14, + choices = REFERER_CHOICES, + default = 'NOT_VISITED' + ) def get_similar_fails(self): if self.LEV_DISTANCE is None: diff --git a/Post/parser.py b/Post/parser.py index 9639308..536e872 100644 --- a/Post/parser.py +++ b/Post/parser.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# SPDX-License-Identifier: MIT # Add errors to database from client # @@ -8,6 +9,7 @@ # Licensed under the MIT license, see COPYING.MIT for details import json, re +import bleach from Post.models import Build, BuildFailure, ErrorType from django.conf import settings from django.utils import timezone @@ -16,18 +18,7 @@ from django.core.urlresolvers import reverse class Parser: def __init__(self, data): - self.data = data - - # returns true if the values contain '<' char - # Ignore the failures field (which is an array anyway) - def contains_tags (self, data): - for key,val in data.items(): - if key == 'failures': - continue - - if '<' in val: - return True - return False + self.data = data.decode('utf-8') def parse(self, request): build_fails_logged = [] @@ -37,8 +28,14 @@ class Parser: except: return { 'error' : 'Invalid json' } - if self.contains_tags(jsondata) == True: - return { 'error' : 'Invalid characters in json' } + # Bleach data going directly into the database so that + # displaying in any of the graphing doesn't introduce XSS + for key,val in jsondata.items(): + if key == 'failures': + continue + if not isinstance(val, str): + continue + jsondata[key] = bleach.clean(val) b = Build.objects.create() try: diff --git a/Post/purge.py b/Post/purge.py new file mode 100644 index 0000000..dd58441 --- /dev/null +++ b/Post/purge.py @@ -0,0 +1,27 @@ +from datetime import datetime, timedelta +from django.utils import timezone +import os +import sys + +def setup_django(): + import django + # Get access to our Django model + newpath = os.path.abspath(os.path.dirname(__file__)) + '/..' + sys.path.append(newpath) + if not os.getenv('DJANGO_SETTINGS_MODULE'): + os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings' + django.setup() + +def main(): + setup_django() + from Post.models import BuildFailure + delete_before = timezone.now()-timedelta(days=45) + query = "SELECT bf.id FROM Post_buildfailure bf LEFT JOIN Post_build b ON (bf.BUILD_id = b.id) WHERE bf.REFERER NOT IN ('OTHER','NO_REFERER') AND b.DATE < '{0}'".format(delete_before.date()) + #print query + items = BuildFailure.objects.raw(query) + for item in items: + print "Deleting: ", item.id + item.delete() + +if __name__ == "__main__": + main() diff --git a/Post/views.py b/Post/views.py index 7f2cffb..3575c1d 100644 --- a/Post/views.py +++ b/Post/views.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT +# # error-reporting-tool - view definitions # # Copyright (C) 2013 Intel Corporation @@ -13,15 +15,16 @@ from django.shortcuts import HttpResponse, render from django.views.decorators.csrf import csrf_exempt from django.shortcuts import redirect from Post.models import BuildFailure, Build, ErrorType -from parser import Parser +from Post.parser import Parser from django.conf import settings -from createStatistics import Statistics +from Post.createStatistics import Statistics from django.core.paginator import Paginator, EmptyPage from django.core.exceptions import FieldError, ObjectDoesNotExist from django.http import JsonResponse from django.db.models import Q import json import urllib +from urllib.parse import urlparse class results_mode(object): LATEST = 0 @@ -42,7 +45,6 @@ def common_context(request): return ret - @csrf_exempt def addData(request, return_json=False): response = '' @@ -63,12 +65,12 @@ def addData(request, return_json=False): if return_json: response = JsonResponse(result) else: - if not result.has_key('error'): + if not 'error' in result: response = HttpResponse("Your entry can be found here: "+result['build_url']) else: response = HttpResponse(result['error']) - if result.has_key('error'): + if 'error' in result: response.status_code=500 else: if return_json: @@ -123,7 +125,7 @@ def search(request, mode=results_mode.LATEST, **kwargs): items = BuildFailure.objects.all() - if request.GET.has_key("limit"): + if "limit" in request.GET: try: n_limit = int(request.GET['limit']) if n_limit > 0: @@ -200,14 +202,14 @@ def search(request, mode=results_mode.LATEST, **kwargs): ], } - if request.GET.has_key("filter") and request.GET.has_key("type"): + if "filter" in request.GET and "type" in request.GET: items = apply_filter(context, items, request.GET['type'], request.GET['filter']) if mode == results_mode.SPECIAL_SUBMITTER and hasattr(settings,"SPECIAL_SUBMITTER"): #Special submitter mode see settings.py to enable name = settings.SPECIAL_SUBMITTER['name'] - items = items.filter(BUILD__NAME__istartswith=name) + items = items.filter(BUILD__NAME__icontains=name) - elif mode == results_mode.SEARCH and request.GET.has_key("query"): + elif mode == results_mode.SEARCH and "query" in request.GET: query = request.GET["query"] items = items.filter( @@ -253,14 +255,25 @@ def search(request, mode=results_mode.LATEST, **kwargs): items = items.order_by() return render(request, "latest-errors.html", context) - def details(request, fail_id): try: - build_failure = BuildFailure.objects.get(id=fail_id) + build_failure = BuildFailure.objects.get(id=fail_id) except ObjectDoesNotExist: - build_failure = None - - context = {'detail' : build_failure, 'error_types' : ErrorType } + build_failure = None + if build_failure: + try: + referer = urlparse(request.META['HTTP_REFERER']) + referer_hostname = referer.hostname + if referer.port: + referer_hostname += ":" + str(referer.port) + if referer_hostname != request.get_host(): + build_failure.REFERER = 'OTHER' + except KeyError: + # There is no referer + build_failure.REFERER = 'NO_REFERER' + build_failure.save() + + context = {'detail' : build_failure, 'error_types' : ErrorType, 'bugzilla_url' : settings.BUGZILLA_URL } return render(request, "error-details.html", context) @@ -48,7 +48,7 @@ The latest version can be checked out by git cloning: git://git.yoctoproject.org/error-report-web Contributions are welcome. Please send patches / pull requests to -yocto@yoctoproject.org with '[error-report-web]' in the subject. +yocto@lists.yoctoproject.org with '[error-report-web]' in the subject. To manage the size of your database there is a convenience command: @@ -1,4 +1,6 @@ #!/usr/bin/env python +# SPDX-License-Identifier: MIT + import os import sys diff --git a/project/settings.py b/project/settings.py index 3c6c87e..989b2c9 100644 --- a/project/settings.py +++ b/project/settings.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT +# # Django settings for error-reporting-tool project. # Based on settings.py from the Django project template # Copyright (c) Django Software Foundation and individual contributors. @@ -195,6 +197,8 @@ TEMPLATE_CONTEXT_PROCESSORS = ( AUTH_PROFILE_MODULE = 'registration.RegistrationProfile' +BUGZILLA_URL = 'https://bugzilla.yoctoproject.org' + ACCOUNT_ACTIVATION_DAYS = 2 EMAIL_HOST = 'localhost' DEFAULT_FROM_EMAIL = 'noreply@example.com' diff --git a/project/urls.py b/project/urls.py index 0e8f39c..c1ac55f 100644 --- a/project/urls.py +++ b/project/urls.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT +# # error-reporting-tool - URL definitions # # Copyright (C) 2013 Intel Corporation @@ -22,7 +24,7 @@ urlpatterns = patterns('', #url(r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: - #url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', include(admin.site.urls)), #url(r'^accounts/', include('registration.backends.default.urls')), url(r'^(?i)Errors/Latest/$', 'Post.views.search', { 'mode' : results_mode.LATEST }, name= "latest_errors"), url(r'^(?i)Errors/Latest/feed$', LatestEntriesFeed(), name="errors_feed"), diff --git a/project/wsgi.py b/project/wsgi.py index 7d4fc73..8d3ba66 100644 --- a/project/wsgi.py +++ b/project/wsgi.py @@ -1,3 +1,7 @@ +# +# SPDX-License-Identifier: MIT +# + """ WSGI config for errorsreport project. diff --git a/requirements.txt b/requirements.txt index 909d054..52633b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ Django<1.9 python-Levenshtein==0.12.0 +bleach
\ No newline at end of file diff --git a/templates/error-details.html b/templates/error-details.html index c30160d..35bf0aa 100644 --- a/templates/error-details.html +++ b/templates/error-details.html @@ -83,7 +83,7 @@ </dl> <div> - <a class="btn btn-block" target="_blank" href="https://bugzilla.yoctoproject.org/enter_bug.cgi?classification=__all" >Open a bug</a> + <a class="btn btn-block" target="_blank" href="{{bugzilla_url}}/enter_bug.cgi?classification=__all" >Open a bug</a> </div> </div> </div> diff --git a/templates/latest-errors.html b/templates/latest-errors.html index 87e30d8..b9f081e 100644 --- a/templates/latest-errors.html +++ b/templates/latest-errors.html @@ -131,7 +131,7 @@ <td class="submitted_on"> <a href="{{details_url}}">{{ build_fail.BUILD.DATE|date:"d/m/y H:i"}}</a></td> <td class="error_type"><a href="{{details_url}}">{{ build_fail.BUILD.get_ERROR_TYPE_display }}</a> - <a class="filter" href="#" data-filter="{{build_fail.BUILD.get_ERROR_TYPE_display}}" data-type="error_type"> + <a class="filter" href="#" data-filter="{{build_fail.BUILD.ERROR_TYPE}}" data-type="error_type"> <i class="icon-filter hover" title="Filter by {{build_fail.BUILD.get_ERROR_TYPE_display}}"></i> </a> </td> diff --git a/test-data/test-send-error.py b/test-data/test-send-error.py index 7070c18..1252855 100755 --- a/test-data/test-send-error.py +++ b/test-data/test-send-error.py @@ -1,5 +1,6 @@ #!/usr/bin/env python -# +# SPDX-License-Identifier: MIT + # test/example script for sending data to error-report-web import urllib2 |