chef-licensing 1.0.4 → 1.2.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: 0c948fd9a7a8f207619bd565dd36ac08080d36eba49603c44375c38aa9a07625
4
- data.tar.gz: c6580bde930ae2e8baa93000cd12b9de11aeff60f5dc53296da96dd8fbefd32d
3
+ metadata.gz: 3261fe05e89d3f85b80af5270597a662ebe84eaca761e43744afbc858582baeb
4
+ data.tar.gz: 7234e048b9f4ab4b303381282786a0c14aef229cb6dc73d00afb00cddc00a884
5
5
  SHA512:
6
- metadata.gz: 934b42b57560e797c58d0dbafd84306a48e5f6edca46b4c32bf64d066fbfcc380d716765297771baae920f18138a6d183476a37125dbd3f636273fb47a941e60
7
- data.tar.gz: 36ca4df33d88d079ed8c23b0a91e9f8a78b2d478fc1185f77053c56cd94ab941457b55184839d91df0e3416e0792a19b1f1eff70e183fd6745ced46e0825528c
6
+ metadata.gz: 18077438f71d4f67c706721df441df2403d6b2e257a6da1966e38dfa52cf975f69356c8b2421b947c74625a1c5c8f026b1848da6b1759a11f502835c51733021
7
+ data.tar.gz: 649ac4de8a6df4ef59aaf7c32c8731ea0200f4b3c22e32abfb329bfb5ba7ba1a5e3f79c7e19fdad27556772ce5ef9e22016cda5354a8709f6a99c5d21445523c
@@ -28,11 +28,12 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_dependency "chef-config", ">= 15"
30
30
  spec.add_dependency "tty-prompt", "~> 0.23"
31
- spec.add_dependency "faraday", ">= 1", "< 3"
31
+ spec.add_dependency "faraday", ">= 1", "< 2"
32
32
  spec.add_dependency "faraday-http-cache"
33
- # Note: 7.1.0 does not defaults its cache_format_version to 7.1 but 6.1 instead which gives deprecation warnings
34
- # Remove the version constraint when we can upgrade to 7.1.1 post stable release of Activesupport 7.1
35
- # Similar issue with 7.0 existed: https://github.com/rails/rails/pull/45293
36
- spec.add_dependency "activesupport", "~> 7.0", "< 7.1"
33
+ spec.add_dependency "activesupport", "~> 7.2", ">= 7.2.2.1"
37
34
  spec.add_dependency "tty-spinner", "~> 0.9.3"
35
+ spec.add_dependency "mixlib-log", "~> 3.0"
36
+
37
+ # Gem dependency needed with Ruby 3.4 upgrade
38
+ spec.add_dependency "ostruct", "~> 0.1.0"
38
39
  end
@@ -3,6 +3,7 @@ require "logger"
3
3
  require_relative "config_fetcher/arg_fetcher"
4
4
  require_relative "config_fetcher/env_fetcher"
5
5
  require_relative "license_key_fetcher/file"
6
+ require_relative "log"
6
7
 
7
8
  # Config class handles all configuration related to chef-licensing
8
9
  # Values can be set via block, environment variable or command line argument
@@ -13,7 +14,7 @@ require_relative "licensing_service/local"
13
14
  module ChefLicensing
14
15
  class Config
15
16
  class << self
16
- attr_writer :license_server_url, :logger, :output, :license_server_url_check_in_file, :license_add_command, :license_list_command
17
+ attr_writer :license_server_url, :logger, :output, :license_server_url_check_in_file, :license_add_command, :license_list_command, :make_licensing_optional
17
18
 
18
19
  # is_local_license_service is used by context class
19
20
  attr_accessor :is_local_license_service, :chef_entitlement_id, :chef_product_name, :chef_executable_name
@@ -22,20 +23,35 @@ module ChefLicensing
22
23
  return @license_server_url if @license_server_url && @license_server_url_check_in_file
23
24
 
24
25
  license_server_url_from_system = ChefLicensing::ArgFetcher.fetch_value("--chef-license-server", :string) || ChefLicensing::EnvFetcher.fetch_value("CHEF_LICENSE_SERVER", :string)
