committee 4.4.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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.