[Patchew-devel] [PATCH 3/3] Add Infra for PUT

Shubham Jain shubhamjain7495 at gmail.com
Wed Aug 8 11:12:26 UTC 2018


Added authentications and validation of the data for PUT of the result
---
 api/rest.py           | 47 +++++++++++++++++++++++++++++++++++++++++++----
 tests/test_git.py     | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_testing.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+), 4 deletions(-)

diff --git a/api/rest.py b/api/rest.py
index 21f4609..dd3a947 100644
--- a/api/rest.py
+++ b/api/rest.py
@@ -26,6 +26,9 @@ import rest_framework
 from mbox import addr_db_to_rest, MboxMessage
 from rest_framework.parsers import JSONParser, BaseParser
 from rest_framework.authentication import SessionAuthentication
+from rest_framework.exceptions import ValidationError
+import re
+import mod
 
 class CsrfExemptSessionAuthentication(SessionAuthentication):
 
@@ -65,8 +68,9 @@ class PatchewPermission(permissions.BasePermission):
 
     def has_generic_permission(self, request, view):
         return (request.method in permissions.SAFE_METHODS) or \
-               self.is_superuser(request) or \
-               self.has_group_permission(request, view)
+                self.is_superuser(request) or \
+                self.has_group_permission(request, view) or \
+                self.has_result_group_permission(request, view) 
 
     def has_permission(self, request, view):
         return self.has_generic_permission(request, view) or \
@@ -78,7 +82,22 @@ class PatchewPermission(permissions.BasePermission):
                (isinstance(obj, Message) and \
                 self.has_message_permission(request, view, obj)) or \
                (isinstance(obj, Project) and \
-                self.has_project_permission(request, view, obj))
+                self.has_project_permission(request, view, obj)) or \
+               (isinstance(obj, Result) and \
+                self.has_result_permission(request, view, obj))
+
+    def has_result_group_permission(self, request, view):
+        name = request.resolver_match.kwargs.get('name')
+        if name:
+            found = re.match("^[^.]*", name)
+            module = mod.get_module(found.group(0)) if found else None
+            for grp in request.user.groups.all():
+                if grp.name in module.allowed_groups:
+                    return True
+        return False
+
+    def has_result_permission(self, request, view, result_obj):
+        return self.has_object_permission(request, view, result_obj.project)
 
 class ImportPermission(PatchewPermission):
     allowed_groups = ('importers',)
@@ -475,6 +494,14 @@ class ResultSerializer(serializers.ModelSerializer):
         request = self.context['request']
         return obj.get_log_url(request)
 
+    def validate(self, data):
+        found = re.match("^[^.]*", self.instance.name)
+        module = mod.get_module(found.group(0)) if found else None
+        is_valid = module.result_data_serializer_class(data=data['data']).is_valid(raise_exception=True)
+        if found is None and not is_valid:
+            raise ValidationError("Invalid")
+        return data
+
 class ResultSerializerFull(ResultSerializer):
     class Meta:
         model = Result
@@ -484,18 +511,30 @@ class ResultSerializerFull(ResultSerializer):
     log = CharField(required=False)
 
 class ResultsViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin,
-                         viewsets.GenericViewSet):
+                     mixins.UpdateModelMixin, viewsets.GenericViewSet):
     lookup_field = 'name'
     lookup_value_regex = '[^/]+'
     filter_backends = (filters.OrderingFilter,)
     ordering_fields = ('name',)
     ordering = ('name',)
+    authentication_classes = (CsrfExemptSessionAuthentication, )
+    permission_classes = (PatchewPermission, )
 
     def get_serializer_class(self, *args, **kwargs):
         if self.lookup_field in self.kwargs:
             return ResultSerializerFull
         return ResultSerializer
 
+    @property
+    def project(self):
+        if hasattr(self, '__project'):
+            return self.__project
+        try:
+            self.__project = Project.objects.get(id=self.kwargs['projects_pk'])
+        except:
+            self.__project = None
+        return self.__project
+
 class ProjectResultsViewSet(ResultsViewSet):
     def get_queryset(self):
         return ProjectResult.objects.filter(project=self.kwargs['projects_pk'])
diff --git a/tests/test_git.py b/tests/test_git.py
index b2802d5..e22a498 100755
--- a/tests/test_git.py
+++ b/tests/test_git.py
@@ -15,6 +15,7 @@ from tests.patchewtest import PatchewTestCase, main
 import shutil
 import subprocess
 from api.models import Message, Result
+import json
 
 class GitTest(PatchewTestCase):
 
@@ -101,6 +102,52 @@ class GitTest(PatchewTestCase):
         self.assertEqual(resp.data['log_url'], None)
         self.assertEqual(resp.data['log'], None)
 