25
-
26
26
  @license_server_url = ChefLicensing::LicenseKeyFetcher::File.fetch_or_persist_url(@license_server_url, license_server_url_from_system, opts)
27
27
  @license_server_url_check_in_file = true
28
28
  @license_server_url
29
29
  end
30
30
 
31
31
  def logger
32
- return @logger if @logger
32
+ # If no log level flags are set and we have a cached logger (like Inspec::Log), use it as-is
33
+ return @logger if @logger && !log_level_flags_present?
33
34
 
34
- @logger = Logger.new(STDERR)
35
- @logger.level = Logger::INFO
35
+ # If log level flags are present, configure the logger with determined level
36
+ @logger = ChefLicensing::Log
37
+ @logger.level = determine_log_level
36
38
  @logger
37
39
  end
38
40
 
41
+ def determine_log_level
42
+ log_level_string = get_log_level_from_flags
43
+
44
+ valid = %w{trace debug info warn error fatal}
45
+
46
+ if valid.include?(log_level_string)
47
+ log_level = log_level_string
48
+ else
49
+ log_level = "info"
50
+ end
51
+
52
+ Mixlib::Log.const_get(log_level.upcase)
53
+ end
54
+
39
55
  def output
40
56
  @output ||= STDOUT
41
57
  end
@@ -47,6 +63,45 @@ module ChefLicensing
47
63
  def license_list_command
48
64
  @license_list_command ||= "license list"
49
65
  end
66
+
67
+ def make_licensing_optional
68
+ @make_licensing_optional ||= false
69
+ end
70
+
71
+ def require_license_mutex
72
+ @require_license_mutex ||= Mutex.new
73
+ end
74
+
75
+ def require_license_for
76
+ return unless block_given?
77
+
78
+ require_license_mutex.synchronize do
79
+ # Store the original value by calling the method, not accessing the instance variable
80
+ original_value = make_licensing_optional
81
+
82
+ begin
83
+ # Temporarily set licensing as required (not optional)
84
+ @make_licensing_optional = false
85
+ yield
86
+ ensure
87
+ # Always restore the original value, even if an exception occurs
88
+ @make_licensing_optional = original_value
89
+ end
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def log_level_flags_present?
96
+ !get_log_level_from_flags.nil?
97
+ end
98
+
99
+ def get_log_level_from_flags
100
+ ChefLicensing::ArgFetcher.fetch_value("--log-level", :string) ||
101
+ ChefLicensing::ArgFetcher.fetch_value("--chef-log-level", :string) ||
102
+ ChefLicensing::EnvFetcher.fetch_value("LOG_LEVEL", :string) ||
103
+ ChefLicensing::EnvFetcher.fetch_value("CHEF_LOG_LEVEL", :string)
104
+ end
50
105
  end
51
106
  end
52
107
  end
@@ -63,7 +63,6 @@ module ChefLicensing
63
63
 
64
64
  # The Context allows changing the State object
65
65
  def transition_to(state)
66
- logger.debug "Chef Licensing Context: Transition to #{state.class}"
67
66
  @state = state
68
67
  @state.context = self
69
68
  @state.options = options
@@ -40,7 +40,8 @@ module ChefLicensing
40
40
 
41
41
  def fetch
42
42
  read_license_key_file
43
- contents&.key?(:licenses) ? fetch_license_keys(contents[:licenses]) : []
43
+ # Check if contents is valid and not an error before accessing license data
44
+ (contents && !contents.is_a?(StandardError) && contents.key?(:licenses)) ? fetch_license_keys(contents[:licenses]) : []
44
45
  end
45
46
 
46
47
  def fetch_license_keys(licenses)
@@ -50,7 +51,8 @@ module ChefLicensing
50
51
  def fetch_license_types
51
52
  read_license_key_file
52
53
 
53
- if contents.nil? || contents[:licenses].nil?
54
+ # Return empty array if contents failed to load, is nil, or has no licenses
55
+ if contents.is_a?(StandardError) || contents.nil? || contents[:licenses].nil?
54
56
  []
55
57
  else
56
58
  contents[:licenses].collect { |x| x[:license_type] }
