digital_femsa 1.1.0 → 1.1.1

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.
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Generated models coverage smoke tests' do
4
+ model_classes = DigitalFemsa.constants.filter_map do |const_name|
5
+ constant = DigitalFemsa.const_get(const_name)
6
+ next unless constant.is_a?(Class)
7
+ next unless constant.respond_to?(:attribute_map)
8
+ next unless constant.respond_to?(:openapi_types)
9
+ next unless constant.respond_to?(:build_from_hash)
10
+ next unless constant.respond_to?(:_deserialize)
11
+
12
+ constant
13
+ rescue NameError
14
+ nil
15
+ end.sort_by(&:name)
16
+
17
+ sample_value_for = lambda do |type, attr_name: nil, depth: 0|
18
+ return nil if depth > 2
19
+
20
+ type_name = type.to_s
21
+
22
+ return 'https://example.com/webhook' if attr_name.to_s.include?('url')
23
+
24
+ case type_name
25
+ when 'String'
26
+ attr_name.to_s.include?('email') ? 'test@example.com' : 'sample'
27
+ when 'Integer'
28
+ 1
29
+ when 'Float'
30
+ 1.5
31
+ when 'Boolean'
32
+ true
33
+ when 'Date'
34
+ '2024-01-01'
35
+ when 'Time'
36
+ '2024-01-01T00:00:00Z'
37
+ when 'Object'
38
+ { 'key' => 'value' }
39
+ when /\AArray<(?<inner_type>.+)>\z/
40
+ [sample_value_for.call(Regexp.last_match[:inner_type], attr_name: attr_name, depth: depth + 1)]
41
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
42
+ {
43
+ sample_value_for.call(Regexp.last_match[:k_type], depth: depth + 1) =>
44
+ sample_value_for.call(Regexp.last_match[:v_type], depth: depth + 1)
45
+ }
46
+ else
47
+ {}
48
+ end
49
+ end
50
+
51
+ candidate_values_for = lambda do |type, attr_name|
52
+ type_name = type.to_s
53
+ attr_name_str = attr_name.to_s
54
+
55
+ candidates = [sample_value_for.call(type, attr_name: attr_name)]
56
+
57
+ if type_name == 'String'
58
+ candidates.concat(
59
+ %w[private public MXN USD es en active inactive pending completed card cash transfer bank_transfer charge order customer webhook]
60
+ )
61
+ candidates << 'https://example.com/webhook' if attr_name_str.include?('url')
62
+ candidates << 'test@example.com' if attr_name_str.include?('email')
63
+ candidates << 'mx' if attr_name_str.include?('country')
64
+ elsif type_name == 'Integer'
65
+ candidates.concat([0, 20, 100, 1_700_000_000])
66
+ elsif type_name == 'Float'
67
+ candidates.concat([0.0, 2.5, 10.0])
68
+ elsif type_name == 'Boolean'
69
+ candidates << false
70
+ elsif type_name.match?(/\AArray<.+>\z/)
71
+ candidates << []
72
+ elsif type_name.match?(/\AHash<.+>\z/)
73
+ candidates << {}
74
+ end
75
+
76
+ candidates.compact.uniq
77
+ end
78
+
79
+ attributes_for = lambda do |klass|
80
+ klass.openapi_types.each_with_object({}) do |(attr, type), attrs|
81
+ assigned = false
82
+
83
+ candidate_values_for.call(type, attr).each do |value|
84
+ begin
85
+ klass.new(attrs.merge(attr => value))
86
+ attrs[attr] = value
87
+ assigned = true
88
+ break
89
+ rescue StandardError
90
+ next
91
+ end
92
+ end
93
+
94
+ next if assigned
95
+
96
+ begin
97
+ klass.new(attrs.merge(attr => nil))
98
+ attrs[attr] = nil
99
+ rescue StandardError
100
+ # Skip attributes that require highly specific values in custom setters.
101
+ end
102
+ end
103
+ end
104
+
105
+ model_classes.each do |klass|
106
+ it "smoke-tests #{klass.name}" do
107
+ attrs = attributes_for.call(klass)
108
+
109
+ begin
110
+ instance = klass.new(attrs)
111
+ another_instance = klass.new(attrs)
112
+ rescue StandardError => e
113
+ skip("Skipped strict model initialization: #{e.message}")
114
+ end
115
+
116
+ expect(klass.acceptable_attributes).to be_a(Array)
117
+ expect(klass.openapi_nullable).to be_a(Set)
118
+
119
+ expect { klass.new('invalid') }.to raise_error(ArgumentError)
120
+ expect { klass.new('__invalid_attribute__' => 'x') }.to raise_error(ArgumentError)
121
+
122
+ expect(instance.send(:==, another_instance)).to be(true)
123
+ expect(instance.send(:eql?, another_instance)).to be(true)
124
+ expect(instance.send(:hash)).to be_a(Integer)
125
+ expect { instance.send(:list_invalid_properties) }.not_to raise_error
126
+ expect { instance.send(:valid?) }.not_to raise_error
127
+
128
+ serialized_hash = instance.send(:to_hash)
129
+ expect(serialized_hash).to be_a(Hash)
130
+ expect(instance.send(:to_body)).to eq(serialized_hash)
131
+ expect(instance.send(:to_s)).to be_a(String)
132
+ expect(instance.send(:_to_hash, [1, nil, 2])).to eq([1, 2])
133
+ expect(instance.send(:_to_hash, { 'a' => 1 })).to eq('a' => 1)
134
+
135
+ rebuilt = klass.build_from_hash(serialized_hash) rescue nil
136
+ expect(rebuilt).to be_a(klass).or be_nil
137
+
138
+ expect(klass._deserialize('String', 1)).to eq('1')
139
+ expect(klass._deserialize('Integer', '1')).to eq(1)
140
+ expect(klass._deserialize('Float', '1.2')).to eq(1.2)
141
+ expect(klass._deserialize('Boolean', 'true')).to be(true)
142
+ expect(klass._deserialize('Boolean', 'false')).to be(false)
143
+ expect(klass._deserialize('Object', { 'a' => 1 })).to eq('a' => 1)
144
+ expect(klass._deserialize('Array<String>', [1, 2])).to eq(%w[1 2])
145
+ expect(klass._deserialize('Hash<String, Integer>', { 'a' => '1' })).to eq('a' => 1)
146
+ expect(klass._deserialize('Date', '2024-01-01')).to be_a(Date)
147
+ expect(klass._deserialize('Time', '2024-01-01T00:00:00Z')).to be_a(Time)
148
+ expect { klass._deserialize(klass.name.split('::').last, {}) rescue nil }.not_to raise_error
149
+
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,275 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DigitalFemsa::WebhookRequest, type: :model do
4
+ describe 'SSRF Protection' do
5
+ let(:valid_url) { 'https://example.com/webhook' }
6
+ let(:webhook_request) { DigitalFemsa::WebhookRequest.new(url: valid_url, synchronous: false) }
7
+
8
+ describe '#url=' do
9
+ context 'with valid URLs' do
10
+ it 'allows legitimate external URLs' do
11
+ expect { webhook_request.url = 'https://api.example.com/webhook' }.not_to raise_error
12
+ end
13
+
14
+ it 'allows HTTP URLs' do
15
+ expect { webhook_request.url = 'http://api.example.com/webhook' }.not_to raise_error
16
+ end
17
+
18
+ it 'allows URLs with standard ports' do
19
+ expect { webhook_request.url = 'https://example.com:443/webhook' }.not_to raise_error
20
+ end
21
+
22
+ it 'allows URLs with non-standard but safe ports' do
23
+ expect { webhook_request.url = 'https://example.com:9443/webhook' }.not_to raise_error
24
+ end
25
+ end
26
+
27
+ context 'with localhost variations' do
28
+ it 'blocks localhost' do
29
+ expect { webhook_request.url = 'https://localhost/webhook' }
30
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
31
+ end
32
+
33
+ it 'blocks 127.0.0.1' do
34
+ expect { webhook_request.url = 'https://127.0.0.1/webhook' }
35
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
36
+ end
37
+
38
+ it 'blocks 127.0.0.0' do
39
+ expect { webhook_request.url = 'https://127.0.0.0/webhook' }
40
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
41
+ end
42
+
43
+ it 'blocks 0.0.0.0' do
44
+ expect { webhook_request.url = 'https://0.0.0.0/webhook' }
45
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
46
+ end
47
+
48
+ it 'blocks IPv6 localhost' do
49
+ expect { webhook_request.url = 'https://::1/webhook' }
50
+ .to raise_error(ArgumentError, /must be a valid URL/)
51
+ end
52
+
53
+ it 'blocks 127.0.0.2' do
54
+ expect { webhook_request.url = 'https://127.0.0.2/webhook' }
55
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
56
+ end
57
+
58
+ it 'blocks 127.1.1.1' do
59
+ expect { webhook_request.url = 'https://127.1.1.1/webhook' }
60
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
61
+ end
62
+ end
63
+
64
+ context 'with private IP ranges' do
65
+ it 'blocks 10.x.x.x range' do
66
+ expect { webhook_request.url = 'https://10.0.0.1/webhook' }
67
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
68
+ end
69
+
70
+ it 'blocks 192.168.x.x range' do
71
+ expect { webhook_request.url = 'https://192.168.1.1/webhook' }
72
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
73
+ end
74
+
75
+ it 'blocks 172.16-31.x.x range' do
76
+ expect { webhook_request.url = 'https://172.16.0.1/webhook' }
77
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
78
+ end
79
+
80
+ it 'blocks 172.31.x.x range' do
81
+ expect { webhook_request.url = 'https://172.31.0.1/webhook' }
82
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
83
+ end
84
+
85
+ it 'blocks 169.254.x.x range (link-local)' do
86
+ expect { webhook_request.url = 'https://169.254.169.254/webhook' }
87
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
88
+ end
89
+ end
90
+
91
+ context 'with internal hostnames' do
92
+ it 'blocks internal hostnames' do
93
+ expect { webhook_request.url = 'https://internal-service/webhook' }
94
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
95
+ end
96
+
97
+ it 'blocks database hostnames' do
98
+ expect { webhook_request.url = 'https://database.local/webhook' }
99
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
100
+ end
101
+
102
+ it 'blocks admin hostnames' do
103
+ expect { webhook_request.url = 'https://admin-panel/webhook' }
104
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
105
+ end
106
+
107
+ it 'blocks api-gateway hostnames' do
108
+ expect { webhook_request.url = 'https://api-gateway.internal/webhook' }
109
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
110
+ end
111
+ end
112
+
113
+ context 'with DNS rebinding services' do
114
+ it 'blocks xip.io' do
115
+ expect { webhook_request.url = 'https://127.0.0.1.xip.io/webhook' }
116
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
117
+ end
118
+
119
+ it 'blocks nip.io' do
120
+ expect { webhook_request.url = 'https://192.168.1.1.nip.io/webhook' }
121
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
122
+ end
123
+
124
+ it 'blocks localtest.me' do
125
+ expect { webhook_request.url = 'https://localtest.me/webhook' }
126
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
127
+ end
128
+ end
129
+
130
+ context 'with suspicious hostname patterns' do
131
+ it 'blocks internal- prefix' do
132
+ expect { webhook_request.url = 'https://internal-api/webhook' }
133
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
134
+ end
135
+
136
+ it 'blocks dev- prefix' do
137
+ expect { webhook_request.url = 'https://dev-service/webhook' }
138
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
139
+ end
140
+
141
+ it 'blocks db- prefix' do
142
+ expect { webhook_request.url = 'https://db-primary/webhook' }
143
+ .to raise_error(ArgumentError, /hostname points to restricted network resource/)
144
+ end
145
+ end
146
+
147
+ context 'with restricted ports' do
148
+ it 'blocks SSH port' do
149
+ expect { webhook_request.url = 'https://example.com:22/webhook' }
150
+ .to raise_error(ArgumentError, /port is not allowed/)
151
+ end
152
+
153
+ it 'blocks database ports' do
154
+ expect { webhook_request.url = 'https://example.com:3306/webhook' }
155
+ .to raise_error(ArgumentError, /port is not allowed/)
156
+ end
157
+
158
+ it 'blocks Redis port' do
159
+ expect { webhook_request.url = 'https://example.com:6379/webhook' }
160
+ .to raise_error(ArgumentError, /port is not allowed/)
161
+ end
162
+
163
+ it 'blocks Elasticsearch port' do
164
+ expect { webhook_request.url = 'https://example.com:9200/webhook' }
165
+ .to raise_error(ArgumentError, /port is not allowed/)
166
+ end
167
+
168
+ it 'blocks MongoDB port' do
169
+ expect { webhook_request.url = 'https://example.com:27017/webhook' }
170
+ .to raise_error(ArgumentError, /port is not allowed/)
171
+ end
172
+
173
+ it 'allows standard HTTP port' do
174
+ expect { webhook_request.url = 'https://example.com:80/webhook' }.not_to raise_error
175
+ end
176
+
177
+ it 'allows standard HTTPS port' do
178
+ expect { webhook_request.url = 'https://example.com:443/webhook' }.not_to raise_error
179
+ end
180
+ end
181
+
182
+ context 'with invalid schemes' do
183
+ it 'blocks ftp scheme' do
184
+ expect { webhook_request.url = 'ftp://example.com/webhook' }
185
+ .to raise_error(ArgumentError, /must use http or https scheme/)
186
+ end
187
+
188
+ it 'blocks file scheme' do
189
+ expect { webhook_request.url = 'file:///etc/passwd' }
190
+ .to raise_error(ArgumentError, /must use http or https scheme/)
191
+ end
192
+
193
+ it 'blocks missing scheme' do
194
+ expect { webhook_request.url = '//example.com/webhook' }
195
+ .to raise_error(ArgumentError, /must use http or https scheme/)
196
+ end
197
+ end
198
+
199
+ context 'with malformed URLs' do
200
+ it 'blocks invalid URL format' do
201
+ expect { webhook_request.url = 'not-a-url' }
202
+ .to raise_error(ArgumentError, /must use http or https scheme/)
203
+ end
204
+
205
+ it 'blocks empty hostname' do
206
+ expect { webhook_request.url = 'https:///webhook' }
207
+ .to raise_error(ArgumentError, /hostname cannot be empty/)
208
+ end
209
+
210
+ it 'blocks nil URL' do
211
+ expect { webhook_request.url = nil }
212
+ .to raise_error(ArgumentError, /url cannot be nil/)
213
+ end
214
+ end
215
+ end
216
+
217
+ describe '#valid?' do
218
+ it 'returns true for valid URLs' do
219
+ webhook_request.url = 'https://example.com/webhook'
220
+ expect(webhook_request.valid?).to be true
221
+ end
222
+
223
+ it 'returns false for localhost URLs' do
224
+ webhook_request.instance_variable_set(:@url, 'https://localhost/webhook')
225
+ expect(webhook_request.valid?).to be false
226
+ end
227
+
228
+ it 'returns false for private IP URLs' do
229
+ webhook_request.instance_variable_set(:@url, 'https://192.168.1.1/webhook')
230
+ expect(webhook_request.valid?).to be false
231
+ end
232
+
233
+ it 'returns false for restricted ports' do
234
+ webhook_request.instance_variable_set(:@url, 'https://example.com:22/webhook')
235
+ expect(webhook_request.valid?).to be false
236
+ end
237
+
238
+ it 'returns false for invalid schemes' do
239
+ webhook_request.instance_variable_set(:@url, 'ftp://example.com/webhook')
240
+ expect(webhook_request.valid?).to be false
241
+ end
242
+ end
243
+
244
+ describe '#list_invalid_properties' do
245
+ it 'returns empty array for valid URLs' do
246
+ webhook_request.url = 'https://example.com/webhook'
247
+ expect(webhook_request.list_invalid_properties).to be_empty
248
+ end
249
+
250
+ it 'returns error for localhost URLs' do
251
+ webhook_request.instance_variable_set(:@url, 'https://localhost/webhook')
252
+ properties = webhook_request.list_invalid_properties
253
+ expect(properties).to include(/hostname points to restricted network resource/)
254
+ end
255
+
256
+ it 'returns error for private IP URLs' do
257
+ webhook_request.instance_variable_set(:@url, 'https://192.168.1.1/webhook')
258
+ properties = webhook_request.list_invalid_properties
259
+ expect(properties).to include(/hostname points to restricted network resource/)
260
+ end
261
+
262
+ it 'returns error for restricted ports' do
263
+ webhook_request.instance_variable_set(:@url, 'https://example.com:22/webhook')
264
+ properties = webhook_request.list_invalid_properties
265
+ expect(properties).to include(/port is not allowed/)
266
+ end
267
+
268
+ it 'returns error for invalid schemes' do
269
+ webhook_request.instance_variable_set(:@url, 'ftp://example.com/webhook')
270
+ properties = webhook_request.list_invalid_properties
271
+ expect(properties).to include(/must use http or https scheme/)
272
+ end
273
+ end
274
+ end
275
+ end
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,43 @@ Generator version: 7.5.0
10
10
 
