rox-rollout 5.1.1 → 6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae34336f9f49d2ba7a2f77003d3f537eb53bbf4cde40fff04846a4c71d9fe177
4
- data.tar.gz: d168174f3d6b72a482b89868d950e4bd8c30c908c0df6d0c11d276aceb8c229d
3
+ metadata.gz: e4cb36cd9c9f0f6d8bf17ec5eae746e232f2b52173af69bb23875ab310202fee
4
+ data.tar.gz: db305b734a05052c51e191fdf6c3c2f6ea68ed1d45302bcf772c43b44f2be25d
5
5
  SHA512:
6
- metadata.gz: be4f8985f0289f5becb88a46f13578d83982ad0b5d471c3241dd8127493cdca9d1479eae63bc87e6c13c81092a37ae63e48bedaa40b806020a497a091e0996f2
7
- data.tar.gz: f5c134a9692176e0495bbb3805799a439c14a08b5c160a61148c4affdb7e39f2699d1586e7f853e6bdd7fc43103bd9a66d17fc61b93a9b228627a92a7a6217ba
6
+ metadata.gz: 710eec50310d083d79cbf5580abcdd44c60586678947bdf39687cf6a29568f320949c935997d0ea8f3c65ced8fcbace9ad368f1a3ef48fe095e942095e222ad1
7
+ data.tar.gz: f715fdb536495f27c33449b260e77f14d7684afe24f5b0ca4f9f9689995b6c5015821e196d29092616663a72ce762f113a872e4309b8e6c1dccaf1ce7f3a42f7
@@ -8,9 +8,10 @@ gem install sinatra --conservative
8
8
  gem install sinatra-contrib --conservative
9
9
  gem install json --conservative
10
10
  gem install em-eventsource --conservative
11
+ gem install rackup
11
12
 
12
13
  nohup ruby ./server.rb $1 1>"$DIR"/log_"$1".out 2>&1 &
13
14
  while true ; do
14
15
  curl -p http://127.0.0.1:$1/status-check && exit
15
16
  sleep 1
16
- done
17
+ done
@@ -10,10 +10,11 @@ require 'rox/core/logging/logging'
10
10
  module Rox
11
11
  module Core
12
12
  class ConfigurationParser
13
- def initialize(signature_verifier, error_reporter, configuration_fetched_invoker)
13
+ def initialize(signature_verifier, error_reporter, configuration_fetched_invoker, rox_options = nil)
14
14
  @signature_verifier = signature_verifier
15
15
  @error_reporter = error_reporter
16
16
  @configuration_fetched_invoker = configuration_fetched_invoker
17
+ @rox_options = rox_options
17
18
  end
18
19
 
19
20
  def parse(fetch_result, sdk_settings)
@@ -31,8 +32,8 @@ module Rox
31
32
  return nil
32
33
  end
33
34
 
34
- if fetch_result.source != ConfigurationSource::ROXY && !@signature_verifier.verify(json_obj['data'],
35
- json_obj['signature_v0'])
35
+ if signature_verification_enabled? && fetch_result.source != ConfigurationSource::ROXY && !@signature_verifier.verify(json_obj['data'],
36
+ json_obj['signature_v0'])
36
37
  @configuration_fetched_invoker.invoke_error(FetcherError::SIGNATURE_VERIFICATION_ERROR)
37
38
  @error_reporter.report('Failed to validate signature',
38
39
  StandardError.new("Data : #{json_obj['data']} Signature : #{json_obj['signature_v0']}"))
@@ -81,6 +82,14 @@ module Rox
81
82
  def parse_target_group(data)
82
83
  TargetGroupModel.new(data['_id'], data['condition'])
83
84
  end
85
+
86
+ private
87
+
88
+ def signature_verification_enabled?
89
+ return true if @rox_options.nil?
90
+
91
+ !@rox_options.disable_signature_verification
92
+ end
84
93
  end
85
94
  end
86
95
  end
@@ -1,3 +1,5 @@
1
+ require 'rox/server/self_managed_options'
2
+
1
3
  module Rox
2
4
  module Core
3
5
  module Environment
@@ -50,6 +52,16 @@ module Rox
50
52
  @notifications_path
