Repository: Kinto/kinto

Issue:
JSON validation crash on missing array minItems property
```
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/pyramid/viewderivers.py", line 147, in _requestonly_view
    response = view(request)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/cornice/service.py", line 491, in wrapper
    response = view_()
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/kinto/core/resource/__init__.py", line 460, in put
    new_record = self.process_record(post_record, old=existing)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/kinto/views/records.py", line 66, in process_record
    jsonschema.validate(stripped, schema)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/jsonschema/validators.py", line 540, in validate
    cls.check_schema(schema)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/jsonschema/validators.py", line 83, in check_schema
    raise SchemaError.create_from(error)
jsonschema.exceptions.SchemaError: [] is too short

Failed validating 'minItems' in schema['properties']['required']:
    {'items': {'type': 'string'},
     'minItems': 1,
     'type': 'array',
     'uniqueItems': True}

On instance['required']:
    []
```
JSON validation crash on missing array minItems property
```
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/pyramid/viewderivers.py", line 147, in _requestonly_view
    response = view(request)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/cornice/service.py", line 491, in wrapper
    response = view_()
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/kinto/core/resource/__init__.py", line 460, in put
    new_record = self.process_record(post_record, old=existing)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/kinto/views/records.py", line 66, in process_record
    jsonschema.validate(stripped, schema)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/jsonschema/validators.py", line 540, in validate
    cls.check_schema(schema)
  File "/home/ubuntu/venvs/kinto/local/lib/python3.5/site-packages/jsonschema/validators.py", line 83, in check_schema
    raise SchemaError.create_from(error)
jsonschema.exceptions.SchemaError: [] is too short

Failed validating 'minItems' in schema['properties']['required']:
    {'items': {'type': 'string'},
     'minItems': 1,
     'type': 'array',
     'uniqueItems': True}

On instance['required']:
    []
```


Discussion:
strange I could reproduce locally with build-hub stuff but not from tests with the exact same data:

```diff
diff --git a/tests/test_views_collections_schema.py b/tests/test_views_collections_schema.py
index c88c5a8f..a66a4615 100644
--- a/tests/test_views_collections_schema.py
+++ b/tests/test_views_collections_schema.py
@@ -180,6 +180,169 @@ class RecordsValidationTest(BaseWebTestWithSchema, unittest.TestCase):
         self.assertEqual(len(resp.json['data']), 1)
 
 
+class RequiredProperties(BaseWebTestWithSchema, unittest.TestCase):
+
+    def setUp(self):
+        super().setUp()
+        schema = {
+            "additionalProperties": False,
+            "description": "Mozilla software releases.",
+            "properties": {
+                "build": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "date": {
+                            "description": "i.e: 2017-04-13T21:49:00Z",
+                            "format": "date-time",
+                            "title": "Build date",
+                            "type": "string"
+                        },
+                        "id": {
+                            "description": "Build ID",
+                            "title": "Build ID",
+                            "type": "string"
+                        }
+                    },
+                    "type": "object"
+                },
+                "download": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "date": {
+                            "description": "Date of the archive",
+                            "format": "date-time",
+                            "title": "Date",
+                            "type": "string"
+                        },
+                        "mimetype": {
+                            "title": "Archive's mimetype",
+                            "type": "string"
+                        },
+                        "size": {
+                            "description": "Size of the archive in bytes",
+                            "title": "Size",
+                            "type": "integer"
+                        },
+                        "url": {
+                            "description": "URL of the archive",
+                            "title": "URL",
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "url",
+                        "mimetype",
+                        "size",
+                        "date"
+                    ],
+                    "type": "object"
+                },
+                "source": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "product": {
+                            "description": "Product name",
+                            "title": "Product",
+                            "type": "string"
+                        },
+                        "repository": {
+                            "title": "Repository",
+                            "type": "string"
+                        },
+                        "revision": {
+                            "title": "Revision number in the tree",
+                            "type": "string"
+                        },
+                        "tree": {
+                            "description": "i.e mozilla-central",
+                            "title": "Tree",
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "product"
+                    ],
+                    "type": "object"
+                },
+                "systemaddons": {
+                    "items": {
+                        "additionalProperties": False,
+                        "properties": {
+                            "builtin": {
+                                "description": "Version in release",
+                                "title": "Built in version",
+                                "type": "string"
+                            },
+                            "id": {
+                                "title": "ID",
+                                "type": "string"
+                            },
+                            "updated": {
+                                "description": "Last update version",
+                                "title": "Updated version",
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "id",
+                            "builtin",
+                            "updated"
+                        ],
+                        "type": "object"
+                    },
+                    "title": "Systemaddons",
+                    "type": "array"
+                },
+                "target": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "channel": {
+                            "title": "Update channel",
+                            "type": "string"
+                        },
+                        "locale": {
+                            "title": "Locale",
+                            "type": "string"
+                        },
+                        "platform": {
+                            "description": "Operating system and Architecture",
+                            "title": "Platform",
+                            "type": "string"
+                        },
+                        "version": {
+                            "title": "Version",
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "platform",
+                        "locale",
+                        "version",
+                        "channel"
+                    ],
+                    "type": "object"
+                }
+            },
+            "required": [
+                "id",
+                "source",
+                "download",
+                "target"
+            ],
+            "title": "Release",
+            "type": "object"
+        }
+        resp = self.app.put_json(COLLECTION_URL,
+                                 {'data': {'schema': schema}},
+                                 headers=self.headers)
+
+    def test_reproduce_1243(self):
+        record  = {'download': {'size': 35420548, 'url': 'https://archive.mozilla.org/pub/mobile/nightly/2017/05/2017-05-02-10-02-40-mozilla-central-android-api-15-l10n/fennec-55.0a1.gl.android-arm.apk', 'date': '2017-05-02T12:01:11Z', 'mimetype': 'application/vnd.android.package-archive'}, 'id': 'fennec_2017-05-02-10-02-40_55-0a1_android-arm_gl', 'target': {'version': '55.0a1', 'platform': 'android-arm', 'locale': 'gl', 'channel': 'nightly'}, 'source': {'product': 'fennec'}}
+        self.app.put_json(COLLECTION_URL + "/records/" + record["id"],
+                          {'data': record},
+                          headers=self.headers)
+
+
 class ExtraPropertiesValidationTest(BaseWebTestWithSchema, unittest.TestCase):
     def setUp(self):
         super().setUp()
```
strange I could reproduce locally with build-hub stuff but not from tests with the exact same data:

