Skip to content

Commit

Permalink
Adds new rule for checking base uri equality.
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksander Lorenc committed Jan 26, 2020
1 parent 5f2b8a3 commit 1550af8
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ It contains rules for checking whether:

- [ ] Update README with rule names and behavior
- [X] Support json specs
- [ ] Add optional rule for checking base url equality & whether suffix after base url is the same in integration
- [X] Add optional rule for checking base url equality
- [ ] Ignore path-params if `http_proxy` integration type used
- [X] Add option to disable rules via CLI
- [X] Add warning threshold to return with status code 0 if limit not exceeded
Expand Down
6 changes: 6 additions & 0 deletions aws_openapi_lint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .rules.CORSInconsistentHeadersRule import CORSInconsistentHeadersRule
from .rules.CORSNotEnoughVerbsRule import CORSNotEnoughVerbsRule
from .rules.ConflictingHttpVerbsRule import ConflictingHttpVerbsRule
from .rules.IntegrationBaseUriRule import IntegrationBaseUriRule
from .rules.MissingAmazonIntegrationRule import MissingAmazonIntegrationRule
from .rules.NoCORSPresentRule import NoCORSPresentRule
from .rules.PathParamNotMappedRule import PathParamNotMappedRule
Expand Down Expand Up @@ -38,6 +39,8 @@ def parse_arguments():
parser.add_argument('--warning-threshold', default=-1, type=int, help='Warning threshold which when surpassed '
'renders exit code to become 1)')
parser.add_argument('--exclude-rules', default="", type=str, help='Excluded rules separated by comma.')
parser.add_argument('--check-base-uri', default="", type=str, help='Checks whether every integration\'s '
'path is equal to the base uri specified.')
return parser.parse_args()


Expand Down Expand Up @@ -67,6 +70,9 @@ def cli(args=None, input_format="yaml", program_name="aws-openapi-lint"):
for rule in effective_rules:
rule_validator.add_rule(rule)

if args.check_base_uri != "":
rule_validator.add_rule(IntegrationBaseUriRule(base_uri = args.check_base_uri))

violations = rule_validator.validate()

if len(violations) == 0:
Expand Down
27 changes: 27 additions & 0 deletions aws_openapi_lint/rules/IntegrationBaseUriRule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from .rule_validator import RuleViolation
from .rules_helper import get_path_verbs, get_apigateway_integration


class IntegrationBaseUriRule:
base_uri = ''

def __init__(self, base_uri):
self.rule_name = 'integration_base_uri'
self.base_uri = base_uri

def validate(self, spec):
violations = []
for path in spec['paths']:
for path_verb in get_path_verbs(spec, path):
if path_verb == 'options':
continue

integration = get_apigateway_integration(spec, path, path_verb)
integration_uri = integration['uri']

if not integration_uri.startswith(self.base_uri):
violations.append(RuleViolation('integration_base_uri',
message='Base URI "%s" not present at the beginning of URI "%s"' % (self.base_uri, integration_uri),
path=path))

return violations
2 changes: 2 additions & 0 deletions aws_openapi_lint/rules/NoCORSPresentRule.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ def validate(self, spec):

integration = get_apigateway_integration(spec, path, 'options')

print(integration)

for response in integration['responses']:
if response not in integration['responses'] or \
'responseParameters' not in integration['responses'][response]:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name='AWS-OpenAPI-Lint',
version='0.1.7',
version='0.2.0',
url='https://github.com/evilmint/aws-openapi-lint',
download_url='https://github.com/evilmint/aws-openapi-lint/archive/0.1.7.tar.gz',
description='AWS API Gateway OpenAPI spec linter',
Expand Down
15 changes: 15 additions & 0 deletions test_files/conflicting_base_uri.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
openapi: "3.0.1"
info:
title: "Test"
version: "1.0.0"
paths:
/test:
get:
responses:
200:
description: "200 response"
x-amazon-apigateway-integration:
type: "http"
uri: "http://some.uri"
passthroughBehavior: "when_no_match"
httpMethod: "GET"
18 changes: 17 additions & 1 deletion test_files/ok_spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,20 @@ paths:
type: "http"
uri: "http://some.uri"
passthroughBehavior: "when_no_match"
httpMethod: "GET"
httpMethod: "GET"
options:
responses:
200:
description: "200 response"
x-amazon-apigateway-integration:
type: "mock"
uri: "http://some.uri"
passthroughBehavior: "when_no_match"
httpMethod: "OPTIONS"
responses:
default:
statusCode: "200"
responseParameters:
method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
method.response.header.Access-Control-Allow-Headers: "''"
method.response.header.Access-Control-Allow-Origin: "'*'"
24 changes: 15 additions & 9 deletions tests/test_rule_validator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest

from aws_openapi_lint import IntegrationBaseUriRule
from aws_openapi_lint.rules.AuthorizerOnOptionsRule import AuthorizerOnOptionsRule
from aws_openapi_lint.rules.AuthorizerReferencedButMissingRule import AuthorizerReferencedButMissingRule
from aws_openapi_lint.rules.CORSInconsistentHeadersRule import CORSInconsistentHeadersRule
Expand All @@ -12,41 +13,46 @@


class RuleValidatorTestCase(unittest.TestCase):
def test_conflicting_verbs(self):
def test_should_return_conflicting_verbs_rule_violation(self):
rule_validator = RuleValidator(spec_path('conflicting_http_verbs_spec'))
rule_validator.add_rule(ConflictingHttpVerbsRule())
self.assertEqual([RuleViolation('conflicting_http_verbs')], rule_validator.validate())

def test_missing_amazon_integration(self):
def test_should_return_missing_amazon_integration_rule_violation(self):
rule_validator = RuleValidator(spec_path('no_amazon_integration'))
rule_validator.add_rule(MissingAmazonIntegrationRule())
self.assertEqual([RuleViolation('missing_amazon_integration')], rule_validator.validate())

def test_no_cors_present(self):
def test_should_return_no_cors_present_rule_violation(self):
rule_validator = RuleValidator(spec_path('options_no_cors_present'))
rule_validator.add_rule(NoCORSPresentRule())
self.assertEqual([RuleViolation('options_no_cors_present')], rule_validator.validate())

def test_cors_not_enough_verbs(self):
def test_should_return_cors_not_enough_verbs_rule_violation(self):
rule_validator = RuleValidator(spec_path('options_cors_inconsistent_verbs'))
rule_validator.add_rule(CORSNotEnoughVerbsRule())
self.assertEqual([RuleViolation('options_cors_not_enough_verbs')], rule_validator.validate())

def test_cors_inconsistent_headers(self):
def test_should_return_cors_inconsistent_headers_rule_violation(self):
rule_validator = RuleValidator(spec_path('options_cors_incosistent_headers'))
rule_validator.add_rule(CORSInconsistentHeadersRule())
self.assertEqual([RuleViolation('options_cors_incosistent_headers')], rule_validator.validate())

def test_authorizer_absent_but_referenced_in_request_params(self):
def test_should_return_authorizer_absent_but_referenced_in_request_params_rule_violation(self):
rule_validator = RuleValidator(spec_path('authorizer_referenced_but_missing'))
rule_validator.add_rule(AuthorizerReferencedButMissingRule())
self.assertEqual([RuleViolation('authorizer_referenced_but_missing')], rule_validator.validate())

def test_no_authorizer_on_options(self):
def test_should_return_no_authorizer_on_options_rule_violation(self):
rule_validator = RuleValidator(spec_path('no_authorizer_on_options'))
rule_validator.add_rule(AuthorizerOnOptionsRule())
self.assertEqual([RuleViolation('authorizer_on_options')], rule_validator.validate())

def test_should_return_integration_base_uri_rule_violation(self):
rule_validator = RuleValidator(spec_path('conflicting_base_uri'))
rule_validator.add_rule(IntegrationBaseUriRule(base_uri = 'e'))
self.assertEqual([RuleViolation('integration_base_uri')], rule_validator.validate())

def test_ok_spec(self):
rule_validator = RuleValidator(spec_path('ok_spec'))
rule_validator.add_rule(ConflictingHttpVerbsRule())
Expand All @@ -62,15 +68,15 @@ def test_should_not_return_violations_if_path_param_not_mapped_and_mock_integrat
rule_validator.add_rule(PathParamNotMappedRule())
self.assertEqual([], rule_validator.validate())

def test_path_param_not_mapped(self):
def test_should_return_path_param_not_mapped_rule_violation(self):
rule_validator = RuleValidator(spec_path('path_parameter_not_mapped'))
rule_validator.add_rule(PathParamNotMappedRule())
self.assertEqual([RuleViolation('path_parameter_not_mapped'), RuleViolation('path_parameter_not_mapped')],
rule_validator.validate())


def spec_path(file_name):
return 'test_files/' + file_name + '.yml'
return './test_files/' + file_name + '.yml'


if __name__ == '__main__':
Expand Down

0 comments on commit 1550af8

Please sign in to comment.