51
53
  end
52
54
 
55
+ def self.set_platform(rox_options)
56
+ @cdn_path = 'https://rox-conf.cloudbees.io'
57
+ @state_cdn_path = 'https://rox-state.cloudbees.io'
58
+ alternative_api_url = rox_options&.self_managed_options&.server_url || 'https://api.cloudbees.io'
59
+ @api_path = "#{alternative_api_url}/device/get_configuration"
60
+ @state_api_path = "#{alternative_api_url}/device/update_state_store"
61
+ @analytics_path = rox_options&.self_managed_options&.analytics_url || 'https://fm-analytics.cloudbees.io'
62
+ @notifications_path = 'https://sdk-notification-service.cloudbees.io/sse'
63
+ end
64
+
53
65
  private
54
66
  def self.setQA()
55
67
  @cdn_path = 'https://qa-conf.rollout.io'
@@ -75,11 +87,11 @@ module Rox
75
87
  alternative_api_url = rox_options&.self_managed_options&.server_url || 'https://x-api.rollout.io'
76
88
  @api_path = "#{alternative_api_url}/device/get_configuration"
77
89
  @state_api_path = "#{alternative_api_url}/device/update_state_store"
78
- @analytics_path = rox_options&.self_managed_options&.analytics_url ||'https://analytic.rollout.io'
90
+ @analytics_path = rox_options&.self_managed_options&.analytics_url || 'https://analytic.rollout.io'
79
91
  @notifications_path = 'https://push.rollout.io/sse'
80
92
  end
81
93
  end
82
94
  end
83
95
  end
84
96
 
85
- Rox::Core::Environment.reset
97
+ Rox::Core::Environment.reset
data/lib/rox/core/core.rb CHANGED
@@ -25,11 +25,14 @@ require 'rox/core/security/signature_verifier'
25
25
  require 'rox/core/security/signature_verifier_mock'
26
26
  require 'rox/core/utils/periodic_task'
27
27
  require 'rox/core/client/dynamic_api'
28
+ require 'rox/core/helpers/api_key'
28
29
  require 'rox/core/error_handling/userspace_unhandled_error_invoker'
29
30
 
30
31
  module Rox
31
32
  module Core
32
33
  class Core
34
+ include Rox::Core::Helpers::ApiKey
35
+
33
36
  def initialize
34
37
  @flag_repository = FlagRepository.new
35
38
  @custom_property_repository = CustomPropertyRepository.new
@@ -59,7 +62,7 @@ module Rox
59
62
  def setup(sdk_settings, device_properties)
60
63
  @sdk_settings = sdk_settings
61
64
  @rox_options = device_properties.rox_options
62
- Rox::Core::Environment.reset(@rox_options)
65
+ reset_environment!(sdk_settings&.api_key, @rox_options)
63
66
 
64
67
  experiments_extensions = ExperimentsExtensions.new(@parser, @target_group_repository, @flag_repository,
65
68
  @experiment_repository)
@@ -156,7 +159,7 @@ module Rox
156
159
  SignatureVerifier.new
157
160
  end
158
161
  configuration_parser = ConfigurationParser.new(signature_verifier, @error_reporter,
159
- @configuration_fetched_invoker)
162
+ @configuration_fetched_invoker, @rox_options)
160
163
  result = @configuration_fetcher.fetch
161
164
  return if result.nil?
162
165
 
@@ -220,12 +223,13 @@ module Rox
220
223
  @state_sender.dump_state
221
224
  end
222
225
 
223
- def validate_api_key(api_key)
224
- valid_api_key_pattern = /^[a-f\d]{24}$/
225
- if api_key&.strip&.empty?
226
- raise ArgumentError, 'Blank Rollout api key - must be specified'
227
- elsif !valid_api_key_pattern.match(api_key)
228
- raise ArgumentError, 'Illegal Rollout api key'
226
+ def reset_environment!(api_key, rox_options)
227
+ raise ArgumentError, 'Blank Feature Flag API key - must be specified' unless api_key
228
+
229
+ if is_cbp?(api_key)
230
+ Rox::Core::Environment.set_platform(rox_options)
231
+ else
232
+ Rox::Core::Environment.reset(rox_options)
229
233
  end
