yes-core 2.3.0 → 2.4.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: '06386ad1e1b30ddacbb4afaf392632875023650518041e3914178427039f91f5'
4
- data.tar.gz: af40c3f3d98c611ce0653dfb0c0e2e2193376feb1ed0aeba69d43827fd6a09f9
3
+ metadata.gz: a67f053c3f41a210b9efa97b11c975194c9af6578ca5b4ba5f6de062031621c2
4
+ data.tar.gz: 9491e1f3a769af3131ca2b70d5c03746401f78adb6513868abdab14f219334a7
5
5
  SHA512:
6
- metadata.gz: e956ac8483b7a53f13009356536c221f92dc2dd6d88f6137ca4d1e6305a7c239a2870484197469243c14dca6552983d0004b263147ad6642d94c17611415cfd6
7
- data.tar.gz: 5ac3c8ea889ddf9a01efc1ac645a35c9d394736f351e1f98d9ca1dc0f5550094ded103ba424f2a8df07f24d46a082948a69e719aab3aa330d18736d0815de17a
6
+ metadata.gz: ae85c83e3178ff406651ef1f42c2fd3a4e54326f6a58290e2aa1ac4fa9dd73cff7d957124d20257809b379b5afb3ea39a441d835c04a43eb940c4fb1557df673
7
+ data.tar.gz: 7bd2ff74f1549b45c76ce29559486222b754652b59bc2d1488e8e528130784521f04f21151f562f96c0b801c8fbf5827c99d75b99515d1a46abae61c4e9ede42
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.4.0] - 2026-09-07
4
+ - See root CHANGELOG.md for details.
5
+
3
6
  ## [2.3.0] - 2026-09-03
4
7
  - See root CHANGELOG.md for details.
5
8
 
@@ -5,6 +5,10 @@ module Yes
5
5
  module Authorization
6
6
  # Provides a shared Cerbos client instance for authorizer classes.
7
7
  #
8
+ # One client (and therefore one gRPC channel) is kept per process. `Cerbos::Client` is
9
+ # thread-safe, but a gRPC channel must not be shared across a fork, so the client is
10
+ # rebuilt in each forked worker.
11
+ #
8
12
  # @example Including in a class with class-level methods
9
13
  # class MyAuthorizer
10
14
  # class << self
@@ -12,14 +16,47 @@ module Yes
12
16
  # end
13
17
  # end
14
18
  module CerbosClientProvider
19
+ class << self
20
+ # @return [Cerbos::Client] the process-wide Cerbos client
21
+ def client
22
+ mutex.synchronize do
23
+ reset! unless @client_pid == Process.pid
24
+ @client ||= build_client
25
+ end
26
+ end
27
+
28
+ # Drops the memoized client so the next call builds a new one (used after a fork and
29
+ # in tests).
30
+ # @return [void]
31
+ def reset!
32
+ @client = nil
33
+ @client_pid = Process.pid
34
+ end
35
+
36
+ private
37
+
38
+ # @return [Mutex]
39
+ def mutex
40
+ @mutex ||= Mutex.new
41
+ end
42
+
43
+ # @return [Cerbos::Client] client configured from Yes::Core configuration
44
+ def build_client
45
+ config = Yes::Core.configuration
46
+
47
+ Cerbos::Client.new(
48
+ config.cerbos_url,
49
+ tls: config.cerbos_tls,
50
+ grpc_channel_args: config.cerbos_grpc_channel_args
51
+ )
52
+ end
53
+ end
54
+
15
55
  private
16
56
 
17
- # @return [Cerbos::Client] Cerbos client configured from Yes::Core configuration
57
+ # @return [Cerbos::Client] the process-wide Cerbos client
18
58
  def cerbos_client
19
- Cerbos::Client.new(
20
- Yes::Core.configuration.cerbos_url,
21
- tls: Yes::Core.configuration.cerbos_tls
22
- )
59
+ CerbosClientProvider.client
23
60
  end
24
61
  end
