prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  The /permissions endpoint is broken
  To reproduce just access https://kinto-ota.dev.mozaws.net/v1/permissions
  
  ```
    File "/home/ubuntu/venvs/kinto/local/lib/python2.7/site-packages/kinto/core/permission/re
  dis.py", line 103, in get_accessible_objects
      _, object_id, permission = key.decode('utf-8').split(':')
  ValueError: too many values to unpack
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `kinto/core/permission/redis.py`
  Content:
  ```
  1 from __future__ import absolute_import
  2 
  3 from collections import defaultdict
  4 
  5 from kinto.core.permission import PermissionBase
  6 from kinto.core.storage.redis import create_from_config, wrap_redis_error
  7 
  8 
  9 class Permission(PermissionBase):
  10     """Permission backend implementation using Redis.
  11 
  12     Enable in configuration::
  13 
  14         kinto.permission_backend = kinto.core.permission.redis
  15 
  16     *(Optional)* Instance location URI can be customized::
  17 
  18         kinto.permission_url = redis://localhost:6379/2
  19 
  20     A threaded connection pool is enabled by default::
  21 
  22         kinto.permission_pool_size = 50
  23 
  24     :noindex:
  25     """
  26 
  27     def __init__(self, client, *args, **kwargs):
  28         super(Permission, self).__init__(*args, **kwargs)
  29         self._client = client
  30 
  31     @property
  32     def settings(self):
  33         return dict(self._client.connection_pool.connection_kwargs)
  34 
  35     def initialize_schema(self):
  36         # Nothing to do.
  37         pass
  38 
  39     def _decode_set(self, results):
  40         return set([r.decode('utf-8') for r in results])
  41 
  42     @wrap_redis_error
  43     def flush(self):
  44         self._client.flushdb()
  45 
  46     @wrap_redis_error
  47     def add_user_principal(self, user_id, principal):
  48         user_key = 'user:%s' % user_id
  49         self._client.sadd(user_key, principal)
  50 
  51     @wrap_redis_error
  52     def remove_user_principal(self, user_id, principal):
  53         user_key = 'user:%s' % user_id
  54         self._client.srem(user_key, principal)
  55         if self._client.scard(user_key) == 0:
  56             self._client.delete(user_key)
  57 
  58     def remove_principal(self, principal):
  59         with self._client.pipeline() as pipe:
  60             user_keys = self._client.scan_iter(match='user:*')
  61             for user_key in user_keys:
  62                 pipe.srem(user_key, principal)
  63             pipe.execute()
  64 
  65     @wrap_redis_error
  66     def get_user_principals(self, user_id):
  67         user_key = 'user:%s' % user_id
  68         return self._decode_set(self._client.smembers(user_key))
  69 
  70     @wrap_redis_error
  71     def add_principal_to_ace(self, object_id, permission, principal):
  72         permission_key = 'permission:%s:%s' % (object_id, permission)
  73         self._client.sadd(permission_key, principal)
  74 
  75     @wrap_redis_error
  76     def remove_principal_from_ace(self, object_id, permission, principal):
  77         permission_key = 'permission:%s:%s' % (object_id, permission)
  78         self._client.srem(permission_key, principal)
  79         if self._client.scard(permission_key) == 0:
  80             self._client.delete(permission_key)
  81 
  82     @wrap_redis_error
  83     def get_object_permission_principals(self, object_id, permission):
  84         permission_key = 'permission:%s:%s' % (object_id, permission)
  85         members = self._client.smembers(permission_key)
  86         return self._decode_set(members)
  87 
  88     @wrap_redis_error
  89     def get_accessible_objects(self, principals, bound_permissions=None):
  90         principals = set(principals)
  91 
  92         if bound_permissions:
  93             keys = ['permission:%s:%s' % op for op in bound_permissions]
  94         else:
  95             keys = ['permission:*']
  96 
  97         perms_by_id = dict()
  98         for key_pattern in keys:
  99             matched = self._client.scan_iter(match=key_pattern)
  100             for key in matched:
  101                 authorized = self._decode_set(self._client.smembers(key))
  102                 if len(authorized & principals) > 0:
  103                     _, object_id, permission = key.decode('utf-8').split(':')
  104                     perms_by_id.setdefault(object_id, set()).add(permission)
  105 
  106         return perms_by_id
  107 
  108     @wrap_redis_error
  109     def get_authorized_principals(self, bound_permissions):
  110         keys = ['permission:%s:%s' % (o, p) for (o, p) in bound_permissions]
  111         if keys:
  112             return self._decode_set(self._client.sunion(*list(keys)))
  113         return set()
  114 
  115     @wrap_redis_error
  116     def get_objects_permissions(self, objects_ids, permissions=None):
  117         objects_perms = []
  118         for object_id in objects_ids:
  119             if permissions is not None:
  120                 keys = ['permission:%s:%s' % (object_id, permission)
  121                         for permission in permissions]
  122             else:
  123                 keys = [key.decode('utf-8') for key in self._client.scan_iter(
  124                     match='permission:%s:*' % object_id)]
  125 
  126             with self._client.pipeline() as pipe:
  127                 for permission_key in keys:
  128                     pipe.smembers(permission_key)
  129 
  130                 results = pipe.execute()
  131 
  132             permissions = defaultdict(set)
  133             for i, result in enumerate(results):
  134                 permission = keys[i].split(':', 2)[-1]
  135                 permissions[permission] = self._decode_set(result)
  136             objects_perms.append(permissions)
  137         return objects_perms
  138 
  139     @wrap_redis_error
  140     def replace_object_permissions(self, object_id, permissions):
  141         keys = ['permission:%s:%s' % (object_id, permission)
  142                 for permission in permissions]
  143         with self._client.pipeline() as pipe:
  144             for key in keys:
  145                 pipe.delete(key)
  146                 permission = key.split(':', 2)[-1]
  147                 principals = permissions[permission]
  148                 if len(principals) > 0:
  149                     pipe.sadd(key, *principals)
  150             pipe.execute()
  151 
  152     @wrap_redis_error
  153     def delete_object_permissions(self, *object_id_list):
  154         with self._client.pipeline() as pipe:
  155             for object_id in object_id_list:
  156                 keys = list(self._client.scan_iter(
  157                     match='permission:%s:*' % object_id))
  158                 if len(keys) > 0:
  159                     pipe.delete(*keys)
  160             pipe.execute()
  161 
  162 
  163 def load_from_config(config):
  164     client = create_from_config(config, prefix='permission_')
  165     return Permission(client)
  166
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/kinto/core/permission/redis.py b/kinto/core/permission/redis.py
  --- a/kinto/core/permission/redis.py
  +++ b/kinto/core/permission/redis.py
  @@ -100,8 +100,8 @@
               for key in matched:
                   authorized = self._decode_set(self._client.smembers(key))
                   if len(authorized & principals) > 0:
  -                    _, object_id, permission = key.decode('utf-8').split(':')
  -                    perms_by_id.setdefault(object_id, set()).add(permission)
  +                    _, obj_id, permission = key.decode('utf-8').split(':', 2)
  +                    perms_by_id.setdefault(obj_id, set()).add(permission)
   
           return perms_by_id
  