230
234
  end
231
235
 
@@ -43,6 +43,10 @@ module Rox
43
43
  def disabled(context)
44
44
  yield unless enabled?(context)
45
45
  end
46
+
47
+ def external_type
48
+ 'Boolean'
49
+ end
46
50
  end
47
51
  end
48
52
  end
@@ -8,6 +8,10 @@ module Rox
8
8
  send_impressions(return_value, context)
9
9
  return_value
10
10
  end
11
+
12
+ def external_type
13
+ 'Number'
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -8,6 +8,10 @@ module Rox
8
8
  send_impressions(return_value, context)
9
9
  return_value
10
10
  end
11
+
12
+ def external_type
13
+ 'Number'
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -63,6 +63,10 @@ module Rox
63
63
 
64
64
  return_value
65
65
  end
66
+
67
+ def external_type
68
+ 'String'
69
+ end
66
70
  end
67
71
  end
68
72
  end
@@ -0,0 +1,28 @@
1
+
2
+ module Rox
3
+ module Core
4
+ module Helpers
5
+ module ApiKey
6
+ MONGO_API_KEY_PATTERN = /^[a-f\d]{24}$/
7
+ UUID_API_KEY_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
8
+
9
+ def is_cbp?(api_key)
10
+ validate_api_key(api_key) && UUID_API_KEY_PATTERN.match?(api_key)
11
+ rescue ArgumentError
12
+ false
13
+ end
14
+
15
+ def validate_api_key(api_key)
16
+ if api_key&.strip&.empty?
17
+ raise ArgumentError, 'Blank Rollout api key - must be specified'
18
+ elsif !MONGO_API_KEY_PATTERN.match(api_key) && !UUID_API_KEY_PATTERN.match(api_key)
19
+ raise ArgumentError, 'Illegal Rollout api key'
20
+ else
21
+ true
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -8,10 +8,13 @@ require 'rox/core/network/request'
8
8
  require 'rox/core/network/request_data'
9
9
  require 'rox/core/network/response'
10
10
  require 'rox/core/utils/debouncer'
11
+ require 'rox/core/helpers/api_key'
11
12
 
12
13
  module Rox
13
14
  module Core
14
15
  class StateSender
16
+ include Rox::Core::Helpers::ApiKey
17
+
15
18
  def initialize(sdk_settings, device_properties, flag_repository, custom_property_repository)
16
19
  @sdk_settings = sdk_settings
17
20
  @device_properties = device_properties
@@ -27,8 +30,8 @@ module Rox
27
30
 
28
31
  def send
29
32
  rollout_key = @device_properties.rollout_key
30
- serialized_feature_flags = StateSender.seralize_flag_repository(@flag_repository)
31
- serialized_custom_properties = StateSender.serialize_custom_properties_repository(@custom_property_repository)
33
+ serialized_feature_flags = seralize_flag_repository
34
+ serialized_custom_properties = serialize_custom_properties_repository
32
35
 
33
36
  state_payload = StateSender.state_payload(serialized_feature_flags, serialized_custom_properties,
34
37
  @device_properties, @sdk_settings.dev_mode_secret)
@@ -39,7 +42,7 @@ module Rox
39
42
  response = get_state_from_CDN(rollout_key, md5_signature)
40
43
  if response.success?
41
44
  Rox::Core::Logging.logger.debug('Successfully fetched state from CDN')
42
- return
45
+ return response, nil
43
46
  else
44
47
  Rox::Core::Logging.logger.debug('Failed to fetch state from CDN. Sending state to API...')
45
48
  end
@@ -52,6 +55,7 @@ module Rox
52
55
  'Failed to send state to API.'
53
56
  end
54
57
  Rox::Core::Logging.logger.debug(message)
58
+ return response, state_payload
55
59
  end
56
60
 
57
61
  def dump_state
@@ -108,7 +112,7 @@ module Rox
108
112
  def self.seralize_flag_repository_with_values(flag_repository)
109
113
  flags = []
110
114
  flag_repository.all_flags.sort_by(&:name).each do |f|