25
62
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yes
4
+ module Core
5
+ module Authorization
6
+ # Default gRPC channel arguments for the Cerbos client.
7
+ #
8
+ # A Cerbos PDP pod that is killed or restarting fails an in-flight check with gRPC status
9
+ # `UNAVAILABLE` ("Stream removed", "Connection refused"). gRPC retries such calls
10
+ # transparently when the channel carries a retry policy in its service config, so the
11
+ # caller never sees a `Cerbos::Error::Unavailable` for a blip that a second attempt on a
12
+ # healthy pod would have answered.
13
+ #
14
+ # @see https://grpc.io/docs/guides/retry/
15
+ module CerbosGrpcRetryPolicy
16
+ SERVICE_NAME = 'cerbos.svc.v1.CerbosService'
17
+ MAX_ATTEMPTS = 4
18
+ INITIAL_BACKOFF = '0.1s'
19
+ MAX_BACKOFF = '1s'
20
+ BACKOFF_MULTIPLIER = 2
21
+ RETRYABLE_STATUS_CODES = %w[UNAVAILABLE].freeze
22
+
23
+ ENABLE_RETRIES_ARG = 'grpc.enable_retries'
24
+ SERVICE_CONFIG_ARG = 'grpc.service_config'
25
+
26
+ class << self
27
+ # @return [Hash{String => Integer, String}] channel arguments for `Cerbos::Client.new`
28
+ def channel_args
29
+ {
30
+ ENABLE_RETRIES_ARG => 1,
31
+ SERVICE_CONFIG_ARG => service_config.to_json
32
+ }
33
+ end
34
+
35
+ # @return [Hash] gRPC service config with the retry policy for the Cerbos service
36
+ def service_config
37
+ {
38
+ methodConfig: [
39
+ {
40
+ name: [{ service: SERVICE_NAME }],
41
+ retryPolicy: {
42
+ maxAttempts: MAX_ATTEMPTS,
43
+ initialBackoff: INITIAL_BACKOFF,
44
+ maxBackoff: MAX_BACKOFF,
45
+ backoffMultiplier: BACKOFF_MULTIPLIER,
46
+ retryableStatusCodes: RETRYABLE_STATUS_CODES
47
+ }
48
+ }
49
+ ]
50
+ }
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -45,6 +45,10 @@ module Yes
45
45
  # @return [Boolean] Whether to use TLS for Cerbos connections (default: true)
46
46
  attr_accessor :cerbos_tls
47
47
 
48
+ # @return [Hash{String => String, Integer}] low-level gRPC channel arguments for the Cerbos client
49
+ # (default: {Authorization::CerbosGrpcRetryPolicy.channel_args}, which retries UNAVAILABLE calls)
50
+ attr_accessor :cerbos_grpc_channel_args
51
+
48
52
  # @return [Boolean] Whether to include metadata in Cerbos command authorizer responses
49
53
  attr_accessor :cerbos_commands_authorizer_include_metadata
50
54
 
@@ -112,6 +116,7 @@ module Yes
112
116
  }
113
117
  @cerbos_url = ENV.fetch('CERBOS_URL', 'cerbos-cluster-ip-service:3593')
114
118
  @cerbos_tls = true
119
+ @cerbos_grpc_channel_args = Authorization::CerbosGrpcRetryPolicy.channel_args
115
120
  @cerbos_commands_authorizer_include_metadata = false
116
121
  @cerbos_read_authorizer_include_metadata = false
117
122
  @cerbos_read_authorizer_actions = %w[read]
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Yes
4
4
  module Core
5
- VERSION = '2.3.0'
5
+ VERSION = '2.4.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yes-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nico Ritsche
@@ -222,6 +222,7 @@ files:
222
222
  - lib/yes/core/aggregate/shared_read_model_rebuilder.rb
223
223
  - lib/yes/core/authentication_error.rb
224
224
  - lib/yes/core/authorization/cerbos_client_provider.rb
225
+ - lib/yes/core/authorization/cerbos_grpc_retry_policy.rb
225
226
  - lib/yes/core/authorization/command_authorizer.rb
226
227
  - lib/yes/core/authorization/command_cerbos_authorizer.rb
227
228
  - lib/yes/core/authorization/lookup_cache.rb