```diff
diff --git a/tests/test_views_collections_schema.py b/tests/test_views_collections_schema.py
index c88c5a8f..a66a4615 100644
--- a/tests/test_views_collections_schema.py
+++ b/tests/test_views_collections_schema.py
@@ -180,6 +180,169 @@ class RecordsValidationTest(BaseWebTestWithSchema, unittest.TestCase):
         self.assertEqual(len(resp.json['data']), 1)
 
 
+class RequiredProperties(BaseWebTestWithSchema, unittest.TestCase):
+
+    def setUp(self):
+        super().setUp()
+        schema = {
+            "additionalProperties": False,
+            "description": "Mozilla software releases.",
+            "properties": {
+                "build": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "date": {
+                            "description": "i.e: 2017-04-13T21:49:00Z",
+                            "format": "date-time",
+                            "title": "Build date",
+                            "type": "string"
+                        },
+                        "id": {
+                            "description": "Build ID",
+                            "title": "Build ID",
+                            "type": "string"
+                        }
+                    },
+                    "type": "object"
+                },
+                "download": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "date": {
+                            "description": "Date of the archive",
+                            "format": "date-time",
+                            "title": "Date",
+                            "type": "string"
+                        },
+                        "mimetype": {
+                            "title": "Archive's mimetype",
+                            "type": "string"
+                        },
+                        "size": {
+                            "description": "Size of the archive in bytes",
+                            "title": "Size",
+                            "type": "integer"
+                        },
+                        "url": {
+                            "description": "URL of the archive",
+                            "title": "URL",
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "url",
+                        "mimetype",
+                        "size",
+                        "date"
+                    ],
+                    "type": "object"
+                },
+                "source": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "product": {
+                            "description": "Product name",
+                            "title": "Product",
+                            "type": "string"
+                        },
+                        "repository": {
+                            "title": "Repository",
+                            "type": "string"
+                        },
+                        "revision": {
+                            "title": "Revision number in the tree",
+                            "type": "string"
+                        },
+                        "tree": {
+                            "description": "i.e mozilla-central",
+                            "title": "Tree",
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "product"
+                    ],
+                    "type": "object"
+                },
+                "systemaddons": {
+                    "items": {
+                        "additionalProperties": False,
+                        "properties": {
+                            "builtin": {
+                                "description": "Version in release",
+                                "title": "Built in version",
+                                "type": "string"
+                            },
+                            "id": {
+                                "title": "ID",
+                                "type": "string"
+                            },
+                            "updated": {
+                                "description": "Last update version",
+                                "title": "Updated version",
+                                "type": "string"
+                            }
+                        },
+                        "required": [
+                            "id",
+                            "builtin",
+                            "updated"
+                        ],
+                        "type": "object"
+                    },
+                    "title": "Systemaddons",
+                    "type": "array"
+                },
+                "target": {
+                    "additionalProperties": False,
+                    "properties": {
+                        "channel": {
+                            "title": "Update channel",
+                            "type": "string"
+                        },
+                        "locale": {
+                            "title": "Locale",
+                            "type": "string"
+                        },
+                        "platform": {
+                            "description": "Operating system and Architecture",
+                            "title": "Platform",
+                            "type": "string"
+                        },
+                        "version": {
+                            "title": "Version",
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "platform",
+                        "locale",
+                        "version",
+                        "channel"
+                    ],
+                    "type": "object"
+                }
+            },
+            "required": [
+                "id",
+                "source",
+                "download",
+                "target"
+            ],
+            "title": "Release",
+            "type": "object"
+        }
+        resp = self.app.put_json(COLLECTION_URL,
+                                 {'data': {'schema': schema}},
+                                 headers=self.headers)
+
+    def test_reproduce_1243(self):
+        record  = {'download': {'size': 35420548, 'url': 'https://archive.mozilla.org/pub/mobile/nightly/2017/05/2017-05-02-10-02-40-mozilla-central-android-api-15-l10n/fennec-55.0a1.gl.android-arm.apk', 'date': '2017-05-02T12:01:11Z', 'mimetype': 'application/vnd.android.package-archive'}, 'id': 'fennec_2017-05-02-10-02-40_55-0a1_android-arm_gl', 'target': {'version': '55.0a1', 'platform': 'android-arm', 'locale': 'gl', 'channel': 'nightly'}, 'source': {'product': 'fennec'}}
+        self.app.put_json(COLLECTION_URL + "/records/" + record["id"],
+                          {'data': record},
+                          headers=self.headers)
+
+
 class ExtraPropertiesValidationTest(BaseWebTestWithSchema, unittest.TestCase):
     def setUp(self):
         super().setUp()
```

