-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
added documentation for new rule #15
Changes from all commits
0221258
e7cc275
e9203aa
3ab8622
948bc88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
[REQ-E004] - Changing additionalProperties to False for a request parameter | ||
================================================================================================================ | ||
|
||
Rationale | ||
--------- | ||
If the object is defined with additionalProperties set to False then the object will not allow presence of properties not defined on the properties section of the object definition. Changing additionalProperties from True to False makes objects sent from a client, that contain additional properties and were permitted by the "old" Swagger specs, to the server be considered invalid by the backend. | ||
|
||
Mitigation | ||
---------- | ||
A possible mitigation could be to not set additionalProperties to False in the object schema. | ||
|
||
Example | ||
------- | ||
Old Swagger Specs | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
.. literalinclude:: examples/REQ-E004/old.yaml | ||
:name: Old Swagger Spec | ||
:language: yaml | ||
:emphasize-lines: 17-18 | ||
:linenos: | ||
|
||
New Swagger Specs | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
.. literalinclude:: examples/REQ-E004/new.yaml | ||
:name: New Swagger Spec | ||
:language: yaml | ||
:linenos: | ||
|
||
|
||
Backward Incompatibility | ||
~~~~~~~~~~~~~~~~~~~~~~~~ | ||
The following snippet triggers the incompatibility error. | ||
|
||
.. literalinclude:: examples/REQ-E004/tester.py | ||
:language: py | ||
:linenos: | ||
|
||
**NOTE**: The code is taking advantage of `bravado <https://github.com/Yelp/bravado>`_ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
swagger: '2.0' | ||
info: | ||
title: Minimal Case of REQ-E004 Rule | ||
version: '1.0' | ||
paths: | ||
/endpoint: | ||
post: | ||
parameters: | ||
- in: body | ||
name: body | ||
required: true | ||
schema: | ||
additionalProperties: false | ||
properties: | ||
property_1: | ||
type: string | ||
property_2: | ||
type: string | ||
type: object | ||
responses: | ||
default: | ||
description: '' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
swagger: '2.0' | ||
info: | ||
title: Minimal Case of REQ-E004 Rule | ||
version: '1.0' | ||
paths: | ||
/endpoint: | ||
post: | ||
parameters: | ||
- in: body | ||
name: body | ||
required: true | ||
schema: | ||
additionalProperties: false | ||
properties: | ||
property_1: | ||
type: string | ||
property_2: | ||
type: string | ||
type: object | ||
responses: | ||
default: | ||
description: '' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
swagger: '2.0' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this file needed? Is it possible that you've added in the repo files that should not be committed? |
||
info: | ||
title: Minimal Case of REQ-E004 Rule | ||
version: '1.0' | ||
paths: | ||
/endpoint: | ||
post: | ||
parameters: | ||
- in: body | ||
name: body | ||
required: true | ||
schema: | ||
properties: | ||
property_1: | ||
type: string | ||
property_2: | ||
type: string | ||
type: object | ||
responses: | ||
default: | ||
description: '' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
swagger: '2.0' | ||
info: | ||
title: Minimal Case of REQ-E004 Rule | ||
version: '1.0' | ||
paths: | ||
/endpoint: | ||
post: | ||
parameters: | ||
- in: body | ||
name: body | ||
required: true | ||
schema: | ||
properties: | ||
property_1: | ||
type: string | ||
property_2: | ||
type: string | ||
type: object | ||
responses: | ||
default: | ||
description: '' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# -*- coding: utf-8 -*- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
from __future__ import absolute_import | ||
from __future__ import print_function | ||
from __future__ import unicode_literals | ||
|
||
from os.path import abspath | ||
|
||
from bravado.client import SwaggerClient | ||
from jsonschema import ValidationError | ||
from six.moves.urllib.parse import urljoin | ||
from six.moves.urllib.request import pathname2url | ||
|
||
old_client = SwaggerClient.from_url( | ||
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))), | ||
) | ||
new_client = SwaggerClient.from_url( | ||
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))), | ||
) | ||
|
||
object_to_send = {'property_1': 'v1', 'property_2': 'v2', 'property_3': 'v3'} | ||
|
||
print('Calling the post endpoint with the old client: Succeeded') | ||
old_client.endpoint.post_endpoint(body=object_to_send) | ||
|
||
print('Calling the post endpoint with the old client: Failed') | ||
try: | ||
new_client.endpoint.post_endpoint(body=object_to_send) | ||
raise RuntimeError('An error was expected') | ||
except ValidationError: | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import | ||
from __future__ import print_function | ||
from __future__ import unicode_literals | ||
|
||
from os.path import abspath | ||
|
||
from bravado.client import SwaggerClient | ||
from jsonschema import ValidationError | ||
from six.moves.urllib.parse import urljoin | ||
from six.moves.urllib.request import pathname2url | ||
|
||
old_client = SwaggerClient.from_url( | ||
spec_url=urljoin('file:', pathname2url(abspath('old.yaml'))), | ||
) | ||
new_client = SwaggerClient.from_url( | ||
spec_url=urljoin('file:', pathname2url(abspath('new.yaml'))), | ||
) | ||
|
||
object_to_send = {'property_1': 'v1', 'property_2': 'v2', 'property_3': 'v3'} | ||
|
||
print('Calling the post endpoint with the old client: Succeeded') | ||
old_client.endpoint.post_endpoint(body=object_to_send) | ||
|
||
print('Calling the post endpoint with the old client: Failed') | ||
try: | ||
new_client.endpoint.post_endpoint(body=object_to_send) | ||
raise RuntimeError('An error was expected') | ||
except ValidationError: | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,6 @@ | |
from swagger_spec_compatibility.rules.common import RuleType | ||
from swagger_spec_compatibility.rules.common import ValidationMessage | ||
from swagger_spec_compatibility.util import is_path_in_top_level_paths | ||
from swagger_spec_compatibility.walkers import format_path | ||
from swagger_spec_compatibility.walkers.enum_values import EnumValuesDifferWalker | ||
from swagger_spec_compatibility.walkers.response_paths import ResponsePathsWalker | ||
|
||
|
@@ -35,4 +34,10 @@ def validate(cls, left_spec, right_spec): | |
continue | ||
if not is_path_in_top_level_paths(response_paths, enum_values_diff.path): | ||
continue | ||
yield cls.validation_message(format_path(enum_values_diff.path)) | ||
message = '\n \t\t{} {}: new enum value {} in property `{}`\n\t\t'.format( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please keeps PR as small and scoped as possible, it simplifies review and increases confidence around the change. PS: removing this change would probably help you out with having green tests. |
||
enum_values_diff.path[2], | ||
enum_values_diff.path[1], | ||
enum_values_diff.mapping.new, | ||
enum_values_diff.path[-1], | ||
) | ||
yield cls.validation_message(message) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import | ||
from __future__ import print_function | ||
from __future__ import unicode_literals | ||
|
||
import typing | ||
|
||
from bravado_core.spec import Spec | ||
|
||
from swagger_spec_compatibility.rules.common import BaseRule | ||
from swagger_spec_compatibility.rules.common import Level | ||
from swagger_spec_compatibility.rules.common import RuleType | ||
from swagger_spec_compatibility.rules.common import ValidationMessage | ||
from swagger_spec_compatibility.util import is_path_in_top_level_paths | ||
from swagger_spec_compatibility.walkers.additional_properties import AdditionalPropertiesDifferWalker | ||
from swagger_spec_compatibility.walkers.additional_properties import DiffType | ||
from swagger_spec_compatibility.walkers.request_parameters import RequestParametersWalker | ||
|
||
|
||
class ChangedAdditionalPropertiesToFalse(BaseRule): | ||
description = \ | ||
'If the object is defined with additionalProperties set to False then the object will not allow presence of ' \ | ||
'properties not defined on the properties section of the object definition. ' \ | ||
'Changing additionalProperties from True to False makes objects sent from a client, ' \ | ||
'that contain additional properties and were permitted by the "old" Swagger specs, ' \ | ||
'to the server be considered invalid by the backend.' | ||
error_code = 'REQ-E004' | ||
error_level = Level.ERROR | ||
rule_type = RuleType.REQUEST_CONTRACT | ||
short_name = 'Changing additionalProperties to False for a request parameter' | ||
|
||
@classmethod | ||
def validate(cls, left_spec, right_spec): | ||
# type: (Spec, Spec) -> typing.Iterable[ValidationMessage] | ||
request_parameter_paths = RequestParametersWalker(left_spec, right_spec).walk() | ||
for additional_properties_diff in AdditionalPropertiesDifferWalker(left_spec, right_spec).walk(): | ||
if additional_properties_diff.diff_type != DiffType.VALUE: | ||
continue | ||
if not is_path_in_top_level_paths(request_parameter_paths, additional_properties_diff.path): | ||
continue | ||
message = "\n \t\t{} {}: schema's additionalProperties changed to False\n\t\t".format( | ||
additional_properties_diff.path[2], | ||
additional_properties_diff.path[1], | ||
) | ||
yield cls.validation_message(message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this file needed? I don't see it linked anywhere