111
- flags << {
115
+ flags << {
112
116
  name: f.name,
113
117
  enabled: f.enabled?,
114
118
  defaultValue: f.default_value,
@@ -142,6 +146,45 @@ module Rox
142
146
  end
143
147
  properties
144
148
  end
149
+
150
+ private
151
+
152
+ def cbp?
153
+ # Memoize assuming that @sdk_settings are not mutable during state sender lifetime
154
+ @cbp ||= is_cbp?(@sdk_settings&.api_key)
155
+ end
156
+
157
+ def seralize_flag_repository
158
+ flags = []
159
+ @flag_repository.all_flags.sort_by(&:name).each do |f|
160
+ flag = {
161
+ name: f.name,
162
+ defaultValue: f.default_value,
163
+ options: f.options
164
+ }
165
+
166
+ flag[:externalType] = f.external_type if cbp?
167
+
168
+ flags << flag
169
+ end
170
+ flags
171
+ end
172
+
173
+ def serialize_custom_properties_repository
174
+ properties = []
175
+ @custom_property_repository.all_custom_properties.sort_by(&:name).each do |p|
176
+ # Check not to send date custom properties to rollout
177
+ return if !is_cbp?(@sdk_settings&.api_key) && p.type.external_type == DateTime
178
+
179
+ properties << {
180
+ name: p.name,
181
+ type: p.type.type,
182
+ externalType: p.type.external_type
183
+ }
184
+ end
185
+ properties
186
+ end
187
+
145
188
  end
146
189
  end
147
190
  end
@@ -13,6 +13,7 @@ module Rox
13
13
  INT = CustomPropertyType.new('int', 'Number')
14
14
  FLOAT = CustomPropertyType.new('double', 'Number')
15
15
  SEMVER = CustomPropertyType.new('semver', 'Semver')
16
+ DATETIME = CustomPropertyType.new("time", "DateTime")
16
17
  end
17
18
  end
18
19
  end
@@ -113,6 +113,17 @@ module Rox
113
113
  )
114
114
  end
115
115
 
116
+ def internal_datetime
117
+ type = Rox::Core::CustomPropertyType::DATETIME
118
+
119
+ Rox::Core::DeviceProperty.new(
120
+ "now",
121
+ type
122
+ ) do
123
+ Time.now
124
+ end
125
+ end
126
+
116
127
  # rubocop:disable Metrics/MethodLength
117
128
  def all_properties
118
129
  [
@@ -124,7 +135,8 @@ module Rox
124
135
  internal_app_key,
125
136
  internal_distinct_id,
126
137
  internal_lib_version,
127
- internal_api_version
138
+ internal_api_version,
139
+ internal_datetime
128
140
  ]
129
141
  end
130
142
  end
@@ -169,6 +169,15 @@ module Rox
169
169
  stack.push(TokenType::UNDEFINED)
170
170
  end
171
171
  end
172
+
173
+ add_operator('tsToNum') do |_parser, stack, _context|
174
+ datetime = stack.pop
175
+ if datetime.is_a?(DateTime)
176
+ stack.push(datetime.to_time.to_i)
177
+ else
178
+ stack.push(TokenType::UNDEFINED)
179
+ end
180
+ end
172
181
  end
173
182
  end
174
183
  end
@@ -8,9 +8,9 @@ module Rox
8
8
  def extend
9
9
  @parser.add_operator('lt') do |_parser, stack, _context|
10
10
  begin
11
- op1 = stack.pop.to_f
12
- op2 = stack.pop.to_f
13
- stack.push(op1 < op2)
11
+ op1 = stack.pop
12
+ op2 = stack.pop
13
+ stack.push(op1.to_f < op2.to_f)
14
14
  rescue StandardError
15
15
  stack.push(false)
16
16
  end
@@ -18,9 +18,9 @@ module Rox
18
18
 
19
19
  @parser.add_operator('lte') do |_parser, stack, _context|
20
20
  begin
21
- op1 = stack.pop.to_f
22
- op2 = stack.pop.to_f
23
- stack.push(op1 <= op2)
21
+ op1 = stack.pop
22
+ op2 = stack.pop
23
+ stack.push(op1.to_f <= op2.to_f)
24
24
  rescue StandardError
25
25
  stack.push(false)
26
26
  end
@@ -28,9 +28,9 @@ module Rox
28
28
 
29
29
  @parser.add_operator('gt') do |_parser, stack, _context|
30
30
  begin
31
- op1 = stack.pop.to_f
32
- op2 = stack.pop.to_f
33
- stack.push(op1 > op2)
31
+ op1 = stack.pop
32
+ op2 = stack.pop
33
+ stack.push(op1.to_f > op2.to_f)
34
34
  rescue StandardError
35
35
  stack.push(false)
36
36
  end
@@ -38,9 +38,9 @@ module Rox
38
38
 
39
39
  @parser.add_operator('gte') do |_parser, stack, _context|
40
40
  begin
41
- op1 = stack.pop.to_f
42
- op2 = stack.pop.to_f
43
- stack.push(op1 >= op2)
41
+ op1 = stack.pop
42
+ op2 = stack.pop
43
+ stack.push(op1.to_f >= op2.to_f)
44
44
  rescue StandardError
45
45
  stack.push(false)
46
46
  end
@@ -48,9 +48,9 @@ module Rox
48
48
 
49
49
  @parser.add_operator('numne') do |_parser, stack, _context|
50
50
  begin
51
- op1 = stack.pop.to_f
52
- op2 = stack.pop.to_f
53
- stack.push(op1 != op2)
51
+ op1 = stack.pop
52
+ op2 = stack.pop
53
+ stack.push(op1.to_f != op2.to_f)
54
54
  rescue StandardError
55
55
  stack.push(false)
56
56
  end
@@ -58,9 +58,9 @@ module Rox
58
58
 
59
59
  @parser.add_operator('numeq') do |_parser, stack, _context|
60
60
  begin
61
- op1 = stack.pop.to_f
62
- op2 = stack.pop.to_f
63
- stack.push(op1 == op2)
61
+ op1 = stack.pop
62
+ op2 = stack.pop
63
+ stack.push(op1.to_f == op2.to_f)
64
64
  rescue StandardError
65
65
  stack.push(false)
66
66
  end
@@ -1,15 +1,19 @@
1
1
  require 'rox/core/logging/logging'
2
2
  require 'rox/server/logging/server_logger'
3
+ require 'rox/core/helpers/api_key'
3
4
 
4
5
  module Rox
5
6
  module Server
6
7
  class RoxOptions
8
+ include Rox::Core::Helpers::ApiKey
9
+
7
10
  attr_reader :dev_mode_key, :version, :fetch_interval,
8
11
  :logger, :impression_handler,
9
12
  :configuration_fetched_handler,
10
13
  :roxy_url, :self_managed_options,
11
14
  :network_configurations_options,
12
- :dynamic_property_rule_handler
15
+ :dynamic_property_rule_handler,
16
+ :disable_signature_verification
13
17
 
14
18
  def initialize(
15
19
  dev_mode_key: nil,
@@ -21,7 +25,8 @@ module Rox
21
25
  roxy_url: nil,
22
26
  self_managed_options: nil,
23
27
  network_configurations_options: nil,
24
- dynamic_property_rule_handler: nil
28
+ dynamic_property_rule_handler: nil,
29
+ disable_signature_verification: nil
25
30
  )
26
31
  @dev_mode_key = dev_mode_key || 'stam'
27
32
  @version = version || '0.0'
@@ -42,11 +47,43 @@ module Rox
42
47
  @dynamic_property_rule_handler = dynamic_property_rule_handler || proc do |prop_name, context|
43
48
  context ? context[prop_name] : nil
44
49
  end
50
+ @disable_signature_verification = disable_signature_verification
45
51
  end
46
52
 
47
53
  def self_managed?
48
54
  !@self_managed_options.nil?
49
55
  end
56
+
57
+ def clone_with_options(options = {})
58
+ # Check if any keys that are not present as attributes were given as params
59
+ redundant_keys = options.keys - valid_attributes
60
+
61
+ # Filter options if there are such keys that are not present
62
+ if !redundant_keys.empty?
63
+ options = options.reduce({}) do |acc, (key, value)|
64
+ acc[key] = value unless redundant_keys.include?(key)
65
+ acc
66
+ end
67
+ end
68
+
69
+ valid_attributes.each do |va|
70
+ unless options.key?(va)
71
+ options[va] = self.instance_variable_get("@#{va}".to_sym)
72
+ end
73
+ end
74
+
75
+ self.class.new(**options)
76
+ end
77
+
78
+ private
79
+
80
+ def valid_attributes
81
+ return @valid_attributes if @valid_attributes
82
+
83
+ cons = self.class.instance_method(:initialize)
84
+ key_parameters = cons.parameters.select { |type, name| type == :keyreq || type == :key }
85
+ @valid_attributes = key_parameters.map(&:last)
86
+ end
50
87
  end
51
88
  end
52
89
  end
@@ -14,9 +14,20 @@ module Rox
14
14
 
15
15
  class << self
16
16
  def setup(api_key, rox_options = nil)
17
- validate_api_key(api_key)
18
-
19
- rox_options = Rox::Server::RoxOptions.new if rox_options.nil?
17
+ # @core.setup calls validate_api_key internally anyway, but it will happen in another thread
18
+ # because of the report_on_exception code below (which might effect older [maybe not supported Ruby versions])
19
+ # decided to call it explicity here too (to keep the current behavor)
20
+ # anyway, this also short circuit the initialization (no need for the initialization and Thread.new)
21
+ # and only costs us calling the validation twice instead of once
22
+ @core.validate_api_key(api_key)
23
+
24
+ rox_options = if rox_options.nil?
25
+ Rox::Server::RoxOptions.new(disable_signature_verification: @core.is_cbp?(api_key))
26
+ else
27
+ rox_options = rox_options.clone_with_options({
28
+ disable_signature_verification: @core.is_cbp?(api_key) || rox_options.disable_signature_verification
29
+ })
30
+ end
20
31
  sdk_settings = Rox::Server::SdkSettings.new(api_key, rox_options.dev_mode_key)
21
32
  server_properties = Rox::Server::ServerProperties.new(sdk_settings, rox_options)
22
33
 
@@ -93,6 +104,12 @@ module Rox
93
104
  &block))