11
11
  =end
12
12
 
13
+ # Configure SimpleCov for code coverage
14
+ require 'simplecov'
15
+ require 'simplecov-json'
16
+
17
+ SimpleCov.start do
18
+ # Minimum coverage threshold
19
+ minimum_coverage 80
20
+
21
+ # Track files in the lib directory
22
+ track_files '{lib,app}/**/*.rb'
23
+
24
+ # Exclude certain files from coverage
25
+ add_filter '/spec/'
26
+ add_filter '/vendor/'
27
+ add_filter '/tasks/'
28
+ add_filter '/config/'
29
+
30
+ # Group coverage by file type
31
+ add_group 'Models', 'lib/digital_femsa/models'
32
+ add_group 'APIs', 'lib/digital_femsa/api'
33
+ add_group 'Core', 'lib/digital_femsa.rb'
34
+ add_group 'Configuration', 'lib/digital_femsa/configuration.rb'
35
+ add_group 'API Client', 'lib/digital_femsa/api_client.rb'
36
+
37
+ # Use multiple formatters
38
+ formatters = SimpleCov::Formatter::MultiFormatter.new([
39
+ SimpleCov::Formatter::HTMLFormatter,
40
+ SimpleCov::Formatter::JSONFormatter
41
+ ])
42
+ SimpleCov.formatter = formatters
43
+
44
+ # Add custom metrics
45
+ add_filter do |source_file|
46
+ source_file.lines.count < 5 # Exclude very small files
47
+ end
48
+ end
49
+
13
50
  # load the gem
