avro_turf 1.17.0 → 1.19.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22e1ca443d93f4f1c38b9626ad1a83db6352a4aac397256a8a3bfae2ca462d9c
4
- data.tar.gz: 2621ae9378b2511cee81522247c5f4df883ee9c25efe92839cdc5af22543bc1f
3
+ metadata.gz: fffcc17349a4bbbcaa1204610da74800c9a519d4774af83c7059c47bb75efb1b
4
+ data.tar.gz: e5afce0fa557da110a0dd1fe73add073f994a72bb8e3a1e37865a3393f864c2b
5
5
  SHA512:
6
- metadata.gz: 56f2e3885be65423da7be65fe067151b3fd270ce13af76455a0f71cccbf6d68b09661e75f882c50ea9745f9cdc21e78ce8bd527d8123fa4b0c094dfaf6baa03a
7
- data.tar.gz: 4b8e92503870f8c83c8af5457786da3c83823706d957a96986488f2800166ae02846141e9eeb28c261c6b0e0f5d7922244f65dfb47e39bbc96a9a29fea075e55
6
+ metadata.gz: 06aac90715b06f0fdf04918ba73c2533a0cad0b9dff769e1bfc30a1488e0916fc3b38c8f4bee6efab5d667688bd9d407330c603f209ead30d67cb13b3b46c4a5
7
+ data.tar.gz: 1a3c95047a2522914394b181eaf01afaee84547d64a72d1aebe3534252f49168cebec0cf7edda8bc8a62f769dd22294eb3916d317a71a65305cb6c46ffba84ad
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v1.19.0
6
+
7
+ - Loosen excon dependency to allow 1.x (#220)
8
+
9
+ ## v1.18.0
10
+
11
+ - Add `compatibility_issues` method to `ConfluentSchemaRegistry` to debug compatibility issues between a schema versions for a given subject (#212)
12
+ - Update tests to support `sinatra` version 4.1 that includes a new `host_authorization` parameter to permit only authorized requests
13
+
5
14
  ## v1.17.0
6
15
 
7
16
  - Add `register_schemas` option to `encode` method [#210](https://github.com/dasch/avro_turf/pull/210)
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in avro_turf.gemspec
4
4
  gemspec
5
+
6
+ gem 'gem-release'
data/README.md CHANGED
@@ -254,6 +254,9 @@ registry = AvroTurf::ConfluentSchemaRegistry.new("http://my-registry:8081/")
254
254
 
255
255
  # Returns true if the schema is compatible, nil if the subject or version is not registered, and false if incompatible.
256
256
  registry.compatible?("person", schema)
257
+
258
+ # Returns an array of any breaking changes, nil if the subject or version is not registered
259
+ registry.compatibility_issues("person", schema)
257
260
  ```
258
261
 
259
262
  The ConfluentSchemaRegistry client can also change the global compatibility level or the compatibility level for an individual subject using the [Config API](http://docs.confluent.io/3.1.2/schema-registry/docs/api.html#config):
@@ -270,17 +273,23 @@ fake schema registry server depends on Sinatra but it is _not_ listed as a runti
270
273
  dependency for AvroTurf. Sinatra must be added to your Gemfile or gemspec in order
271
274
  to use the fake server.
272
275
 
276
+ Given the recent update in `sinatra` to fix [CVE-2024-21510](https://github.com/advisories/GHSA-hxx2-7vcw-mqr3) that included a new `HostAuthorization` middleware, the `FakeConfluentSchemaRegistryServer` is provided as a base implementation that has to be inherited into a new class and configured by the user so requests are properly authorised to the test registry host.
277
+
273
278
  Example using RSpec:
274
279
 
275
280
  ```ruby
276
281
  require 'avro_turf/test/fake_confluent_schema_registry_server'
277
282
  require 'webmock/rspec'
278
283
 
284
+ class AuthorizedFakeConfluentSchemaRegistryServer < FakeConfluentSchemaRegistryServer
285
+ set :host_authorization, permitted_hosts: ['registry.example.com']
286
+ end
287
+
279
288
  # within an example
280
289
  let(:registry_url) { "http://registry.example.com" }
281
290
  before do
282
- stub_request(:any, /^#{registry_url}/).to_rack(FakeConfluentSchemaRegistryServer)
283
- FakeConfluentSchemaRegistryServer.clear
291
+ stub_request(:any, /^#{registry_url}/).to_rack(AuthorizedFakeConfluentSchemaRegistryServer)
292
+ AuthorizedFakeConfluentSchemaRegistryServer.clear
284
293
  end
285
294
 
286
295
  # Messaging objects created with the same registry_url will now use the fake server.
data/avro_turf.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ["lib"]
21
21
 
22
22
  spec.add_dependency "avro", ">= 1.11.3", "< 1.13"
23
- spec.add_dependency "excon", "~> 0.104"
23
+ spec.add_dependency "excon", ">= 0.104", "< 2"
24
24
 
25
25
  spec.add_development_dependency "bundler", "~> 2.0"
26
26
  spec.add_development_dependency "rake", "~> 13.0"
@@ -18,7 +18,8 @@ class AvroTurf::ConfluentSchemaRegistry
18
18
  client_key_data: nil,
19
19
  path_prefix: nil,
20
20
  connect_timeout: nil,
21
- resolv_resolver: nil
21
+ resolv_resolver: nil,
22
+ retry_limit: nil
22
23
  )
23
24
  @path_prefix = path_prefix
24
25
  @schema_context_prefix = schema_context.nil? ? '' : ":.#{schema_context}:"
@@ -27,20 +28,26 @@ class AvroTurf::ConfluentSchemaRegistry
27
28
  headers = Excon.defaults[:headers].merge(
28
29
  "Content-Type" => CONTENT_TYPE
29
30
  )
30
- headers[:proxy] = proxy unless proxy.nil?
31
- @connection = Excon.new(
32
- url,
31
+ params = {
33
32
  headers: headers,
34
33
  user: user,
35
34
  password: password,
35
+ proxy: proxy,
36
36
  ssl_ca_file: ssl_ca_file,
37
37
  client_cert: client_cert,
38
38
  client_key: client_key,
39
39
  client_key_pass: client_key_pass,
40
40
  client_cert_data: client_cert_data,
41
41
  client_key_data: client_key_data,
42
+ resolv_resolver: resolv_resolver,
42
43
  connect_timeout: connect_timeout,
43
- resolv_resolver: resolv_resolver
44
+ retry_limit: retry_limit
45
+ }
46
+ # Remove nil params to allow Excon to use its default values
47
+ params.reject! { |_, v| v.nil? }
48
+ @connection = Excon.new(
49
+ url,
50
+ params
44
51
  )
45
52
  end
46
53
 
@@ -101,6 +108,18 @@ class AvroTurf::ConfluentSchemaRegistry
101
108
  data.fetch('is_compatible', false) unless data.has_key?('error_code')
102
109
  end
103
110
 
111
+ # Check for specific schema compatibility issues
112
+ # Returns:
113
+ # - nil if the subject or version does not exist
114
+ # - a list of compatibility issues
115
+ # https://docs.confluent.io/platform/current/schema-registry/develop/api.html#sr-api-compatibility
116
+ def compatibility_issues(subject, schema, version = 'latest')
117
+ data = post("/compatibility/subjects/#{@schema_context_prefix}#{subject}/versions/#{version}",
118
+ expects: [200, 404], body: { schema: schema.to_s }.to_json, query: { verbose: true }, idempotent: true)
119
+
120
+ data.fetch('messages', []) unless data.has_key?('error_code')
121
+ end
122
+
104
123
  # Get global config
105
124
  def global_config
106
125
  get("/config", idempotent: true)
@@ -10,6 +10,7 @@ require 'avro_turf/schema_registry'
10
10
  require 'avro_turf/cached_schema_registry'
11
11
 
12
12
  class AvroTurf
13
+ class IncompatibleSchemaError < StandardError; end
13
14
 
14
15
  # Provides a way to encode and decode messages without having to embed schemas
15
16
  # in the encoded data. Confluent's Schema Registry[1] is used to register
@@ -77,7 +78,8 @@ class AvroTurf
77
78
  client_cert_data: nil,
78
79
  client_key_data: nil,
79
80
  connect_timeout: nil,
80
- resolv_resolver: nil
81
+ resolv_resolver: nil,
82
+ retry_limit: nil
81
83
  )
82
84
  @logger = logger || Logger.new($stderr)
83
85
  @namespace = namespace
@@ -98,7 +100,8 @@ class AvroTurf
98
100
  client_key_data: client_key_data,
99
101
  path_prefix: registry_path_prefix,
100
102
  connect_timeout: connect_timeout,
101
- resolv_resolver: resolv_resolver
103
+ resolv_resolver: resolv_resolver,
104
+ retry_limit: retry_limit
102
105
  )
103
106
  )
104
107
  @schemas_by_id = {}
@@ -216,11 +219,15 @@ class AvroTurf
216
219
  end
217
220
 
218
221
  # Providing subject and version to determine the schema,
219
- # which skips the auto registeration of schema on the schema registry.
222
+ # which skips the auto registration of schema on the schema registry.
220
223
  # Fetch the schema from registry with the provided subject name and version.
221
224
  def fetch_schema(subject:, version: 'latest')
222
225
  schema_data = @registry.subject_version(subject, version)
223
226
  schema_id = schema_data.fetch('id')
227
+ schema_type = schema_data['schemaType']
228
+ if schema_type && schema_type != "AVRO"
229
+ raise IncompatibleSchemaError, "The #{schema_type} schema for #{subject} is incompatible."
230
+ end
224
231
  schema = Avro::Schema.parse(schema_data.fetch('schema'))
225
232
  [schema, schema_id]
226
233
  end
@@ -92,6 +92,6 @@ class AvroTurf::SchemaStore
92
92
 
93
93
  def build_schema_path(fullname)
94
94
  *namespace, schema_name = fullname.split(".")
95
- schema_path = File.join(@path, *namespace, schema_name + ".avsc")
95
+ File.join(@path, *namespace, "#{schema_name}.avsc")
96
96
  end
97
97
  end
@@ -1,3 +1,3 @@
1
1
  class AvroTurf
2
- VERSION = "1.17.0"
2
+ VERSION = "1.19.0"
3
3
  end
@@ -1,7 +1,5 @@
1
1
  require 'webmock/rspec'
2
2
  require 'avro_turf/messaging'
3
- require 'avro_turf/test/fake_confluent_schema_registry_server'
4
- require 'avro_turf/test/fake_prefixed_confluent_schema_registry_server'
5
3
 
6
4
  describe AvroTurf::Messaging do
7
5
  let(:registry_url) { "http://registry.example.com" }
@@ -61,8 +59,8 @@ describe AvroTurf::Messaging do
61
59
  end
62
60
 
63
61
  before do
64
- stub_request(:any, /^#{registry_url}/).to_rack(FakeConfluentSchemaRegistryServer)
65
- FakeConfluentSchemaRegistryServer.clear
62
+ stub_request(:any, /^#{registry_url}/).to_rack(AuthorizedFakeConfluentSchemaRegistryServer)
63
+ AuthorizedFakeConfluentSchemaRegistryServer.clear
66
64
  end
67
65
 
68
66
  before do
@@ -379,6 +377,18 @@ describe AvroTurf::Messaging do
379
377
  it 'gets schema from registry' do
380
378
  expect(subject).to eq([schema, schema_id])
381
379
  end
380
+
381
+ context "with an incompatible schema type" do
382
+ let(:response) { {'id' => schema_id, 'schema' => 'blah', 'schemaType' => schema_type } }
383
+ let(:schema_type) { 'PROTOBUF' }
384
+
385
+ it 'raises IncompatibleSchemaError' do
386
+ expect { subject }.to raise_error(
387
+ AvroTurf::IncompatibleSchemaError,
388
+ "The #{schema_type} schema for #{subj} is incompatible."
389
+ )
390
+ end
391
+ end
382
392
  end
383
393
 
384
394
  context 'using fetch_schema_by_id' do
@@ -474,8 +484,8 @@ describe AvroTurf::Messaging do
474
484
  }
475
485
 
476
486
  before do
477
- stub_request(:any, /^#{registry_url}/).to_rack(FakePrefixedConfluentSchemaRegistryServer)
478
- FakePrefixedConfluentSchemaRegistryServer.clear
487
+ stub_request(:any, /^#{registry_url}/).to_rack(AuthorizedFakePrefixedConfluentSchemaRegistryServer)
488
+ AuthorizedFakePrefixedConfluentSchemaRegistryServer.clear
479
489
  end
480
490
 
481
491
  it_behaves_like "encoding and decoding with the schema from schema store"
@@ -506,6 +516,54 @@ describe AvroTurf::Messaging do
506
516
  end
507
517
  end
508
518
 
519
+ context 'with a connect timeout' do
520
+ let(:avro) {
521
+ AvroTurf::Messaging.new(
522
+ registry_url: registry_url,
523
+ schemas_path: "spec/schemas",
524
+ logger: logger,
525
+ client_cert: client_cert,
526
+ client_key: client_key,
527
+ client_key_pass: client_key_pass,
528
+ retry_limit: 5
529
+ )
530
+ }
531
+
532
+ it_behaves_like "encoding and decoding with the schema from schema store"
533
+ it_behaves_like 'encoding and decoding with the schema from registry'
534
+ it_behaves_like 'encoding and decoding with the schema_id from registry'
535
+
536
+ it 'passes the connect timeout setting to Excon' do
537
+ expect(Excon).to receive(:new).with(anything, hash_including(retry_limit: 5)).and_call_original
538
+ avro
539
+ end
540
+ end
541
+
542
+ context 'with a proxy' do
543
+ let(:proxy_url) { 'http://proxy.example.com' }
544
+ let(:avro) {
545
+ AvroTurf::Messaging.new(
546
+ registry_url: registry_url,
547
+ schemas_path: "spec/schemas",
548
+ logger: logger,
549
+ client_cert: client_cert,
550
+ client_key: client_key,
551
+ client_key_pass: client_key_pass,
552
+ proxy: proxy_url
553
+ )
554
+ }
555
+
556
+ it_behaves_like "encoding and decoding with the schema from schema store"
557
+ it_behaves_like 'encoding and decoding with the schema from registry'
558
+ it_behaves_like 'encoding and decoding with the schema_id from registry'
559
+
560
+ it 'passes the proxy setting to Excon' do
561
+ expect(Excon).to receive(:new).with(anything, hash_including(proxy: proxy_url)).and_call_original
562
+ avro
563
+ end
564
+ end
565
+
566
+
509
567
  context 'with a custom domain name resolver' do
510
568
  let(:resolv_resolver) { Resolv.new([Resolv::Hosts.new, Resolv::DNS.new(nameserver: ['127.0.0.1', '127.0.0.1'])]) }
511
569
  let(:avro) {
@@ -0,0 +1,5 @@
1
+ require 'avro_turf/test/fake_confluent_schema_registry_server'
2
+
3
+ class AuthorizedFakeConfluentSchemaRegistryServer < FakeConfluentSchemaRegistryServer
4
+ set :host_authorization, permitted_hosts: ['example.org', 'registry.example.com']
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'avro_turf/test/fake_prefixed_confluent_schema_registry_server'
2
+
3
+ class AuthorizedFakePrefixedConfluentSchemaRegistryServer < FakePrefixedConfluentSchemaRegistryServer
4
+ set :host_authorization, permitted_hosts: ['example.org', 'registry.example.com']
5
+ end
@@ -18,7 +18,7 @@ shared_examples_for "a confluent schema registry client" do |schema_context: nil
18
18
  {
19
19
  'Accept'=>'*/*',
20
20
  'Content-Type'=> AvroTurf::ConfluentSchemaRegistry::CONTENT_TYPE,
21
- 'Host'=> "#{URI.parse(registry_url).host}:80",
21
+ 'Host'=> "#{URI.parse(registry_url).host}",
22
22
  'User-Agent'=> "excon/#{Excon::VERSION}"
23
23
  }
24
24
  end
@@ -26,9 +26,9 @@ shared_examples_for "a confluent schema registry client" do |schema_context: nil
26
26
  before do
27
27
  stub_request(:any, /^#{registry_url}/)
28
28
  .with(headers: headers)
29
- .to_rack(FakeConfluentSchemaRegistryServer)
29
+ .to_rack(AuthorizedFakeConfluentSchemaRegistryServer)
30
30
 
31
- FakeConfluentSchemaRegistryServer.clear
31
+ AuthorizedFakeConfluentSchemaRegistryServer.clear
32
32
  end
33
33
 
34
34
  describe "#register and #fetch" do
@@ -1,10 +1,9 @@
1
1
  require 'rack/test'
2
- require 'avro_turf/test/fake_confluent_schema_registry_server'
3
2
 
4
3
  describe FakeConfluentSchemaRegistryServer do
5
4
  include Rack::Test::Methods
6
5
 
7
- def app; described_class; end
6
+ def app; AuthorizedFakeConfluentSchemaRegistryServer; end
8
7
 
9
8
  describe 'POST /subjects/:subject/versions' do
10
9
  it 'returns the same schema ID when invoked with same schema and same subject' do
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avro_turf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schierbeck
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-08-26 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: avro
@@ -34,16 +33,22 @@ dependencies:
34
33
  name: excon
35
34
  requirement: !ruby/object:Gem::Requirement
36
35
  requirements:
37
- - - "~>"
36
+ - - ">="
38
37
  - !ruby/object:Gem::Version
39
38
  version: '0.104'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '2'
40
42
  type: :runtime
41
43
  prerelease: false
42
44
  version_requirements: !ruby/object:Gem::Requirement
43
45
  requirements:
44
- - - "~>"
46
+ - - ">="
45
47
  - !ruby/object:Gem::Version
46
48
  version: '0.104'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '2'
47
52
  - !ruby/object:Gem::Dependency
48
53
  name: bundler
49
54
  requirement: !ruby/object:Gem::Requirement
@@ -170,7 +175,6 @@ dependencies:
170
175
  - - ">="
171
176
  - !ruby/object:Gem::Version
172
177
  version: '0'
173
- description:
174
178
  email:
175
179
  - dasch@zendesk.com
176
180
  executables: []
@@ -236,6 +240,8 @@ files:
236
240
  - spec/schema_store_spec.rb
237
241
  - spec/schema_to_avro_patch_spec.rb
238
242
  - spec/spec_helper.rb
243
+ - spec/support/authorized_fake_confluent_schema_registry_server.rb
244
+ - spec/support/authorized_fake_prefixed_confluent_schema_registry_server.rb
239
245
  - spec/support/confluent_schema_registry_context.rb
240
246
  - spec/test/fake_confluent_schema_registry_server_spec.rb
241
247
  homepage: https://github.com/dasch/avro_turf
@@ -266,8 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
272
  - !ruby/object:Gem::Version
267
273
  version: '0'
268
274
  requirements: []
269
- rubygems_version: 3.5.11
270
- signing_key:
275
+ rubygems_version: 3.6.9
271
276
  specification_version: 4
272
277
  summary: A library that makes it easier to use the Avro serialization format from
273
278
  Ruby
@@ -290,5 +295,7 @@ test_files:
290
295
  - spec/schema_store_spec.rb
291
296
  - spec/schema_to_avro_patch_spec.rb
292
297
  - spec/spec_helper.rb
298
+ - spec/support/authorized_fake_confluent_schema_registry_server.rb
299
+ - spec/support/authorized_fake_prefixed_confluent_schema_registry_server.rb
293
300
  - spec/support/confluent_schema_registry_context.rb
294
301
  - spec/test/fake_confluent_schema_registry_server_spec.rb