Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 17 additions & 28 deletions samtranslator/model/api/api_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,41 +969,30 @@ def _openapi_postprocess(self, definition_body):
del definition_body["definitions"]
# removes `consumes` and `produces` options for CORS in openapi3 and
# adds `schema` for the headers in responses for openapi3
if definition_body.get("paths"):
for path in definition_body.get("paths"):
if definition_body.get("paths").get(path).get("options"):
definition_body_options = definition_body.get("paths").get(path).get("options").copy()
for field in definition_body_options.keys():
paths = definition_body.get("paths")
if paths:
for path, path_item in paths.items():
SwaggerEditor.validate_path_item_is_dict(path_item, path)
if path_item.get("options"):
options = path_item.get("options").copy()
for field, field_val in options.items():
# remove unsupported produces and consumes in options for openapi3
if field in ["produces", "consumes"]:
del definition_body["paths"][path]["options"][field]
# add schema for the headers in options section for openapi3
if field in ["responses"]:
options_path = definition_body["paths"][path]["options"]
if options_path and not isinstance(options_path.get(field), dict):
raise InvalidDocumentException(
[
InvalidTemplateException(
"Value of responses in options method for path {} must be a "
"dictionary according to Swagger spec.".format(path)
)
]
)
if (
options_path
and options_path.get(field).get("200")
and options_path.get(field).get("200").get("headers")
):
headers = definition_body["paths"][path]["options"][field]["200"]["headers"]
for header in headers.keys():
header_value = {
"schema": definition_body["paths"][path]["options"][field]["200"][
"headers"
][header]
}
SwaggerEditor.validate_is_dict(
field_val,
"Value of responses in options method for path {} must be a "
"dictionary according to Swagger spec.".format(path),
)
if field_val.get("200") and field_val.get("200").get("headers"):
headers = field_val["200"]["headers"]
for header, header_val in headers.items():
new_header_val_with_schema = {"schema": header_val}
definition_body["paths"][path]["options"][field]["200"]["headers"][
header
] = header_value
] = new_header_val_with_schema

return definition_body

Expand Down
61 changes: 33 additions & 28 deletions samtranslator/swagger/swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,7 @@ def add_path(self, path, method=None):
method = self._normalize_method_name(method)

path_dict = self.paths.setdefault(path, {})

if not isinstance(path_dict, dict):
# Either customers has provided us an invalid Swagger, or this class has messed it somehow
raise InvalidDocumentException(
[
InvalidTemplateException(
"Value of '{}' path must be a dictionary according to Swagger spec.".format(path)
)
]
)
SwaggerEditor.validate_path_item_is_dict(path_dict, path)

if self._CONDITIONAL_IF in path_dict:
path_dict = path_dict[self._CONDITIONAL_IF][1]
Expand Down Expand Up @@ -536,15 +527,10 @@ def set_path_default_authorizer(
# It is possible that the method could have two definitions in a Fn::If block.
for method_definition in self.get_method_contents(method):

SwaggerEditor.validate_is_dict(
method_definition, "{} for path {} is not a valid dictionary.".format(method_definition, path)
)
# If no integration given, then we don't need to process this definition (could be AWS::NoValue)
if not isinstance(method_definition, dict):
raise InvalidDocumentException(
[
InvalidTemplateException(
"{} for path {} is not a valid dictionary.".format(method_definition, path)
)
]
)
if not self.method_definition_has_integration(method_definition):
continue
existing_security = method_definition.get("security", [])
Expand All @@ -559,14 +545,9 @@ def set_path_default_authorizer(
# (e.g. sigv4 (AWS_IAM), api_key (API Key/Usage Plans), NONE (marker for ignoring default))
# We want to ensure only a single Authorizer security entry exists while keeping everything else
for security in existing_security:
if not isinstance(security, dict):
raise InvalidDocumentException(
[
InvalidTemplateException(
"{} in Security for path {} is not a valid dictionary.".format(security, path)
)
]
)
SwaggerEditor.validate_is_dict(
security, "{} in Security for path {} is not a valid dictionary.".format(security, path)
)
if authorizer_names.isdisjoint(security.keys()):
existing_non_authorizer_security.append(security)
else:
Expand Down Expand Up @@ -912,8 +893,7 @@ def add_resource_policy(self, resource_policy, path, stage):
"""
if resource_policy is None:
return
if not isinstance(resource_policy, dict):
raise InvalidDocumentException([InvalidTemplateException("Resource Policy is not a valid dictionary.")])
SwaggerEditor.validate_is_dict(resource_policy, "Resource Policy is not a valid dictionary.")

aws_account_whitelist = resource_policy.get("AwsAccountWhitelist")
aws_account_blacklist = resource_policy.get("AwsAccountBlacklist")
Expand Down Expand Up @@ -1244,6 +1224,31 @@ def is_valid(data):
)
return False

@staticmethod
def validate_is_dict(obj, exception_message):
"""
Throws exception if obj is not a dict

:param obj: object being validated
:param exception_message: message to include in exception if obj is not a dict
"""

if not isinstance(obj, dict):
raise InvalidDocumentException([InvalidTemplateException(exception_message)])

@staticmethod
def validate_path_item_is_dict(path_item, path):
"""
Throws exception if path_item is not a dict

:param path_item: path_item (value at the path) being validated
:param path: path name
"""

SwaggerEditor.validate_is_dict(
path_item, "Value of '{}' path must be a dictionary according to Swagger spec.".format(path)
)

Comment on lines +1227 to +1251
Copy link
Contributor Author

@torresxb1 torresxb1 Nov 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure where's the best place to add this, but thought this was good for now since some validation is done in this file. Also am I supposed to also add this to open_api.py?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you add a new method, and did not used validate_is_dict. The new method is just a wrapper for the existing one.

Copy link
Contributor Author

@torresxb1 torresxb1 Nov 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because this same action (validating the path item) would be done in swagger.py and api_generator.py. I mainly just didn't want to repeat the error message and make sure that it was consistent in every place if it's changed in the future. Not sure if there's a better way of doing it, where I just generate the error message.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@staticmethod
def gen_skeleton():
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Resources:
ApiWithInvalidPath:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
OpenApiVersion: 3.0.1
DefinitionBody:
openapi: 3.0.1
info:
title: test invalid paths Api
paths:
/foo: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Resources:
ApiWithInvalidPath:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
OpenApiVersion: 3.0.1
DefinitionBody:
openapi: 3.0.1
info:
title: test invalid paths Api
paths:
/foo: invalid
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Structure of the SAM template is invalid. Value of '/foo' path must be a dictionary according to Swagger spec."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Structure of the SAM template is invalid. Value of '/foo' path must be a dictionary according to Swagger spec."
}