14
51
  require 'digital_femsa'
15
52
 
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: digital_femsa
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - DigitalFemsa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-26 00:00:00.000000000 Z
11
+ date: 2026-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.0.1
20
- - - "<"
17
+ - - '='
21
18
  - !ruby/object:Gem::Version
22
- version: '3.0'
19
+ version: 2.14.2
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 1.0.1
30
- - - "<"
24
+ - - '='
31
25
  - !ruby/object:Gem::Version
32
- version: '3.0'
26
+ version: 2.14.2
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: faraday-multipart
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +82,7 @@ files:
88
82
  - CODE_OF_CONDUCT.md
89
83
  - CONTRIBUTING.md
90
84
  - Gemfile
85
+ - Gemfile.lock
91
86
  - LICENSE
92
87
  - Makefile
93
88
  - README.md
@@ -425,6 +420,7 @@ files:
425
420
  - spec/api/customers_api_spec.rb
426
421
  - spec/api/discounts_api_spec.rb
427
422
  - spec/api/events_api_spec.rb
423
+ - spec/api/generated_apis_coverage_spec.rb
428
424
  - spec/api/logs_api_spec.rb
429
425
  - spec/api/orders_api_spec.rb
430
426
  - spec/api/payment_link_api_spec.rb
@@ -437,6 +433,9 @@ files:
437
433
  - spec/api/transfers_api_spec.rb
