committee 4.4.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/committee/drivers/open_api_2/driver.rb +1 -1
  3. data/lib/committee/drivers/open_api_2/parameter_schema_builder.rb +1 -1
  4. data/lib/committee/drivers.rb +21 -9
  5. data/lib/committee/middleware/base.rb +5 -4
  6. data/lib/committee/middleware/request_validation.rb +1 -8
  7. data/lib/committee/middleware/response_validation.rb +13 -14
  8. data/lib/committee/request_unpacker.rb +1 -1
  9. data/lib/committee/schema_validator/hyper_schema/response_validator.rb +8 -2
  10. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +36 -33
  11. data/lib/committee/schema_validator/open_api_3/request_validator.rb +11 -2
  12. data/lib/committee/schema_validator/open_api_3.rb +28 -15
  13. data/lib/committee/schema_validator/option.rb +5 -13
  14. data/lib/committee/schema_validator.rb +1 -1
  15. data/lib/committee/test/methods.rb +2 -7
  16. data/lib/committee/version.rb +5 -0
  17. data/lib/committee.rb +9 -2
  18. data/test/committee_test.rb +28 -2
  19. data/test/drivers/open_api_3/driver_test.rb +1 -1
  20. data/test/drivers_test.rb +20 -7
  21. data/test/middleware/base_test.rb +6 -13
  22. data/test/middleware/request_validation_open_api_3_test.rb +117 -41
  23. data/test/middleware/request_validation_test.rb +1 -28
  24. data/test/middleware/response_validation_open_api_3_test.rb +46 -3
  25. data/test/middleware/response_validation_test.rb +6 -25
  26. data/test/schema_validator/hyper_schema/response_validator_test.rb +10 -0
  27. data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +1 -1
  28. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +55 -11
  29. data/test/schema_validator/open_api_3/request_validator_test.rb +25 -1
  30. data/test/schema_validator/open_api_3/response_validator_test.rb +14 -0
  31. data/test/test/methods_new_version_test.rb +1 -1
  32. data/test/test/methods_test.rb +11 -31
  33. data/test/test_helper.rb +15 -5
  34. metadata +9 -14
@@ -32,12 +32,15 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
32
32
  ]
33
33
 
34
34
  it 'correct data' do
35
- operation_object.validate_request_params(SCHEMA_PROPERTIES_PAIR.to_h, HEADER, @validator_option)
35
+ operation_object.validate_request_params({}, {}, SCHEMA_PROPERTIES_PAIR.to_h, HEADER, @validator_option)
36
36
  assert true
37
37
  end
38
38
 
39
39
  it 'correct object data' do