@@ -61,7 +63,8 @@ module ChefLicensing
61
63
  @active_trial_status = false
62
64
  read_license_key_file
63
65
 
64
- if contents&.key?(:licenses)
66
+ # Only proceed if contents loaded successfully and contains license data
67
+ if contents && !contents.is_a?(StandardError) && contents.key?(:licenses)
65
68
  @active_trial_status = contents[:licenses].any? { |license| license[:license_type] == :trial && ChefLicensing.client(license_keys: [license[:license_key]]).active? }
66
69
  end
67
70
  @active_trial_status
@@ -69,7 +72,8 @@ module ChefLicensing
69
72
 
70
73
  def user_has_active_trial_or_free_license?
71
74
  read_license_key_file
72
- return false unless contents&.key?(:licenses)
75
+ # Early return if contents failed to load or doesn't contain license data
76
+ return false unless contents && !contents.is_a?(StandardError) && contents.key?(:licenses)
73
77
 
74
78
  all_license_keys = contents[:licenses].collect { |license| license[:license_key] }
75
79
  license_obj = ChefLicensing.client(license_keys: all_license_keys)
@@ -87,7 +91,8 @@ module ChefLicensing
87
91
 
88
92
  def fetch_license_keys_based_on_type(license_type)
89
93
  read_license_key_file
90
- if contents.nil?
94
+ # Return empty array if contents failed to load or is nil
95
+ if contents.is_a?(StandardError) || contents.nil?
91
96
  []
92
97
  else
93
98
  contents[:licenses].collect do |x|
@@ -131,15 +136,21 @@ module ChefLicensing
131
136
 
132
137
  @contents = load_license_file(license_key_file_path)
133
138
 
134
- # Two possible cases:
135
- # 1. If contents is nil, load basic license data with the latest structure.
136
- # 2. If contents is not nil, but the license server URL in contents is different from the system's,
139
+ # Three possible cases:
140
+ # 1. If contents is nil or an error occurred while loading, load basic license data with the latest structure.
141
+ # 2. If contents is not nil and valid, but the license server URL in contents is different from the system's,
137
142
  # update the license server URL in contents and licenses.yaml file.
138
- if @contents.nil?
143
+ # 3. If contents is valid and no update is needed, return the existing license server URL.
144
+ # Handle error cases first - when file loading failed or contents is nil
145
+ if @contents.is_a?(StandardError) || @contents.nil?
139
146
  url = license_server_url_from_system || license_server_url_from_config
140
147
  load_basic_license_data_to_contents(url, [])
141
148
  elsif @contents && license_server_url_from_system && license_server_url_from_system != @contents[:license_server_url]
142
149
  @contents[:license_server_url] = license_server_url_from_system
150
+ else
151
+ # Nothing to change in the file
152
+ @license_server_url = @contents[:license_server_url]
153
+ return @license_server_url
143
154
  end
144
155
 
145
156
  # Ensure the license server URL is returned to the caller in all cases
@@ -151,7 +162,6 @@ module ChefLicensing
151
162
  ensure
152
163
  @license_server_url = @contents[:license_server_url]
153
164
  end
154
- logger.debug "License server URL: #{@license_server_url}"
155
165
  @license_server_url
156
166
  end
157
167
 
@@ -214,7 +224,6 @@ module ChefLicensing
214
224
  def read_license_key_file
215
225
  return contents if contents
216
226
 
217
- logger.debug "Reading license file from #{seek}"
218
227
  path = seek
219
228
  return nil unless path
220
229
 
@@ -239,7 +248,6 @@ module ChefLicensing
239
248
  write_license_file(path) # update the license file contents to the latest version
240
249
  @contents
241
250
  else
242
- logger.debug "License File version #{@contents[:file_format_version]} not supported."
243
251
  raise ChefLicensing::InvalidFileFormatVersion.new("Unable to read licenses. License File version #{@contents[:file_format_version]} not supported.")
244
252
  end
245
253
  end
@@ -261,7 +269,6 @@ module ChefLicensing
261
269
  def load_license_file(license_key_file_path)
262
270
  return unless ::File.exist?(license_key_file_path)
263
271
 