verification_info: {"golden_diff": "diff --git a/kinto/core/permission/redis.py b/kinto/core/permission/redis.py\n--- a/kinto/core/permission/redis.py\n+++ b/kinto/core/permission/redis.py\n@@ -100,8 +100,8 @@\n             for key in matched:\n                 authorized = self._decode_set(self._client.smembers(key))\n                 if len(authorized & principals) > 0:\n-                    _, object_id, permission = key.decode('utf-8').split(':')\n-                    perms_by_id.setdefault(object_id, set()).add(permission)\n+                    _, obj_id, permission = key.decode('utf-8').split(':', 2)\n+                    perms_by_id.setdefault(obj_id, set()).add(permission)\n \n         return perms_by_id\n", "issue": "The /permissions endpoint is broken\nTo reproduce just access https://kinto-ota.dev.mozaws.net/v1/permissions\n\n```\n  File \"/home/ubuntu/venvs/kinto/local/lib/python2.7/site-packages/kinto/core/permission/re\ndis.py\", line 103, in get_accessible_objects\n    _, object_id, permission = key.decode('utf-8').split(':')\nValueError: too many values to unpack\n```\n\n", "before_files": [{"content": "from __future__ import absolute_import\n\nfrom collections import defaultdict\n\nfrom kinto.core.permission import PermissionBase\nfrom kinto.core.storage.redis import create_from_config, wrap_redis_error\n\n\nclass Permission(PermissionBase):\n    \"\"\"Permission backend implementation using Redis.\n\n    Enable in configuration::\n\n        kinto.permission_backend = kinto.core.permission.redis\n\n    *(Optional)* Instance location URI can be customized::\n\n        kinto.permission_url = redis://localhost:6379/2\n\n    A threaded connection pool is enabled by default::\n\n        kinto.permission_pool_size = 50\n\n    :noindex:\n    \"\"\"\n\n    def __init__(self, client, *args, **kwargs):\n        super(Permission, self).__init__(*args, **kwargs)\n        self._client = client\n\n    @property\n    def settings(self):\n        return dict(self._client.connection_pool.connection_kwargs)\n\n    def initialize_schema(self):\n        # Nothing to do.\n        pass\n\n    def _decode_set(self, results):\n        return set([r.decode('utf-8') for r in results])\n\n    @wrap_redis_error\n    def flush(self):\n        self._client.flushdb()\n\n    @wrap_redis_error\n    def add_user_principal(self, user_id, principal):\n        user_key = 'user:%s' % user_id\n        self._client.sadd(user_key, principal)\n\n    @wrap_redis_error\n    def remove_user_principal(self, user_id, principal):\n        user_key = 'user:%s' % user_id\n        self._client.srem(user_key, principal)\n        if self._client.scard(user_key) == 0:\n            self._client.delete(user_key)\n\n    def remove_principal(self, principal):\n        with self._client.pipeline() as pipe:\n            user_keys = self._client.scan_iter(match='user:*')\n            for user_key in user_keys:\n                pipe.srem(user_key, principal)\n            pipe.execute()\n\n    @wrap_redis_error\n    def get_user_principals(self, user_id):\n        user_key = 'user:%s' % user_id\n        return self._decode_set(self._client.smembers(user_key))\n\n    @wrap_redis_error\n    def add_principal_to_ace(self, object_id, permission, principal):\n        permission_key = 'permission:%s:%s' % (object_id, permission)\n        self._client.sadd(permission_key, principal)\n\n    @wrap_redis_error\n    def remove_principal_from_ace(self, object_id, permission, principal):\n        permission_key = 'permission:%s:%s' % (object_id, permission)\n        self._client.srem(permission_key, principal)\n        if self._client.scard(permission_key) == 0:\n            self._client.delete(permission_key)\n\n    @wrap_redis_error\n    def get_object_permission_principals(self, object_id, permission):\n        permission_key = 'permission:%s:%s' % (object_id, permission)\n        members = self._client.smembers(permission_key)\n        return self._decode_set(members)\n\n    @wrap_redis_error\n    def get_accessible_objects(self, principals, bound_permissions=None):\n        principals = set(principals)\n\n        if bound_permissions:\n            keys = ['permission:%s:%s' % op for op in bound_permissions]\n        else:\n            keys = ['permission:*']\n\n        perms_by_id = dict()\n        for key_pattern in keys:\n            matched = self._client.scan_iter(match=key_pattern)\n            for key in matched:\n                authorized = self._decode_set(self._client.smembers(key))\n                if len(authorized & principals) > 0:\n                    _, object_id, permission = key.decode('utf-8').split(':')\n                    perms_by_id.setdefault(object_id, set()).add(permission)\n\n        return perms_by_id\n\n    @wrap_redis_error\n    def get_authorized_principals(self, bound_permissions):\n        keys = ['permission:%s:%s' % (o, p) for (o, p) in bound_permissions]\n        if keys:\n            return self._decode_set(self._client.sunion(*list(keys)))\n        return set()\n\n    @wrap_redis_error\n    def get_objects_permissions(self, objects_ids, permissions=None):\n        objects_perms = []\n        for object_id in objects_ids:\n            if permissions is not None:\n                keys = ['permission:%s:%s' % (object_id, permission)\n                        for permission in permissions]\n            else:\n                keys = [key.decode('utf-8') for key in self._client.scan_iter(\n                    match='permission:%s:*' % object_id)]\n\n            with self._client.pipeline() as pipe:\n                for permission_key in keys:\n                    pipe.smembers(permission_key)\n\n                results = pipe.execute()\n\n            permissions = defaultdict(set)\n            for i, result in enumerate(results):\n                permission = keys[i].split(':', 2)[-1]\n                permissions[permission] = self._decode_set(result)\n            objects_perms.append(permissions)\n        return objects_perms\n\n    @wrap_redis_error\n    def replace_object_permissions(self, object_id, permissions):\n        keys = ['permission:%s:%s' % (object_id, permission)\n                for permission in permissions]\n        with self._client.pipeline() as pipe:\n            for key in keys:\n                pipe.delete(key)\n                permission = key.split(':', 2)[-1]\n                principals = permissions[permission]\n                if len(principals) > 0:\n                    pipe.sadd(key, *principals)\n            pipe.execute()\n\n    @wrap_redis_error\n    def delete_object_permissions(self, *object_id_list):\n        with self._client.pipeline() as pipe:\n            for object_id in object_id_list:\n                keys = list(self._client.scan_iter(\n                    match='permission:%s:*' % object_id))\n                if len(keys) > 0:\n                    pipe.delete(*keys)\n            pipe.execute()\n\n\ndef load_from_config(config):\n    client = create_from_config(config, prefix='permission_')\n    return Permission(client)\n", "path": "kinto/core/permission/redis.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nfrom collections import defaultdict\n\nfrom kinto.core.permission import PermissionBase\nfrom kinto.core.storage.redis import create_from_config, wrap_redis_error\n\n\nclass Permission(PermissionBase):\n    \"\"\"Permission backend implementation using Redis.\n\n    Enable in configuration::\n\n        kinto.permission_backend = kinto.core.permission.redis\n\n    *(Optional)* Instance location URI can be customized::\n\n        kinto.permission_url = redis://localhost:6379/2\n\n    A threaded connection pool is enabled by default::\n\n        kinto.permission_pool_size = 50\n\n    :noindex:\n    \"\"\"\n\n    def __init__(self, client, *args, **kwargs):\n        super(Permission, self).__init__(*args, **kwargs)\n        self._client = client\n\n    @property\n    def settings(self):\n        return dict(self._client.connection_pool.connection_kwargs)\n\n    def initialize_schema(self):\n        # Nothing to do.\n        pass\n\n    def _decode_set(self, results):\n        return set([r.decode('utf-8') for r in results])\n\n    @wrap_redis_error\n    def flush(self):\n        self._client.flushdb()\n\n    @wrap_redis_error\n    def add_user_principal(self, user_id, principal):\n        user_key = 'user:%s' % user_id\n        self._client.sadd(user_key, principal)\n\n    @wrap_redis_error\n    def remove_user_principal(self, user_id, principal):\n        user_key = 'user:%s' % user_id\n        self._client.srem(user_key, principal)\n        if self._client.scard(user_key) == 0:\n            self._client.delete(user_key)\n\n    def remove_principal(self, principal):\n        with self._client.pipeline() as pipe:\n            user_keys = self._client.scan_iter(match='user:*')\n            for user_key in user_keys:\n                pipe.srem(user_key, principal)\n            pipe.execute()\n\n    @wrap_redis_error\n    def get_user_principals(self, user_id):\n        user_key = 'user:%s' % user_id\n        return self._decode_set(self._client.smembers(user_key))\n\n    @wrap_redis_error\n    def add_principal_to_ace(self, object_id, permission, principal):\n        permission_key = 'permission:%s:%s' % (object_id, permission)\n        self._client.sadd(permission_key, principal)\n\n    @wrap_redis_error\n    def remove_principal_from_ace(self, object_id, permission, principal):\n        permission_key = 'permission:%s:%s' % (object_id, permission)\n        self._client.srem(permission_key, principal)\n        if self._client.scard(permission_key) == 0:\n            self._client.delete(permission_key)\n\n    @wrap_redis_error\n    def get_object_permission_principals(self, object_id, permission):\n        permission_key = 'permission:%s:%s' % (object_id, permission)\n        members = self._client.smembers(permission_key)\n        return self._decode_set(members)\n\n    @wrap_redis_error\n    def get_accessible_objects(self, principals, bound_permissions=None):\n        principals = set(principals)\n\n        if bound_permissions:\n            keys = ['permission:%s:%s' % op for op in bound_permissions]\n        else:\n            keys = ['permission:*']\n\n        perms_by_id = dict()\n        for key_pattern in keys:\n            matched = self._client.scan_iter(match=key_pattern)\n            for key in matched:\n                authorized = self._decode_set(self._client.smembers(key))\n                if len(authorized & principals) > 0:\n                    _, obj_id, permission = key.decode('utf-8').split(':', 2)\n                    perms_by_id.setdefault(obj_id, set()).add(permission)\n\n        return perms_by_id\n\n    @wrap_redis_error\n    def get_authorized_principals(self, bound_permissions):\n        keys = ['permission:%s:%s' % (o, p) for (o, p) in bound_permissions]\n        if keys:\n            return self._decode_set(self._client.sunion(*list(keys)))\n        return set()\n\n    @wrap_redis_error\n    def get_objects_permissions(self, objects_ids, permissions=None):\n        objects_perms = []\n        for object_id in objects_ids:\n            if permissions is not None:\n                keys = ['permission:%s:%s' % (object_id, permission)\n                        for permission in permissions]\n            else:\n                keys = [key.decode('utf-8') for key in self._client.scan_iter(\n                    match='permission:%s:*' % object_id)]\n\n            with self._client.pipeline() as pipe:\n                for permission_key in keys:\n                    pipe.smembers(permission_key)\n\n                results = pipe.execute()\n\n            permissions = defaultdict(set)\n            for i, result in enumerate(results):\n                permission = keys[i].split(':', 2)[-1]\n                permissions[permission] = self._decode_set(result)\n            objects_perms.append(permissions)\n        return objects_perms\n\n    @wrap_redis_error\n    def replace_object_permissions(self, object_id, permissions):\n        keys = ['permission:%s:%s' % (object_id, permission)\n                for permission in permissions]\n        with self._client.pipeline() as pipe:\n            for key in keys:\n                pipe.delete(key)\n                permission = key.split(':', 2)[-1]\n                principals = permissions[permission]\n                if len(principals) > 0:\n                    pipe.sadd(key, *principals)\n            pipe.execute()\n\n    @wrap_redis_error\n    def delete_object_permissions(self, *object_id_list):\n        with self._client.pipeline() as pipe:\n            for object_id in object_id_list:\n                keys = list(self._client.scan_iter(\n                    match='permission:%s:*' % object_id))\n                if len(keys) > 0:\n                    pipe.delete(*keys)\n            pipe.execute()\n\n\ndef load_from_config(config):\n    client = create_from_config(config, prefix='permission_')\n    return Permission(client)\n", "path": "kinto/core/permission/redis.py"}]}