40
- operation_object.validate_request_params({
40
+ operation_object.validate_request_params(
41
+ {},
42
+ {},
43
+ {
41
44
  "object_1" =>
42
45
  {
43
46
  "string_1" => nil,
@@ -54,7 +57,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
54
57
 
55
58
  it 'invalid params' do
56
59
  e = assert_raises(Committee::InvalidRequest) {
57
- operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
60
+ operation_object.validate_request_params({}, {}, {"string" => 1}, HEADER, @validator_option)
58
61
  }
59
62
 
60
63
  assert_match(/expected string, but received Integer: 1/i, e.message)
@@ -63,10 +66,10 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
63
66
 
64
67
  it 'support put method' do
65
68
  @method = "put"
66
- operation_object.validate_request_params({"string" => "str"}, HEADER, @validator_option)
69
+ operation_object.validate_request_params({}, {}, {"string" => "str"}, HEADER, @validator_option)
67
70
 
68
71
  e = assert_raises(Committee::InvalidRequest) {
69
- operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
72
+ operation_object.validate_request_params({}, {}, {"string" => 1}, HEADER, @validator_option)
70
73
  }
71
74
 
72
75
  assert_match(/expected string, but received Integer: 1/i, e.message)
@@ -75,10 +78,10 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
75
78
 
76
79
  it 'support patch method' do
77
80
  @method = "patch"
78
- operation_object.validate_request_params({"integer" => 1}, HEADER, @validator_option)
81
+ operation_object.validate_request_params({}, {}, {"integer" => 1}, HEADER, @validator_option)
79
82
 
80
83
  e = assert_raises(Committee::InvalidRequest) {
81
- operation_object.validate_request_params({"integer" => "str"}, HEADER, @validator_option)
84
+ operation_object.validate_request_params({}, {}, {"integer" => "str"}, HEADER, @validator_option)
82
85
  }
83
86
 
84
87
  assert_match(/expected integer, but received String: "str"/i, e.message)
@@ -86,7 +89,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
86
89
  end
87
90
 
88
91
  it 'unknown param' do
89
- operation_object.validate_request_params({"unknown" => 1}, HEADER, @validator_option)
92
+ operation_object.validate_request_params({}, {}, {"unknown" => 1}, HEADER, @validator_option)
90
93
  end
91
94
 
92
95
  describe 'support get method' do
@@ -96,13 +99,17 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
96
99
 
97
100
  it 'correct' do
98
101
  operation_object.validate_request_params(
102
+ {},
99
103
  {"query_string" => "query", "query_integer_list" => [1, 2]},
104
+ {},
100
105
  HEADER,
101
106
  @validator_option
102
107
  )
103
108
 
104
109
  operation_object.validate_request_params(
110
+ {},
105
111
  {"query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1},
112
+ {},
106
113
  HEADER,
107
114
  @validator_option
108
115
  )
@@ -112,7 +119,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
112
119
 
113
120
  it 'not exist required' do
114
121
  e = assert_raises(Committee::InvalidRequest) {
115
- operation_object.validate_request_params({"query_integer_list" => [1, 2]}, HEADER, @validator_option)
122
+ operation_object.validate_request_params({}, {"query_integer_list" => [1, 2]}, {}, HEADER, @validator_option)
116
123
  }
117
124
 
118
125
  assert_match(/missing required parameters: query_string/i, e.message)
@@ -122,7 +129,9 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
122
129
  it 'invalid type' do
123
130
  e = assert_raises(Committee::InvalidRequest) {
124
131
  operation_object.validate_request_params(
132
+ {},
125
133
  {"query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1},
134
+ {},
126
135
  HEADER,
127
136
  @validator_option
128
137
  )
@@ -140,14 +149,14 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
140
149
  end
141
150
 
142
151
  it 'correct' do
143
- operation_object.validate_request_params({"limit" => "1"}, HEADER, @validator_option)
152
+ operation_object.validate_request_params({}, {"limit" => "1"}, {}, HEADER, @validator_option)
144
153
 
145
154
  assert true
146
155
  end
147
156
 
148
157
  it 'invalid type' do
149
158
  e = assert_raises(Committee::InvalidRequest) {
150
- operation_object.validate_request_params({"limit" => "a"}, HEADER, @validator_option)
159
+ operation_object.validate_request_params({}, {"limit" => "a"}, {}, HEADER, @validator_option)
151
160
  }
152
161
 
153
162
  assert_match(/expected integer, but received String: "a"/i, e.message)
@@ -155,6 +164,41 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
155
164
  end
156
165
  end
157
166
 
167
+ describe 'support head method' do
168
+ before do
169
+ @path = '/characters'
170
+ @method = 'head'
171
+ end
172
+
173
+ it 'correct' do
174
+ operation_object.validate_request_params({}, {"limit" => "1"}, {}, HEADER, @validator_option)
175
+
176
+ assert true
177
+ end
178
+
179
+ it 'invalid type' do
180
+ e = assert_raises(Committee::InvalidRequest) {
181
+ operation_object.validate_request_params({}, {"limit" => "a"}, {}, HEADER, @validator_option)
182
+ }
183
+
184
+ assert_match(/expected integer, but received String: "a"/i, e.message)
185
+ assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
186
+ end
187
+ end
188
+
189
+ it 'support options method' do
190
+ @method = "options"
191
+ operation_object.validate_request_params({}, {}, {"integer" => 1}, HEADER, @validator_option)
192
+
193
+ e = assert_raises(Committee::InvalidRequest) {
194
+ operation_object.validate_request_params({}, {}, {"integer" => "str"}, HEADER, @validator_option)
195
+ }
196
+
197
+ assert_match(/expected integer, but received String: "str"/i, e.message)
198
+ assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
199
+ end
200
+
201
+
158
202
  describe '#content_types' do
159
203
  it 'returns supported content types' do
160
204
  @path = '/validate_content_types'
@@ -71,10 +71,34 @@ describe Committee::SchemaValidator::OpenAPI3::RequestValidator do
71
71
  assert_equal 200, last_response.status
72
72
  end
73
73
 
74
+ it "skips content_type check with an empty body" do
75
+ @app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
76
+ header "Content-Type", "application/x-www-form-urlencoded"
77
+ patch "/validate_empty_optional_body"
78
+ assert_equal 200, last_response.status
79
+ end
80
+
81
+ it "does not mix up parameters and requestBody" do
82
+ @app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
83
+ params = {
84
+ "last_name" => "Skywalker"
85
+ }
86
+ header "Content-Type", "application/json"
87
+ post "/additional_properties?first_name=Luke", JSON.generate(params)
88
+ assert_equal 200, last_response.status
89
+ end
90
+
91
+ it "error because content_type check with body" do
92
+ @app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
93
+ header "Content-Type", "application/x-www-form-urlencoded"
94
+ patch "/validate_empty_optional_body", "{}"
95
+ assert_equal 400, last_response.status
96
+ end
97
+
74
98
  def new_rack_app(options = {})
75
99
  # TODO: delete when 5.0.0 released because default value changed
76
100
  options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
77
-
101
+
78
102
  Rack::Builder.new {
79
103
  use Committee::Middleware::RequestValidation, options
80
104
  run lambda { |_|
@@ -42,6 +42,15 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
42
42
  assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
43
43
  end
44
44
 
45
+ it "raises InvalidResponse when a invalid status code with strict option" do
46
+ @status = 201
47
+ e = assert_raises(Committee::InvalidResponse) {
48
+ call_response_validator(true)
49
+ }
50
+
51
+ assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
52
+ end
53
+
45
54
  it "passes through a valid response with no Content-Type" do
46
55
  @headers = {}
47
56
  call_response_validator
@@ -67,6 +76,11 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
67
76
  call_response_validator
68
77
  end
69
78
 
79
+ it "passes through a 304 Not Modified response" do
80
+ @status, @headers, @data = 304, {}, nil
81
+ call_response_validator
82
+ end
83
+
70
84
  private
71
85
 
72
86
  def call_response_validator(strict = false)
@@ -72,7 +72,7 @@ describe Committee::Test::Methods do
72
72
  @committee_options.merge!(validate_success_only: true)
73
73
  @app = new_rack_app(JSON.generate([ValidApp]), 400, {})
74
74
  get "/apps"
75
- assert_schema_conform
75
+ assert_schema_conform(400)
76
76
  end
77
77
 
78
78
  it "detects an invalid response Content-Type and check all status code" do
@@ -57,16 +57,6 @@ describe Committee::Test::Methods do
57
57
  end
58
58
  assert_match(/response header must be set to/i, e.message)
59
59
  end
60
-
61
- it "outputs deprecation warning" do
62
- @app = new_rack_app(JSON.generate([ValidApp]))
63
- get "/apps"
64
- _, err = capture_io do
65
- assert_schema_conform
66
- end
67
- assert_match(/\[DEPRECATION\] Now assert_schema_conform check response schema only/i, err)
68
- assert_match(/\[DEPRECATION\] Pass expected response status code/i, err)
69
- end
70
60
  end
71
61
 
72
62
  describe "assert_request_schema_confirm" do
@@ -99,14 +89,14 @@ describe Committee::Test::Methods do
99
89
  it "passes through a valid response" do
100
90
  @app = new_rack_app(JSON.generate([ValidApp]))
101
91
  get "/apps"
102
- assert_response_schema_confirm
92
+ assert_response_schema_confirm(200)
103
93
  end
104
94
 
105
95
  it "detects an invalid response Content-Type" do
106
96
  @app = new_rack_app(JSON.generate([ValidApp]), {})
107
97
  get "/apps"
108
98
  e = assert_raises(Committee::InvalidResponse) do
109
- assert_response_schema_confirm
99
+ assert_response_schema_confirm(200)
110
100
  end
111
101
  assert_match(/response header must be set to/i, e.message)
112
102
  end
@@ -133,14 +123,14 @@ describe Committee::Test::Methods do
133
123
  it "passes through a valid response" do
134
124
  @app = new_rack_app(JSON.generate(@correct_response))
135
125
  get "/characters"
136
- assert_schema_conform
126
+ assert_schema_conform(200)
137
127
  end
138
128
 
139
129
  it "detects an invalid response Content-Type" do
140
130
  @app = new_rack_app(JSON.generate([@correct_response]), {})
141
131
  get "/characters"
142
132
  e = assert_raises(Committee::InvalidResponse) do
143
- assert_schema_conform
133
+ assert_schema_conform(200)
144
134
  end
145
135
  assert_match(/response definition does not exist/i, e.message)
146
136
  end
@@ -151,20 +141,10 @@ describe Committee::Test::Methods do
151
141
  get "/characters"
152
142
 
153
143
  e = assert_raises(Committee::InvalidResponse) do
154
- assert_schema_conform
144
+ assert_schema_conform(419)
155
145
  end
156
146
  assert_match(/status code definition does not exist/i, e.message)
157
147
  end
158
-
159
- it "outputs deprecation warning" do
160
- @app = new_rack_app(JSON.generate(@correct_response))
161
- get "/characters"
162
- _, err = capture_io do
163
- assert_schema_conform
164
- end
165
- assert_match(/\[DEPRECATION\] Now assert_schema_conform check response schema only/i, err)
166
- assert_match(/\[DEPRECATION\] Pass expected response status code/i, err)
167
- end
168
148
  end
169
149
 
170
150
  describe "assert_request_schema_confirm" do
@@ -198,14 +178,14 @@ describe Committee::Test::Methods do
198
178
  it "passes through a valid response" do
199
179
  @app = new_rack_app(JSON.generate(@correct_response))
200
180
  get "/characters"
201
- assert_response_schema_confirm
181
+ assert_response_schema_confirm(200)
202
182
  end
203
183
 
204
184
  it "detects an invalid response Content-Type" do
205
185
  @app = new_rack_app(JSON.generate([@correct_response]), {})
206
186
  get "/characters"
207
187
  e = assert_raises(Committee::InvalidResponse) do
208
- assert_response_schema_confirm
188
+ assert_response_schema_confirm(200)
209
189
  end
210
190
  assert_match(/response definition does not exist/i, e.message)
211
191
  end
@@ -216,7 +196,7 @@ describe Committee::Test::Methods do
216
196
  get "/characters"
217
197
 
218
198
  e = assert_raises(Committee::InvalidResponse) do
219
- assert_response_schema_confirm
199
+ assert_response_schema_confirm(419)
220
200
  end
221
201
  assert_match(/status code definition does not exist/i, e.message)
222
202
  end
@@ -249,7 +229,7 @@ describe Committee::Test::Methods do
249
229
  end
250
230
  it 'records openapi coverage' do
251
231
  get "/posts"
252
- assert_response_schema_confirm
232
+ assert_response_schema_confirm(200)
253
233
  assert_equal({
254
234
  '/threads/{id}' => {
255
235
  'get' => {
@@ -290,7 +270,7 @@ describe Committee::Test::Methods do
290
270
  it 'can record openapi coverage correctly when prefix is set' do
291
271
  @committee_options.merge!(prefix: '/api')
292
272
  post "/api/likes"
293
- assert_response_schema_confirm
273
+ assert_response_schema_confirm(200)
294
274
  assert_equal({
295
275
  '/threads/{id}' => {
296
276
  'get' => {
@@ -330,7 +310,7 @@ describe Committee::Test::Methods do
330
310
 
331
311
  it 'records openapi coverage correctly with path param' do
332
312
  get "/threads/asd"
333
- assert_response_schema_confirm
313
+ assert_response_schema_confirm(200)
334
314
  assert_equal({
335
315
  '/threads/{id}' => {
336
316
  'get' => {
data/test/test_helper.rb CHANGED
@@ -11,8 +11,10 @@ SimpleCov.start do
11
11
  add_filter "/test/"
12
12
 
13
13
  # This library has a pretty modest number of lines, so let's try to stick
14
- # to a 100% coverage target for a while and see what happens.
15
- minimum_coverage 100
14
+ # to a 99% coverage target for a while and see what happens.
15
+ # We can't use 100% because old rack version doesn't support media_type and it's not testable :(
16
+ # https://github.com/interagent/committee/pull/360/files#diff-ce1125b6594690a88a70dbe2869f7fcfa2962c2bca80751f3720888920e2dfabR54
17
+ minimum_coverage 99
16
18
  end
17
19
 
18
20
  require "minitest"
@@ -60,11 +62,11 @@ def open_api_2_form_schema
60
62
  end
61
63
 
62
64
  def open_api_3_schema
63
- @open_api_3_schema ||= Committee::Drivers.load_from_file(open_api_3_schema_path)
65
+ @open_api_3_schema ||= Committee::Drivers.load_from_file(open_api_3_schema_path, parser_options:{strict_reference_validation: true})
64
66
  end
65
67
 
66
68
  def open_api_3_coverage_schema
67
- @open_api_3_coverage_schema ||= Committee::Drivers.load_from_file(open_api_3_coverage_schema_path)
69
+ @open_api_3_coverage_schema ||= Committee::Drivers.load_from_file(open_api_3_coverage_schema_path, parser_options:{strict_reference_validation: true})
68
70
  end
69
71
 
70
72
  # Don't cache this because we'll often manipulate the created hash in tests.
@@ -82,7 +84,11 @@ def open_api_2_form_data
82
84
  end
83
85
 
84
86
  def open_api_3_data
85
- YAML.load_file(open_api_3_schema_path)
87
+ if YAML.respond_to?(:unsafe_load_file)
88
+ YAML.unsafe_load_file(open_api_3_schema_path)
89
+ else
90
+ YAML.load_file(open_api_3_schema_path)
91
+ end
86
92
  end
87
93
 
88
94
  def hyper_schema_schema_path
@@ -108,3 +114,7 @@ end
108
114
  def open_api_3_0_1_schema_path
109
115
  "./test/data/openapi3/3_0_1.yaml"
110
116
  end
117
+
118
+ def open_api_3_invalid_reference_path
119
+ "./test/data/openapi3/invalid_reference.yaml"
120
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: committee
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandur
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-06-12 00:00:00.000000000 Z
13
+ date: 2023-01-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json_schema
@@ -50,20 +50,14 @@ dependencies:
50
50
  name: openapi_parser
51
51
  requirement: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: 0.11.1
56
- - - "<"
53
+ - - "~>"
57
54
  - !ruby/object:Gem::Version
58
55
  version: '1.0'
59
56
  type: :runtime
60
57
  prerelease: false
61
58
  version_requirements: !ruby/object:Gem::Requirement
62
59
  requirements:
63
- - - ">="
64
- - !ruby/object:Gem::Version
65
- version: 0.11.1
66
- - - "<"
60
+ - - "~>"
67
61
  - !ruby/object:Gem::Version
68
62
  version: '1.0'
69
63
  - !ruby/object:Gem::Dependency
@@ -86,14 +80,14 @@ dependencies:
86
80
  requirements:
87
81
  - - "~>"
88
82
  - !ruby/object:Gem::Version
89
- version: '0.6'
83
+ version: '0.8'
90
84
  type: :development
91
85
  prerelease: false
92
86
  version_requirements: !ruby/object:Gem::Requirement
93
87
  requirements:
94
88
  - - "~>"
95
89
  - !ruby/object:Gem::Version
96
- version: '0.6'
90
+ version: '0.8'
97
91
  - !ruby/object:Gem::Dependency
98
92
  name: rake
99
93
  requirement: !ruby/object:Gem::Requirement
@@ -275,6 +269,7 @@ files:
275
269
  - lib/committee/test/schema_coverage.rb
276
270
  - lib/committee/utils.rb
277
271
  - lib/committee/validation_error.rb
272
+ - lib/committee/version.rb
278
273
  - test/bin/committee_stub_test.rb
279
274
  - test/bin_test.rb
280
275
  - test/committee_test.rb
@@ -319,14 +314,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
319
314
  requirements:
320
315
  - - ">="
321
316
  - !ruby/object:Gem::Version
322
- version: 2.4.0
317
+ version: 2.6.0
323
318
  required_rubygems_version: !ruby/object:Gem::Requirement
324
319
  requirements:
325
320
  - - ">="
326
321
  - !ruby/object:Gem::Version
327
322
  version: '0'
328
323
  requirements: []
329
- rubygems_version: 3.2.3
324
+ rubygems_version: 3.3.3
330
325
  signing_key:
331
326
  specification_version: 4
332
327
  summary: A collection of Rack middleware to support JSON Schema.