264
- logger.debug "Reading license_key file at #{license_key_file_path}"
265
272
  msg = "Could not read license key file #{license_key_file_path}"
266
273
  YAML.load_file(license_key_file_path)
267
274
  rescue StandardError => e
@@ -271,8 +278,8 @@ module ChefLicensing
271
278
  def load_license_data_to_contents(license_data)
272
279
  return unless license_data
273
280
 
274
- logger.debug "Loading license data to contents"
275
- if @contents.nil? || @contents.empty? # this case is likely to happen only during testing
281
+ # Handle cases where contents failed to load, is nil, or empty
282
+ if @contents.is_a?(StandardError) || @contents.nil? || @contents.empty? # this case is likely to happen only during testing or when file loading fails
276
283
  load_basic_license_data_to_contents(@license_server_url, [license_data])
277
284
  elsif @contents[:licenses].nil?
278
285
  @contents[:licenses] = [license_data]
@@ -292,7 +299,7 @@ module ChefLicensing
292
299
  end
293
300
 
294
301
  def handle_error(e, message = nil)
295
- logger.debug "#{e.backtrace.join("\n\t")}"
302
+ logger.trace "#{e.backtrace.join("\n\t")}"
296
303
  e
297
304
  end
298
305
 
@@ -37,7 +37,6 @@ module ChefLicensing
37
37
  config[:dir] = opts[:dir]
38
38
 
39
39
  # While using on-prem licensing service, @license_keys are fetched from API
40
- logger.debug "License Key fetcher - fetching license keys depending upon the context (either API or file)"
41
40
  # While using global licensing service, @license_keys are fetched from file
42
41
  @license_keys = ChefLicensing::Context.license_keys(opts) || []
43
42
 
@@ -92,12 +91,10 @@ module ChefLicensing
92
91
  end
93
92
 
94
93
  # Otherwise nothing was able to fetch a license. Throw an exception.
95
- logger.debug "License Key fetcher - no license Key able to be fetched."
96
94
  raise LicenseKeyNotFetchedError.new("Unable to obtain a License Key.")
97
95
  end
98
96
 
99
97
  def perform_global_operations
100
- logger.debug "License Key fetcher examining CLI arg checks"
101
98
  new_keys = fetch_license_key_from_arg
102
99
  license_type = validate_and_fetch_license_type(new_keys)
103
100
  if license_type && !unrestricted_license_added?(new_keys, license_type)
@@ -106,7 +103,6 @@ module ChefLicensing
106
103
  return license_keys
107
104
  end
108
105
 
109
- logger.debug "License Key fetcher examining ENV checks"
110
106
  new_keys = fetch_license_key_from_env
111
107
  license_type = validate_and_fetch_license_type(new_keys)
112
108
  if license_type && !unrestricted_license_added?(new_keys, license_type)
@@ -124,7 +120,6 @@ module ChefLicensing
124
120
  # Lowest priority is to interactively prompt if we have a TTY
125
121
  if config[:output].isatty
126
122
  append_extra_info_to_tui_engine # will add extra dynamic values in tui flows
127
- logger.debug "License Key fetcher - detected TTY, prompting..."
128
123
  new_keys = prompt_fetcher.fetch
129
124
 
130
125
  unless new_keys.empty?
@@ -150,12 +145,10 @@ module ChefLicensing
150
145
  end
151
146
 
152
147
  # Otherwise nothing was able to fetch a license. Throw an exception.
153
- logger.debug "License Key fetcher - no license Key able to be fetched."
154
148
  raise LicenseKeyNotFetchedError.new("Unable to obtain a License Key.")
155
149
  end
156
150
 
157
151
  def add_license
158
- logger.debug "License Key fetcher - add license flow, starting..."
159
152
  if ChefLicensing::Context.local_licensing_service?
160
153
  raise LicenseKeyAddNotAllowed.new("'inspec license add' command is not supported with airgapped environment. You cannot generate license from airgapped environment.")
161
154
  else
@@ -302,7 +295,6 @@ module ChefLicensing
302
295
  end
303
296
 
304
297
  def prompt_license_addition_restricted(license_type, existing_license_keys_in_file)