94
105
  end
95
106
 
107
+ def set_custom_datetime_property(name, value = nil, &block)
108
+ @core.add_custom_property(
109
+ Rox::Core::CustomProperty.new(name, Rox::Core::CustomPropertyType::DATETIME, value, &block)
110
+ )
111
+ end
112
+
96
113
  def dynamic_api
97
114
  @core.dynamic_api(Rox::Server::ServerEntitiesProvider.new)
98
115
  end
@@ -100,14 +117,6 @@ module Rox
100
117
  def dump_state
101
118
  @core.dump_state
102
119
  end
103
-
104
- private
105
-
106
- def validate_api_key(api_key)
107
- raise ArgumentError, 'api_key is not valid' if (api_key =~ /^[a-f\d]{24}$/).nil?
108
-
109
- true
110
- end
111
120
  end
112
121
  end
113
122
  end
data/lib/rox/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rox
2
- VERSION = '5.1.1'.freeze
2
+ VERSION = '6.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rox-rollout
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - CloudBees
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-08 00:00:00.000000000 Z
11
+ date: 2024-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-eventsource
@@ -168,6 +168,7 @@ files:
168
168
  - lib/rox/core/error_handling/exception_trigger.rb
169
169
  - lib/rox/core/error_handling/userspace_handler_exception.rb
170
170
  - lib/rox/core/error_handling/userspace_unhandled_error_invoker.rb
171
+ - lib/rox/core/helpers/api_key.rb
171
172
  - lib/rox/core/impression/impression_args.rb
172
173
  - lib/rox/core/impression/impression_invoker.rb
173
174
  - lib/rox/core/impression/models/experiment.rb
@@ -247,7 +248,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
247
248
  - !ruby/object:Gem::Version
248
249
  version: '0'
249
250
  requirements: []
250
- rubygems_version: 3.4.7
251
+ rubygems_version: 3.5.14
251
252
  signing_key:
252
253
  specification_version: 4
253
254
  summary: Feature Management ROX Ruby SDK