ibm_appconfiguration_ruby_sdk 0.1.0.pre.rc.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/CONTRIBUTING.md +9 -0
- data/LICENSE +201 -0
- data/README.md +474 -0
- data/Rakefile +8 -0
- data/examples/README.md +60 -0
- data/examples/app.rb +104 -0
- data/lib/ibm_appconfiguration_ruby_sdk/app_configuration.rb +291 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/configuration_handler.rb +828 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/constants.rb +89 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/file_manager.rb +72 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/logger.rb +98 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb +284 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/config_fetcher.rb +254 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/utils.rb +240 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/connection_manager.rb +501 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/connectivity.rb +30 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/driver_socket.rb +28 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/retry_policy.rb +42 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/state.rb +24 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/watchdog.rb +50 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/websocket_client.rb +43 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/models/feature.rb +121 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/models/property.rb +107 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/models/rule.rb +87 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/models/secret_property.rb +81 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/models/segment.rb +39 -0
- data/lib/ibm_appconfiguration_ruby_sdk/configurations/models/segment_rules.rb +57 -0
- data/lib/ibm_appconfiguration_ruby_sdk/core/api_manager.rb +269 -0
- data/lib/ibm_appconfiguration_ruby_sdk/core/metering.rb +400 -0
- data/lib/ibm_appconfiguration_ruby_sdk/core/url_builder.rb +252 -0
- data/lib/ibm_appconfiguration_ruby_sdk/version.rb +20 -0
- data/lib/ibm_appconfiguration_ruby_sdk.rb +20 -0
- data/sig/ibm_appconfiguration_ruby_sdk.rbs +4 -0
- metadata +209 -0
data/lib/ibm_appconfiguration_ruby_sdk/configurations/internal/websocket_client/websocket_client.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 IBM Corp. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative "connection_manager"
|
|
18
|
+
|
|
19
|
+
class WebSocketClient
|
|
20
|
+
def initialize(region:, guid:, apikey:, collection_id:, environment_id:, start_background_retry: false)
|
|
21
|
+
@manager =
|
|
22
|
+
ConnectionManager.new(
|
|
23
|
+
region: region,
|
|
24
|
+
guid: guid,
|
|
25
|
+
apikey: apikey,
|
|
26
|
+
collection_id: collection_id,
|
|
27
|
+
environment_id: environment_id,
|
|
28
|
+
start_background_retry: start_background_retry
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def connect
|
|
33
|
+
@manager.connect
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def disconnect
|
|
37
|
+
@manager.disconnect
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def connected?
|
|
41
|
+
@manager.connected?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 IBM Corp. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative "../internal/constants"
|
|
18
|
+
require_relative "../internal/logger"
|
|
19
|
+
|
|
20
|
+
# Feature model for App Configuration service
|
|
21
|
+
class Feature
|
|
22
|
+
attr_reader :name, :feature_id, :type, :format, :disabled_value, :enabled_value,
|
|
23
|
+
:enabled, :rollout_type, :rollout_percentage, :rollout_configuration,
|
|
24
|
+
:segment_rules, :experiment
|
|
25
|
+
|
|
26
|
+
# @param feature [Hash] Feature configuration hash
|
|
27
|
+
def initialize(feature)
|
|
28
|
+
@name = feature[:name]
|
|
29
|
+
@feature_id = feature[:feature_id]
|
|
30
|
+
@type = feature[:type]
|
|
31
|
+
@format = feature[:format]
|
|
32
|
+
@disabled_value = feature[:disabled_value]
|
|
33
|
+
@enabled_value = feature[:enabled_value]
|
|
34
|
+
@enabled = feature[:enabled]
|
|
35
|
+
@rollout_type = feature.key?(:rollout_type) ? feature[:rollout_type] : Constants::MANUAL
|
|
36
|
+
|
|
37
|
+
if feature[:rollout_configuration]
|
|
38
|
+
@rollout_configuration = feature[:rollout_configuration]
|
|
39
|
+
else
|
|
40
|
+
@rollout_percentage = feature.key?(:rollout_percentage) ? feature[:rollout_percentage] : 100
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@segment_rules = feature[:segment_rules]
|
|
44
|
+
@experiment = feature[:experiment]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @return [String] Feature name
|
|
48
|
+
def get_feature_name
|
|
49
|
+
@name || ""
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [String] Feature ID
|
|
53
|
+
def get_feature_id
|
|
54
|
+
@feature_id || ""
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @return [String] Feature data type (BOOLEAN/STRING/NUMERIC)
|
|
58
|
+
def get_feature_data_type
|
|
59
|
+
@type || ""
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [String, nil] Feature data format (TEXT/JSON/YAML)
|
|
63
|
+
def get_feature_data_format
|
|
64
|
+
@format = "TEXT" if @format.nil? && @type == "STRING"
|
|
65
|
+
@format
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @return [Boolean] Feature enabled state
|
|
69
|
+
def is_enabled?
|
|
70
|
+
@enabled
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
##
|
|
74
|
+
# Evaluates and returns feature value for entity.
|
|
75
|
+
# Returns a hash containing evaluated value, enabled status & detailed reason.
|
|
76
|
+
#
|
|
77
|
+
# @param entity_id [String] Id of the Entity.
|
|
78
|
+
# This will be a string identifier related to the Entity against which the feature is evaluated.
|
|
79
|
+
# For example, an entity might be an instance of an app that runs on a mobile device, a microservice
|
|
80
|
+
# that runs on the cloud, or a component of infrastructure that runs that microservice.
|
|
81
|
+
# For any entity to interact with App Configuration, it must provide a unique entity ID.
|
|
82
|
+
#
|
|
83
|
+
# @param entity_attributes [Hash] A hash consisting of the attribute name and their values that defines
|
|
84
|
+
# the specified entity. This is an optional parameter if the feature flag is not configured with any
|
|
85
|
+
# targeting definition. If the targeting is configured, then entity_attributes should be provided for
|
|
86
|
+
# the rule evaluation. An attribute is a parameter that is used to define a segment. The SDK uses the
|
|
87
|
+
# attribute values to determine if the specified entity satisfies the targeting rules, and returns the
|
|
88
|
+
# appropriate feature flag value.
|
|
89
|
+
#
|
|
90
|
+
# @return [Hash, nil] Returns a hash containing evaluated value, enabled status & detailed reason.
|
|
91
|
+
# The evaluated value will be one of Enabled/Disabled/Overridden value based on the evaluation.
|
|
92
|
+
# The data type of evaluated value matches that of feature flag.
|
|
93
|
+
# Returns nil if entity_id is invalid.
|
|
94
|
+
#
|
|
95
|
+
# @example
|
|
96
|
+
# feature = app_config_client.get_feature('discount')
|
|
97
|
+
# if feature
|
|
98
|
+
# result = feature.get_current_value(entity_id, entity_attributes)
|
|
99
|
+
#
|
|
100
|
+
# # Access the evaluated value, enabled status & details as shown below
|
|
101
|
+
# # result[:value]
|
|
102
|
+
# # result[:is_enabled]
|
|
103
|
+
# # result[:details]
|
|
104
|
+
# end
|
|
105
|
+
#
|
|
106
|
+
# # Note: While experiment is running, the `true` value of result[:is_enabled] indicates that
|
|
107
|
+
# # given entity_id was part of experiment audience. The `false` value indicates the entity_id
|
|
108
|
+
# # was not part of experiment audience.
|
|
109
|
+
#
|
|
110
|
+
def get_current_value(entity_id, entity_attributes = {})
|
|
111
|
+
if entity_id.nil? || entity_id.to_s.strip.empty?
|
|
112
|
+
logger = Logger.instance
|
|
113
|
+
logger.error("Feature flag evaluation: #{Constants::INVALID_ENTITY_ID} get_current_value")
|
|
114
|
+
return nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
require_relative "../configuration_handler"
|
|
118
|
+
configuration_handler_instance = ConfigurationHandler.instance
|
|
119
|
+
configuration_handler_instance.feature_evaluation(self, entity_id, entity_attributes)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 IBM Corp. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative "../internal/constants"
|
|
18
|
+
require_relative "../internal/logger"
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Defines the model of a Property defined in App Configuration service.
|
|
22
|
+
class Property
|
|
23
|
+
attr_reader :name, :property_id, :type, :format, :value, :segment_rules
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Initialize a new Property instance
|
|
27
|
+
# @param property [Hash] properties hash that contains all the properties
|
|
28
|
+
def initialize(property)
|
|
29
|
+
@name = property[:name]
|
|
30
|
+
@property_id = property[:property_id]
|
|
31
|
+
@type = property[:type]
|
|
32
|
+
@format = property[:format] # will be nil for boolean & numeric datatypes
|
|
33
|
+
@value = property[:value]
|
|
34
|
+
@segment_rules = property[:segment_rules]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Get the Property name
|
|
39
|
+
# @return [String] The Property name
|
|
40
|
+
def get_property_name
|
|
41
|
+
@name || ""
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Get the Property id
|
|
46
|
+
# @return [String] The Property Id
|
|
47
|
+
def get_property_id
|
|
48
|
+
@property_id || ""
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Get the Property data type
|
|
53
|
+
# @return [String] string named BOOLEAN/STRING/NUMERIC
|
|
54
|
+
def get_property_data_type
|
|
55
|
+
@type || ""
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
##
|
|
59
|
+
# Get the Property data format
|
|
60
|
+
# applicable only for STRING datatype property.
|
|
61
|
+
#
|
|
62
|
+
# @return [String, nil] string named TEXT/JSON/YAML
|
|
63
|
+
def get_property_data_format
|
|
64
|
+
# Format will be `nil` for Boolean & Numeric properties
|
|
65
|
+
# If the Format is nil for a String type, we default it to TEXT
|
|
66
|
+
@format = "TEXT" if @format.nil? && @type == "STRING"
|
|
67
|
+
@format
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
##
|
|
71
|
+
# Get the evaluated value of the property.
|
|
72
|
+
#
|
|
73
|
+
# @param entity_id [String] Id of the Entity.
|
|
74
|
+
# This will be a string identifier related to the Entity against which the property is evaluated.
|
|
75
|
+
# For example, an entity might be an instance of an app that runs on a mobile device, a microservice that runs on the cloud, or a component of infrastructure that runs that microservice.
|
|
76
|
+
# For any entity to interact with App Configuration, it must provide a unique entity ID.
|
|
77
|
+
#
|
|
78
|
+
# @param entity_attributes [Hash] A hash consisting of the attribute name and their values that defines the specified entity.
|
|
79
|
+
# This is an optional parameter if the property is not configured with any targeting definition. If the targeting is configured, then entity_attributes should be provided for the rule evaluation.
|
|
80
|
+
# An attribute is a parameter that is used to define a segment. The SDK uses the attribute values to determine if the
|
|
81
|
+
# specified entity satisfies the targeting rules, and returns the appropriate property value.
|
|
82
|
+
#
|
|
83
|
+
# @return [Hash, nil] Returns a hash containing evaluated value & detailed reason.
|
|
84
|
+
# The evaluated value will be either the default property value or its overridden value based on the evaluation. The data type of returned value matches that of property.
|
|
85
|
+
# Returns nil if entity_id is invalid.
|
|
86
|
+
#
|
|
87
|
+
# @example
|
|
88
|
+
# property = app_config_client.get_property('discount')
|
|
89
|
+
# if property
|
|
90
|
+
# result = property.get_current_value(entity_id, entity_attributes)
|
|
91
|
+
#
|
|
92
|
+
# # Access the evaluated value & details as shown below
|
|
93
|
+
# # result[:value]
|
|
94
|
+
# # result[:details]
|
|
95
|
+
# end
|
|
96
|
+
def get_current_value(entity_id, entity_attributes = {})
|
|
97
|
+
if entity_id.nil? || entity_id.to_s.strip.empty?
|
|
98
|
+
logger = Logger.instance
|
|
99
|
+
logger.error("Property evaluation: #{Constants::INVALID_ENTITY_ID} get_current_value")
|
|
100
|
+
return nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
require_relative "../configuration_handler"
|
|
104
|
+
configuration_handler_instance = ConfigurationHandler.instance
|
|
105
|
+
configuration_handler_instance.property_evaluation(self, entity_id, entity_attributes)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 IBM Corp. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
# Rule model for segment evaluation
|
|
18
|
+
class Rule
|
|
19
|
+
attr_reader :attribute_name, :operator, :values
|
|
20
|
+
|
|
21
|
+
# @param segment_rules [Hash] Rule configuration hash
|
|
22
|
+
def initialize(segment_rules)
|
|
23
|
+
@attribute_name = segment_rules[:attribute_name]
|
|
24
|
+
@operator = segment_rules[:operator]
|
|
25
|
+
@values = segment_rules[:values]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param key [Object] Attribute value to check
|
|
29
|
+
# @param value [Object] Value to compare against
|
|
30
|
+
# @return [Boolean] True if operator check passes
|
|
31
|
+
def operator_check(key, value)
|
|
32
|
+
return false if key.nil? || value.nil?
|
|
33
|
+
|
|
34
|
+
case @operator
|
|
35
|
+
when "endsWith"
|
|
36
|
+
/#{Regexp.escape(value.to_s)}$/i.match?(key.to_s)
|
|
37
|
+
when "notEndsWith"
|
|
38
|
+
!/#{Regexp.escape(value.to_s)}$/i.match?(key.to_s)
|
|
39
|
+
when "startsWith"
|
|
40
|
+
/^#{Regexp.escape(value.to_s)}/i.match?(key.to_s)
|
|
41
|
+
when "notStartsWith"
|
|
42
|
+
!/^#{Regexp.escape(value.to_s)}/i.match?(key.to_s)
|
|
43
|
+
when "contains"
|
|
44
|
+
key.to_s.include?(value.to_s)
|
|
45
|
+
when "notContains"
|
|
46
|
+
!key.to_s.include?(value.to_s)
|
|
47
|
+
when "is"
|
|
48
|
+
key.is_a?(Numeric) ? key.to_f == value.to_f : key.to_s == value.to_s
|
|
49
|
+
when "isNot"
|
|
50
|
+
key.is_a?(Numeric) ? key.to_f != value.to_f : key.to_s != value.to_s
|
|
51
|
+
when "greaterThan"
|
|
52
|
+
key.to_f > value.to_f
|
|
53
|
+
when "lesserThan"
|
|
54
|
+
key.to_f < value.to_f
|
|
55
|
+
when "greaterThanEquals"
|
|
56
|
+
key.to_f >= value.to_f
|
|
57
|
+
when "lesserThanEquals"
|
|
58
|
+
key.to_f <= value.to_f
|
|
59
|
+
else
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Evaluates rule against entity attributes
|
|
65
|
+
#
|
|
66
|
+
# @param entity_attributes [Hash] Entity attributes hash
|
|
67
|
+
# @return [Boolean] True if evaluation passes
|
|
68
|
+
def evaluate_rule(entity_attributes)
|
|
69
|
+
return false unless entity_attributes.is_a?(Hash)
|
|
70
|
+
|
|
71
|
+
# Support both string and symbol keys in entity_attributes
|
|
72
|
+
# Check for string key first, then symbol key
|
|
73
|
+
key = if entity_attributes.key?(@attribute_name)
|
|
74
|
+
entity_attributes[@attribute_name]
|
|
75
|
+
elsif entity_attributes.key?(@attribute_name.to_sym)
|
|
76
|
+
entity_attributes[@attribute_name.to_sym]
|
|
77
|
+
else
|
|
78
|
+
return false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if %w[isNot notContains notStartsWith notEndsWith].include?(@operator)
|
|
82
|
+
@values.all? { |value| operator_check(key, value) }
|
|
83
|
+
else
|
|
84
|
+
@values.any? { |value| operator_check(key, value) }
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 IBM Corp. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative "../internal/constants"
|
|
18
|
+
require_relative "../internal/logger"
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Defines the SecretProperty model.
|
|
22
|
+
class SecretProperty
|
|
23
|
+
attr_reader :property_id
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Initialize a new SecretProperty instance
|
|
27
|
+
# @param property_id [String] Property identifier
|
|
28
|
+
def initialize(property_id)
|
|
29
|
+
@property_id = property_id
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Evaluate the value of the secret property.
|
|
34
|
+
#
|
|
35
|
+
# @param entity_id [String] Id of the Entity.
|
|
36
|
+
# @param entity_attributes [Hash] A hash consisting of the attribute name and their values that defines the specified entity.
|
|
37
|
+
#
|
|
38
|
+
# @return [Object, nil] returns the response from the secret manager or nil if entity_id is invalid.
|
|
39
|
+
# The returned value will be the actual secret value of the evaluated secret reference. The response contains the body, the headers, the status code, and the status text.
|
|
40
|
+
# If an error occurs, it will be raised as an exception.
|
|
41
|
+
def get_current_value(entity_id, entity_attributes = {})
|
|
42
|
+
logger = Logger.instance
|
|
43
|
+
|
|
44
|
+
if entity_id.nil? || entity_id.to_s.strip.empty?
|
|
45
|
+
logger.error("SecretProperty evaluation: #{Constants::INVALID_ENTITY_ID} get_current_value")
|
|
46
|
+
return nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
require_relative "../configuration_handler"
|
|
50
|
+
configuration_handler_instance = ConfigurationHandler.instance
|
|
51
|
+
|
|
52
|
+
# Get the property object
|
|
53
|
+
property_obj = configuration_handler_instance.get_property(@property_id)
|
|
54
|
+
return nil unless property_obj
|
|
55
|
+
|
|
56
|
+
# Get the current value of the property (which contains the secret reference)
|
|
57
|
+
property_current_val = property_obj.get_current_value(entity_id, entity_attributes)
|
|
58
|
+
return nil unless property_current_val
|
|
59
|
+
|
|
60
|
+
# Check if the property value contains a secret id
|
|
61
|
+
if property_current_val[:value].is_a?(Hash) && property_current_val[:value].key?(:id)
|
|
62
|
+
secret_id = property_current_val[:value][:id]
|
|
63
|
+
|
|
64
|
+
# Get the secrets map from configuration handler
|
|
65
|
+
secret_map = configuration_handler_instance.get_secrets_map
|
|
66
|
+
secret_manager_obj = secret_map[@property_id]
|
|
67
|
+
|
|
68
|
+
return secret_manager_obj.get_secret(id: secret_id) if secret_manager_obj
|
|
69
|
+
|
|
70
|
+
# Call the get_secret method on the secret manager object
|
|
71
|
+
# The caller is responsible for handling any exceptions
|
|
72
|
+
|
|
73
|
+
logger.error("SecretProperty Evaluation: Secret manager not configured for property: #{property_obj.get_property_name}")
|
|
74
|
+
return nil
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
logger.error("SecretProperty Evaluation: Secret Id is missing from the Property: #{property_obj.get_property_name}")
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 IBM Corp. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative "rule"
|
|
18
|
+
|
|
19
|
+
# Segment model for App Configuration service
|
|
20
|
+
class Segment
|
|
21
|
+
attr_reader :name, :segment_id, :rules
|
|
22
|
+
|
|
23
|
+
# @param segment_list [Hash] Segment configuration hash
|
|
24
|
+
def initialize(segment_list)
|
|
25
|
+
@name = segment_list[:name]
|
|
26
|
+
@segment_id = segment_list[:segment_id]
|
|
27
|
+
@rules = segment_list[:rules] || []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Evaluates all segment rules against entity attributes
|
|
31
|
+
#
|
|
32
|
+
# @param entity_attributes [Hash] Entity attributes hash
|
|
33
|
+
# @return [Boolean] True if all rules pass
|
|
34
|
+
def evaluate_rule(entity_attributes)
|
|
35
|
+
@rules.all? do |rule|
|
|
36
|
+
Rule.new(rule).evaluate_rule(entity_attributes)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 IBM Corp. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
# SegmentRules model for App Configuration service
|
|
18
|
+
class SegmentRules
|
|
19
|
+
attr_reader :rules, :rule_id, :value, :order, :rollout_type, :rollout_percentage, :rollout_configuration
|
|
20
|
+
|
|
21
|
+
# @param segment_rules [Hash] Segment rules configuration hash
|
|
22
|
+
def initialize(segment_rules)
|
|
23
|
+
require_relative "../internal/constants"
|
|
24
|
+
|
|
25
|
+
@rules = segment_rules[:rules]
|
|
26
|
+
@rule_id = segment_rules[:rule_id]
|
|
27
|
+
@value = segment_rules[:value]
|
|
28
|
+
@order = segment_rules[:order]
|
|
29
|
+
@rollout_type = segment_rules.key?(:rollout_type) ? segment_rules[:rollout_type] : Constants::MANUAL
|
|
30
|
+
|
|
31
|
+
if segment_rules[:rollout_configuration]
|
|
32
|
+
@rollout_configuration = segment_rules[:rollout_configuration]
|
|
33
|
+
else
|
|
34
|
+
@rollout_percentage = segment_rules.key?(:rollout_percentage) ? segment_rules[:rollout_percentage] : 100
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [Array<Hash>] Rules array
|
|
39
|
+
def get_rules
|
|
40
|
+
@rules || []
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [Boolean, String, Numeric] Rule value
|
|
44
|
+
def get_value
|
|
45
|
+
@value || ""
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Integer] Rule order
|
|
49
|
+
def get_order
|
|
50
|
+
@order
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [Integer] Rollout percentage
|
|
54
|
+
def get_rollout_percentage
|
|
55
|
+
@rollout_percentage
|
|
56
|
+
end
|
|
57
|
+
end
|