305
- logger.debug "License Key fetcher - prompting license addition restriction"
306
298
  # For trial license
307
299
  # TODO for Free Tier License
308
300
  config[:start_interaction] = :prompt_license_addition_restriction
@@ -117,11 +117,9 @@ module ChefLicensing
117
117
  license_keys = opts[:license_keys] || ChefLicensing::LicenseKeyFetcher.fetch({ dir: opts[:dir] })
118
118
 
119
119
  if license_keys.empty?
120
- logger.debug "No license keys found on disk."
121
120
  output.puts "No license keys found on disk."
122
121
  exit
123
122
  end
124
- logger.debug "License keys fetched from disk: #{license_keys}"
125
123
 
126
124
  license_keys
127
125
  rescue ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError => e
@@ -135,7 +133,6 @@ module ChefLicensing
135
133
  licenses_metadata = ChefLicensing::Api::Describe.list({
136
134
  license_keys: license_keys,
137
135
  })
138
- logger.debug "License metadata fetched from server: #{licenses_metadata}"
139
136
 
140
137
  licenses_metadata
141
138
  rescue ChefLicensing::DescribeError => e
@@ -0,0 +1,10 @@
1
+ require "mixlib/log"
2
+
3
+ module ChefLicensing
4
+ class Log
5
+ extend Mixlib::Log
6
+
7
+ # Initialize with STDERR as the default output stream
8
+ init(STDERR)
9
+ end
10
+ end
@@ -92,7 +92,7 @@ module ChefLicensing
92
92
  attempted_urls << url
93
93
  break if i == REQUEST_LIMIT - 1
94
94
 
95
- logger.debug "Trying to connect to #{url}"
95
+ logger.debug "Trying to connect to #{url}" if urls.size > 1
96
96
  handle_connection.call(url) do |connection|
97
97
  response = connection.send(http_method, endpoint) do |request|
98
98
  request.body = payload.to_json if payload
@@ -59,7 +59,6 @@ module ChefLicensing
59
59
  verify_interaction_data
60
60
  store_interaction_objects
61
61
  build_interaction_path
62
- logger.debug "TUI Engine initialized."
63
62
  end
64
63
 
65
64
  def inflate_interaction_data(interaction_file)
@@ -19,8 +19,6 @@ module ChefLicensing
19
19
  end
20
20
 
21
21
  def default_action(interaction)
22
- logger.debug "Default action called for interaction id: #{interaction.id}"
23
-
24
22
  response = if interaction.messages
25
23
  messages = render_messages(interaction.messages)
26
24
  @prompt.send(interaction.prompt_type, messages, interaction.prompt_attributes)
@@ -29,8 +27,6 @@ module ChefLicensing
29
27
  end
30
28
 
31
29
  @input.store(interaction.id, response)
32
- logger.debug "Response for interaction #{interaction.id} is #{@input[interaction.id]}"
33
-
34
30
  @next_interaction_id = if interaction.paths.size > 1
35
31
  interaction.response_path_map[response.to_s]
36
32
  elsif interaction.paths.size == 1
@@ -1,3 +1,3 @@
1
1
  module ChefLicensing
2
- VERSION = "1.0.4".freeze
2
+ VERSION = "1.2.0".freeze
3
3
  end
@@ -23,6 +23,9 @@ module ChefLicensing
23
23
  end
24
24
 
25
25
  def check_feature_entitlement!(feature_name: nil, feature_id: nil)
26
+ # If licensing is optional, bypass entitlement checks
27
+ return true if ChefLicensing::Config.make_licensing_optional
28
+
26
29
  # Checking for feature presence in license feature entitlements
27
30
  license = client(license_keys: license_keys)
28
31
  feature_entitlements = license.feature_entitlements.select { |feature| feature.id == feature_id || feature.name == feature_name }
@@ -35,9 +38,14 @@ module ChefLicensing
35
38
 
36
39
  def check_software_entitlement!
37
40
  # If API call is not breaking that means license is entitled.
38
- raise ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError.new("Unable to obtain a License Key.") if license_keys.empty?
41
+ unless ChefLicensing::Config.make_licensing_optional
42
+ if license_keys.empty?
43
+ raise ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError,
44
+ "Unable to obtain a License Key."
45
+ end
39
46
 