438
434
  - spec/api/webhook_keys_api_spec.rb
439
435
  - spec/api/webhooks_api_spec.rb
436
+ - spec/api_client_spec.rb
437
+ - spec/models/generated_models_coverage_spec.rb
438
+ - spec/models/webhook_request_ssrf_protection_spec.rb
440
439
  - spec/spec_helper.rb
441
440
  - ssl_data/ca_bundle.crt
442
441
  - templates/ruby/CUSTOM_VERSION.mustache
@@ -466,23 +465,27 @@ signing_key:
466
465
  specification_version: 4
467
466
  summary: This library provides https://api.digitalfemsa.io operations
468
467
  test_files:
469
- - spec/api/discounts_api_spec.rb
470
- - spec/api/payment_methods_api_spec.rb
468
+ - spec/api/orders_api_spec.rb
469
+ - spec/api/products_api_spec.rb
470
+ - spec/api/generated_apis_coverage_spec.rb
471
+ - spec/api/balances_api_spec.rb
472
+ - spec/api/taxes_api_spec.rb
473
+ - spec/api/webhooks_api_spec.rb
474
+ - spec/api/shipping_contacts_api_spec.rb
471
475
  - spec/api/transfers_api_spec.rb
476
+ - spec/api/charges_api_spec.rb
472
477
  - spec/api/companies_api_spec.rb