Resolving patch:
diff --git a/kinto/views/records.py b/kinto/views/records.py
--- a/kinto/views/records.py
+++ b/kinto/views/records.py
@@ -65,10 +65,10 @@ def process_record(self, new, old=None):
             stripped.pop(self.schema_field, None)
             jsonschema.validate(stripped, schema)
         except jsonschema_exceptions.ValidationError as e:
-            try:
-                field = e.path.pop() if e.path else e.validator_value.pop()
-            except AttributeError:
-                field = None
+            if e.validator_value:
+                field = e.validator_value[-1]
+            else:
+                field = e.schema_path[-1]
             raise_invalid(self.request, name=field, description=e.message)
 
         new[self.schema_field] = collection_timestamp


Test patch:
diff --git a/tests/test_views_collections_schema.py b/tests/test_views_collections_schema.py
--- a/tests/test_views_collections_schema.py
+++ b/tests/test_views_collections_schema.py
@@ -90,6 +90,25 @@ def test_schema_should_be_json_schema(self):
         error_msg = "'Washmachine' is not valid under any of the given schemas"
         self.assertIn(error_msg, resp.json['message'])
 
+    def test_extra_unknown_required_property(self):
+        schema = {**SCHEMA, "required": ["unknown"]}
+        self.app.put_json(COLLECTION_URL,
+                          {'data': {'schema': schema}},
+                          headers=self.headers)
+
+        record = {'title': 'bug 1243'}
+        r = self.app.post_json(RECORDS_URL,
+                               {'data': record},
+                               headers=self.headers,
+                               status=400)
+        self.assertEqual("'unknown' is a required property", r.json["message"])
+
+        # With bug Kinto/kinto#1243, the second call would crash.
+        self.app.post_json(RECORDS_URL,
+                           {'data': record},
+                           headers=self.headers,
+                           status=400)
+
 
 class RecordsValidationTest(BaseWebTestWithSchema, unittest.TestCase):
     def setUp(self):