40
- client(license_keys: license_keys)
47
+ client(license_keys: license_keys)
48
+ end
41
49
  true
42
50
  rescue ChefLicensing::ClientError => e
43
51
  # Checking specific text phrase for entitlement error
@@ -55,6 +63,9 @@ module ChefLicensing
55
63
 
56
64
  # @note fetch_and_persist is invoked by chef-products to fetch and persist the license keys
57
65
  def fetch_and_persist
66
+ # Return early if make_licensing_optional is enabled
67
+ return true if ChefLicensing::Config.make_licensing_optional
68
+
58
69
  ChefLicensing::LicenseKeyFetcher.fetch_and_persist
59
70
  rescue ChefLicensing::ClientError => e
60
71
  # Checking specific text phrase for entitlement error
@@ -82,3 +93,13 @@ module ChefLicensing
82
93
  end
83
94
  end
84
95
  end
96
+
97
+ # Require the chef-official-distribution gem if available
98
+ # chef-official-distribution gem has a dependency on ChefLicensing.configure which is only loaded after this file is loaded.
99
+ # Hence this require is placed at the end of the file.
100
+ begin
101
+ require "chef-official-distribution"
102
+ rescue LoadError
103
+ # Todo: should we warn here?
104
+ # Running in an unofficial distribution mode.
105
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-licensing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Inspec Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-01 00:00:00.000000000 Z
11
+ date: 2025-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-config
@@ -47,7 +47,7 @@ dependencies:
47
47
  version: '1'
48
48
  - - "<"
49
49
  - !ruby/object:Gem::Version
50
- version: '3'
50
+ version: '2'
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
@@ -57,7 +57,7 @@ dependencies:
57
57
  version: '1'
58
58
  - - "<"
59
59
  - !ruby/object:Gem::Version
60
- version: '3'
60
+ version: '2'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: faraday-http-cache
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -78,20 +78,20 @@ dependencies:
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '7.0'
82
- - - "<"
81
+ version: '7.2'
82
+ - - ">="
83
83
  - !ruby/object:Gem::Version
84
- version: '7.1'
84
+ version: 7.2.2.1
85
85
  type: :runtime
86
86
  prerelease: false
87
87
  version_requirements: !ruby/object:Gem::Requirement
88
88
  requirements:
89
89
  - - "~>"
90
90
  - !ruby/object:Gem::Version
91
- version: '7.0'
92
- - - "<"
91
+ version: '7.2'
92
+ - - ">="
93
93
  - !ruby/object:Gem::Version
94
- version: '7.1'
94
+ version: 7.2.2.1
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: tty-spinner
97
97
  requirement: !ruby/object:Gem::Requirement
@@ -106,6 +106,34 @@ dependencies:
106
106
  - - "~>"
107
107
  - !ruby/object:Gem::Version
108
108
  version: 0.9.3
109
+ - !ruby/object:Gem::Dependency
110
+ name: mixlib-log
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '3.0'
116
+ type: :runtime
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '3.0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: ostruct
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: 0.1.0
130
+ type: :runtime
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: 0.1.0
109
137
  description: Ruby library to support CLI tools that use Progress Chef license storage,
110
138
  generation, and entitlement.
111
139
  email:
@@ -154,6 +182,7 @@ files:
154
182
  - lib/chef-licensing/license_key_validator.rb
155
183
  - lib/chef-licensing/licensing_service/local.rb
156
184
  - lib/chef-licensing/list_license_keys.rb
185
+ - lib/chef-licensing/log.rb
157
186
  - lib/chef-licensing/restful_client/base.rb
158
187
  - lib/chef-licensing/restful_client/middleware/content_type_validator.rb
159
188
  - lib/chef-licensing/restful_client/middleware/exceptions_handler.rb
@@ -187,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
216
  - !ruby/object:Gem::Version
188
217
  version: '0'
189
218
  requirements: []
190
- rubygems_version: 3.2.3
219
+ rubygems_version: 3.3.27
191
220
  signing_key:
192
221
  specification_version: 4
193
222
  summary: Chef License storage, generation, and entitlement