473
- - spec/api/taxes_api_spec.rb
474
- - spec/api/webhook_keys_api_spec.rb
475
478
  - spec/api/shippings_api_spec.rb
476
- - spec/api/api_keys_api_spec.rb
477
- - spec/api/payment_link_api_spec.rb
478
- - spec/api/charges_api_spec.rb
479
- - spec/api/balances_api_spec.rb
479
+ - spec/api/customers_api_spec.rb
480
+ - spec/api/discounts_api_spec.rb
480
481
  - spec/api/logs_api_spec.rb
481
- - spec/api/webhooks_api_spec.rb
482
- - spec/api/products_api_spec.rb
483
482
  - spec/api/transactions_api_spec.rb
484
- - spec/api/shipping_contacts_api_spec.rb
485
- - spec/api/orders_api_spec.rb
486
- - spec/api/customers_api_spec.rb
483
+ - spec/api/webhook_keys_api_spec.rb
484
+ - spec/api/payment_link_api_spec.rb
487
485
  - spec/api/events_api_spec.rb
486
+ - spec/api/payment_methods_api_spec.rb
487
+ - spec/api/api_keys_api_spec.rb
488
+ - spec/api_client_spec.rb
489
+ - spec/models/generated_models_coverage_spec.rb
490
+ - spec/models/webhook_request_ssrf_protection_spec.rb
488
491
  - spec/spec_helper.rb