+    def test_auth_importer(self):
+        self.cli_import("0013-foo-patch.mbox.gz")
+        MESSAGE_ID = '20160628014747.20971-1-famz at redhat.com'
+        test = self.create_user(username="test", password="userpass", groups=['importers'])
+        self.api_client.login(username="test", password="userpass")
+        data = {
+                "name": "testing.a",
+                "status": "failure",
+                "data": {"tag": "test_tag", "url": "test_url", "repo": "test_repo", "base": "test_base"},
+                "log": "test",
+                "last_update": '2018-08-07T03:51:13.262213'}
+
+        resp= self.api_client.put('%sseries/%s/results/git/' % (self.PROJECT_BASE, MESSAGE_ID), data=json.dumps(data), content_type='application/json')
+        self.assertEquals(resp.status_code, 200)
+        self.assertEquals(resp.data['log'], "test")
+
+    def test_data_validation(self):
+        self.cli_import("0013-foo-patch.mbox.gz")
+        MESSAGE_ID = '20160628014747.20971-1-famz at redhat.com'
+        test = self.create_user(username="test", password="userpass", groups=['importers'])
+        self.api_client.login(username="test", password="userpass")
+        data = {
+                "name": "testing.a",
+                "status": "failure",
+                "data": "",
+                "log": "test",
+                "last_update": '2018-08-07T03:51:13.262213'}
+
+        resp= self.api_client.put('%sseries/%s/results/git/' % (self.PROJECT_BASE, MESSAGE_ID), data=json.dumps(data), content_type='application/json')
+        self.assertEquals(resp.status_code, 400)
+
+    def test_auth_without_permission(self):
+        self.cli_import("0013-foo-patch.mbox.gz")
+        MESSAGE_ID = '20160628014747.20971-1-famz at redhat.com'
+        test = self.create_user(username="test", password="userpass")
+        self.api_client.login(username="test", password="userpass")
+        data = {
+                "name": "testing.a",
+                "status": "failure",
+                "data": {"tag": "test_tag", "url": "test_url", "repo": "test_repo", "base": "test_base"},
+                "log": "test",
+                "last_update": '2018-08-07T03:51:13.262213'}
+
+        resp= self.api_client.put('%sseries/%s/results/git/' % (self.PROJECT_BASE, MESSAGE_ID), data=json.dumps(data), content_type='application/json')
+        self.assertEquals(resp.status_code, 403)
+
     def test_rest_git_base(self):
         self.cli_import("0013-foo-patch.mbox.gz")
         self.do_apply()
diff --git a/tests/test_testing.py b/tests/test_testing.py
index 7ca4625..85b16a6 100755
--- a/tests/test_testing.py
+++ b/tests/test_testing.py
@@ -15,6 +15,7 @@ import subprocess
 sys.path.append(os.path.dirname(__file__))
 from tests.patchewtest import PatchewTestCase, main
 from api.models import Message, Result
+import json
 
 def create_test(project, name):
     prefix = "testing.tests." + name + "."
@@ -214,6 +215,7 @@ class TesterTest(PatchewTestCase):
 
         self.p1 = self.add_project("QEMU", "qemu-devel at nongnu.org")
         create_test(self.p1, "a")
+        self.PROJECT_BASE = '%sprojects/%d/' % (self.REST_BASE, self.p1.id)
         self.p2 = self.add_project("UMEQ", "qemu-devel at nongnu.org")
         create_test(self.p2, "b")
 
@@ -248,6 +250,51 @@ class TesterTest(PatchewTestCase):
                                        cwd=self.repo).decode()
         p.set_property("git.head", head)
 
+    def test_auth_tester(self):
+        resp = self.api_client.get('%sresults/' % (
+                                       self.PROJECT_BASE))
+        test = self.create_user(username="test", password="userpass", groups=['testers'])
+        self.api_client.login(username="test", password="userpass")
+        data = {
+                "name": "testing.a",
+                "status": "failure",
+                "data": {"head": "test_head", "tester": "test_tester", "is_timeout": False},
+                "log": "test",
+                "last_update": '2018-08-07T03:51:13.262213'}
+
+        resp1= self.api_client.put(resp.data['results'][0]['resource_uri'],data=json.dumps(data), content_type='application/json')
+        self.assertEquals(resp1.status_code, 200)
+        self.assertEquals(resp1.data['log'], "test")
+
+    def test_data_validation(self):
+        resp = self.api_client.get('%sresults/' % (
+                                       self.PROJECT_BASE))
+        test = self.create_user(username="test", password="userpass", groups=['testers'])
+        self.api_client.login(username="test", password="userpass")
+        data = {
+                "name":"testing.a",
+                "status":"failure",
+                "data":"",
+                "log":"test",
+                "last_update": '2018-08-07T03:51:13.262213'}
+        resp1= self.api_client.put(resp.data['results'][0]['resource_uri'],data=json.dumps(data), content_type='application/json')
+        self.assertEquals(resp1.status_code, 400)
+
+    def test_auth_without_permission(self):
+        resp = self.api_client.get('%sresults/' % (
+                                       self.PROJECT_BASE))
+        test = self.create_user(username="test", password="userpass")
+        self.api_client.login(username="test", password="userpass")
+        data = {
+                "name": "testing.a",
+                "status": "failure",
+                "data": {"head": "test_head", "tester": "test_tester", "is_timeout": False},
+                "log": "test",
+                "last_update": '2018-08-07T03:51:13.262213'}
+
+        resp1= self.api_client.put(resp.data['results'][0]['resource_uri'],data=json.dumps(data), content_type='application/json')
+        self.assertEquals(resp1.status_code, 403)
+
     def test_tester(self):
         self.cli_login()
         out, err = self.check_cli(["tester", "-p", "QEMU,UMEQ",
-- 
2.15.1 (Apple Git-101)




More information about the Patchew-devel mailing list