Skip to content
Draft
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* `QuerystringBefore32`: detect Parameter `in: querystring` usage in pre-3.2 documents (3.2 addition; not validated at runtime)
* `CookieStyleBefore32`: detect Parameter `style: cookie` usage in pre-3.2 documents (3.2 addition)
* `ResponseSummaryBefore32`: detect Response Object `summary` usage in pre-3.2 documents (3.2 addition)
* `AllowEmptyValueDeprecation`: detect Parameter `allowEmptyValue` usage in 3.2 documents (deprecated in 3.2)
* return nil from `request_operation` for a document without `paths` (3.1 allows a document with only `webhooks`), instead of raising `NoMethodError`
* validate a value against a schema without `type`: keywords such as `properties`, `required`, `items`, `maxLength`, `enum` and `minimum` now apply when the value has the type the keyword is for, as in JSON Schema. They were all skipped before, so a value that breaks them may now fail validation
* add `allow_3_2_features` config to apply OpenAPI 3.2 runtime behavior to documents that declare an earlier version (default `false`: pre-3.2 documents behave as before)
Expand Down
2 changes: 2 additions & 0 deletions lib/openapi_parser/spec_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
require_relative 'spec_validator/rules/querystring_before_32'
require_relative 'spec_validator/rules/cookie_style_before_32'
require_relative 'spec_validator/rules/response_summary_before_32'
require_relative 'spec_validator/rules/allow_empty_value_deprecation'

module OpenAPIParser
class SpecViolationError < OpenAPIError
Expand Down Expand Up @@ -113,6 +114,7 @@ def rules
Rules::QuerystringBefore32,
Rules::CookieStyleBefore32,
Rules::ResponseSummaryBefore32,
Rules::AllowEmptyValueDeprecation,
]
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module OpenAPIParser
class SpecValidator
module Rules
# 3.2 deprecates `allowEmptyValue` on the Parameter Object (3.1 only
# called it NOT RECOMMENDED). The field is still allowed but
# discouraged, so we report it as a violation on 3.2 documents.
class AllowEmptyValueDeprecation < Rule
def check(root)
return [] unless version_at_least?('3.2')

violations = []
each_node(root, OpenAPIParser::Schemas::Parameter) do |node|
raw = node.raw_schema
next unless raw.is_a?(Hash) && raw.key?('allowEmptyValue')

violations << violation(
path: "#{node.object_reference}/allowEmptyValue",
message: '`allowEmptyValue` on a Parameter Object is deprecated in 3.2',
)
end
violations
end
end
end
end
end
4 changes: 4 additions & 0 deletions sig/openapi_parser/spec_validator.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ module OpenAPIParser
class ResponseSummaryBefore32 < Rule
def check: (OpenAPIParser::Schemas::OpenAPI root) -> Array[SpecValidator::SpecViolation]
end

class AllowEmptyValueDeprecation < Rule
def check: (OpenAPIParser::Schemas::OpenAPI root) -> Array[SpecValidator::SpecViolation]
end
end
end

Expand Down
17 changes: 17 additions & 0 deletions spec/data/openapi_3_2/allow_empty_value_31.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
openapi: 3.1.0
info:
title: Pet API
version: '1.0'
paths:
/pets:
get:
summary: List pets
parameters:
- name: q
in: query
allowEmptyValue: true
schema:
type: string
responses:
'200':
description: OK
19 changes: 19 additions & 0 deletions spec/data/openapi_3_2/allow_empty_value_32.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
openapi: 3.2.0
info:
title: Pet API
version: '1.0'
paths:
/pets:
get:
summary: List pets
parameters:
# `allowEmptyValue` on a Parameter Object is deprecated in 3.2, so its
# use here is a spec violation.
- name: q
in: query
allowEmptyValue: true
schema:
type: string
responses:
'200':
description: OK
14 changes: 14 additions & 0 deletions spec/openapi_parser/spec_validator/integration_3_2_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,18 @@ def expect_clean(file)
expect_clean('response_summary_32.yaml')
end
end

describe 'Parameter allowEmptyValue (deprecated in 3.2)' do
it 'warns on the version-mismatched document under :warn' do
expect_mismatch_warns('allow_empty_value_32.yaml', [:allow_empty_value_deprecation])
end

it 'raises SpecViolationError on the version-mismatched document under :raise' do
expect_mismatch_raises('allow_empty_value_32.yaml', [:allow_empty_value_deprecation])
end

it 'stays clean on the correctly-versioned document' do
expect_clean('allow_empty_value_31.yaml')
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
require_relative '../../../spec_helper'

RSpec.describe 'OpenAPIParser::SpecValidator::Rules::AllowEmptyValueDeprecation' do
def base_doc(openapi_version_string, param)
{
'openapi' => openapi_version_string,
'info' => { 'title' => 'test', 'version' => '1.0' },
'paths' => {
'/pets' => {
'get' => {
'parameters' => [param],
'responses' => { '200' => { 'description' => 'OK' } },
},
},
},
}
end

def doc_with(openapi_version_string)
OpenAPIParser.parse(base_doc(openapi_version_string, { 'name' => 'q', 'in' => 'query', 'allowEmptyValue' => true, 'schema' => { 'type' => 'string' } }), strict_reference_validation: false)
end

def doc_without(openapi_version_string)
OpenAPIParser.parse(base_doc(openapi_version_string, { 'name' => 'q', 'in' => 'query', 'schema' => { 'type' => 'string' } }), strict_reference_validation: false)
end

def run_rule_for(root)
OpenAPIParser::SpecValidator::Rules::AllowEmptyValueDeprecation.new(root.openapi_version).check(root)
end

context 'with a 3.2 document using allowEmptyValue' do
it 'reports one violation pointing at the field' do
root = doc_with('3.2.0')
violations = run_rule_for(root)
expect(violations.size).to eq 1
expect(violations.first.path).to eq '#/paths/~1pets/get/parameters/0/allowEmptyValue'
expect(violations.first.rule_name).to eq :allow_empty_value_deprecation
expect(violations.first.message).to include('deprecated in 3.2')
end
end

context 'with a 3.2 document without allowEmptyValue' do
it 'reports no violation' do
expect(run_rule_for(doc_without('3.2.0'))).to eq []
end
end

context 'with a 3.1 document using allowEmptyValue' do
it 'reports no violation' do
expect(run_rule_for(doc_with('3.1.0'))).to eq []
end
end

context 'with a 3.1 document without allowEmptyValue' do
it 'reports no violation' do
expect(run_rule_for(doc_without('3.1.0'))).to eq []
end
end

context 'with a 3.0 document using allowEmptyValue' do
it 'reports no violation' do
expect(run_rule_for(doc_with('3.0.0'))).to eq []
end
end

context 'with a document whose openapi field is not a version' do
it 'reports no violation (rule skipped)' do
expect(run_rule_for(doc_with('not-a-version'))).to eq []
end
end
end