knife 18.5.0 → 18.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7dbcf835eedd6dece43282604cd9c7136ba0adf6375c856582860700d65031e
4
- data.tar.gz: bc342db29c4bb913525ff031519efaa585a0067e1ae65bb2786403edef3934f9
3
+ metadata.gz: e9b1053a729f2359d5714a6cbdbdbb1ff4aea8f8927e838b510e249d741489e3
4
+ data.tar.gz: 9776202dc87c3c7dc76a7a0e1335fcab453301a738133ea292965cb380bf1a05
5
5
  SHA512:
6
- metadata.gz: 11a5c1d4e9449e7e566ba18ca38efda979c2341ecba1e07b607a90c7c18acc57af69115039757a3cdb48059c08468d38c75c65f5a28953863c5d8228337d3378
7
- data.tar.gz: baa24762c6c61cc695ccd0f8fcba24284aab84502dbd2c74f26d436912d66ce7e2119edc401d5071c1577ce77d2b5c08da2eaa145738a4871f18a139d79da609
6
+ metadata.gz: 96f3ff8dff0498644dfb8c534be6fabcd2992e620299ab66d240ea6f20c0188e9bac7d20f9be80ba3aba468f669f8f5af1fa7beca8b84647e90e0cfbb97022e1
7
+ data.tar.gz: 823775c2c0c2bd7f7153c06f49efffe4a0fc98ee698456d1530c6969e3ad2a7c7cec71e578314dd893ff94a909bada414477ae565dfac2336a9a72161bf3ed9a
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ group(:development, :test) do
6
6
  gem "cheffish", ">= 14" # testing only , but why didn't this need to explicit in chef?
7
7
  gem "webmock"
8
8
  gem "crack", "< 0.4.6" # due to https://github.com/jnunemaker/crack/pull/75
9
- gem "rake"
9
+ gem "rake", ">= 12.3.3"
10
10
  gem "rspec"
11
11
  gem "chef-bin", path: "../chef-bin"
12
12
  end
@@ -21,7 +21,7 @@ group(:chefstyle) do
21
21
  gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "main"
22
22
  end
23
23
 
24
- gem "ohai", git: "https://github.com/chef/ohai.git", branch: "main"
24
+ gem "ohai", git: "https://github.com/chef/ohai.git", branch: "18-stable"
25
25
  gem "chef", path: ".."
26
26
  gem "chef-utils", path: File.expand_path("../chef-utils", __dir__) if File.exist?(File.expand_path("../chef-utils", __dir__))
27
27
  gem "chef-config", path: File.expand_path("../chef-config", __dir__) if File.exist?(File.expand_path("../chef-config", __dir__))
data/knife.gemspec CHANGED
@@ -44,6 +44,8 @@ Gem::Specification.new do |s|
44
44
 
45
45
  s.add_dependency "proxifier2", "~> 1.1"
46
46
 
47
+ s.add_dependency "chef-licensing", "~> 1.0"
48
+
47
49
  s.bindir = "bin"
48
50
  s.executables = %w{ knife }
49
51
 
@@ -19,6 +19,9 @@ require "chef/application"
19
19
  require_relative "../knife"
20
20
  require "mixlib/log"
21
21
  require "ohai/config"
22
+ require "chef-licensing"
23
+ require "chef/utils/licensing_handler"
24
+ require "chef/knife/core/ui"
22
25
  module Net
23
26
  autoload :HTTP, "net/http"
24
27
  end
@@ -171,7 +171,14 @@ do_download() {
171
171
  <% if @config[:bootstrap_install_command] %>
172
172
  <%= @config[:bootstrap_install_command] %>
173
173
  <% else %>
174
- install_sh="<%= @config[:bootstrap_url] ? @config[:bootstrap_url] : "https://omnitruck.chef.io/chef/install.sh" %>"
174
+ <% if @config[:bootstrap_url] %>
175
+ install_sh="<%= @config[:bootstrap_url] %>"
176
+ <% elsif license_available? %>
177
+ install_sh="<%= config[:license_url] %>"
178
+ <% else %>
179
+ install_sh="https://omnitruck.chef.io/chef/install.sh"
180
+ <% end %>
181
+
175
182
  if test -f /usr/bin/<%= ChefUtils::Dist::Infra::CLIENT %>; then
176
183
  echo "-----> Existing <%= ChefUtils::Dist::Infra::PRODUCT %> installation detected"
177
184
  else
@@ -21,6 +21,8 @@ require_relative "data_bag_secret_options"
21
21
  require "chef-utils/dist" unless defined?(ChefUtils::Dist)
22
22
  require "license_acceptance/cli_flags/mixlib_cli"
23
23
  require "chef/json_compat" unless defined?(Chef::JSONCompat) # can't be lazy loaded since it's used in options
24
+ require "chef/utils/licensing_config"
25
+ require "chef/utils/licensing_handler"
24
26
 
25
27
  module LicenseAcceptance
26
28
  autoload :Acceptor, "license_acceptance/acceptor"
@@ -442,7 +444,7 @@ class Chef
442
444
 
443
445
  # Determine if we need to accept the Chef Infra license locally in order to successfully bootstrap
444
446
  # the remote node. Remote 'chef-client' run will fail if it is >= 15 and the license is not accepted locally.
445
- def check_license
447
+ def check_eula_license
446
448
  Chef::Log.debug("Checking if we need to accept Chef license to bootstrap node")
447
449
  version = config[:bootstrap_version] || Chef::VERSION.split(".").first
448
450
  acceptor = LicenseAcceptance::Acceptor.new(logger: Chef::Log, provided: Chef::Config[:chef_license])
@@ -550,7 +552,8 @@ class Chef
550
552
  end
551
553
 
552
554
  def run
553
- check_license if ChefUtils::Dist::Org::ENFORCE_LICENSE
555
+ check_eula_license if ChefUtils::Dist::Org::ENFORCE_LICENSE
556
+ fetch_license
554
557
 
555
558
  plugin_setup!
556
559
  validate_name_args!
@@ -572,6 +575,7 @@ class Chef
572
575
  bootstrap_path = upload_bootstrap(content)
573
576
  perform_bootstrap(bootstrap_path)
574
577
  plugin_finalize
578
+ warn_license_usage
575
579
  ensure
576
580
  connection.del_file!(bootstrap_path) if connection && bootstrap_path
577
581
  end
@@ -1188,6 +1192,28 @@ class Chef
1188
1192
 
1189
1193
  connection&.connection&.transport_options&.merge! opts
1190
1194
  end
1195
+
1196
+ # Fetch the workstation license stored in the system
1197
+ def fetch_license
1198
+ license = Chef::Utils::LicensingHandler.validate!
1199
+ config[:license_url] = license.install_sh_url
1200
+ config[:license_id] = license.license_key
1201
+ config[:license_type] = license.license_type
1202
+ end
1203
+
1204
+ def warn_license_usage
1205
+ return if config[:license_type].present?
1206
+
1207
+ ui.warn(<<~MSG
1208
+ +-------------------------------------------------------------------------------------------------------+
1209
+ Knife bootstrap now needs a license key to allow uninterrupted download of Infra Client.
1210
+ It is easy to add a license by following the command <knife license>.
1211
+ If you are a commercial customer, you may get a license from the customer portal else you can generate
1212
+ from https://www.chef.io/license-generation-free-trial
1213
+ +-------------------------------------------------------------------------------------------------------+
1214
+ MSG
1215
+ )
1216
+ end
1191
1217
  end
1192
1218
  end
1193
1219
  end
@@ -203,7 +203,13 @@ class Chef
203
203
  def version_to_install
204
204
  return config[:bootstrap_version] if config[:bootstrap_version]
205
205
 
206
- if config[:channel] == "stable"
206
+ if config[:license_url]
207
+ if config[:channel] == "stable" && config[:license_type] == "commercial"
208
+ Chef::VERSION.split(".").first
209
+ else
210
+ "latest"
211
+ end
212
+ elsif config[:channel] == "stable"
207
213
  Chef::VERSION.split(".").first
208
214
  else
209
215
  "latest"
@@ -223,6 +229,10 @@ class Chef
223
229
  end
224
230
  end
225
231
 
232
+ def license_available?
233
+ config[:license_id] && config[:license_type]
234
+ end
235
+
226
236
  private
227
237
 
228
238
  # Returns a string for copying the trusted certificates on the workstation to the system being bootstrapped
@@ -242,6 +242,18 @@ class Chef
242
242
  objADOStream.SaveToFile path
243
243
  objADOStream.Close
244
244
  Set objADOStream = Nothing
245
+ ElseIf objXMLHTTP.Status = 400 Then
246
+ errorBody = objXMLHTTP.ResponseText
247
+ WScript.Echo "Error: 400 BadRequest"
248
+ WScript.Echo "Error Body:"
249
+ WScript.Echo errorBody
250
+ Else
251
+ WScript.Echo "An error occurred while downloading the file:"
252
+ errorBody = objXMLHTTP.ResponseText
253
+ WScript.Echo "Status: "
254
+ WScript.Echo objXMLHTTP.Status
255
+ WScript.Echo "Status Text: "
256
+ WScript.Echo errorBody
245
257
  End If
246
258
  Set objXMLHTTP = Nothing
247
259
  End If
@@ -266,7 +278,28 @@ class Chef
266
278
  $WebClient.Proxy = $WebProxy
267
279
  }
268
280
 
269
- $webClient.DownloadFile($remoteUrl, $localPath);
281
+ try {
282
+ $webClient.DownloadFile($remoteUrl, $localPath);
283
+
284
+ Write-Host "Download complete. The file has been saved to $localPath."
285
+ } catch [System.Net.WebException] {
286
+ $response = $_.Exception.Response
287
+
288
+ if ($response.StatusCode -eq [System.Net.HttpStatusCode]::BadRequest) {
289
+ $streamReader = New-Object System.IO.StreamReader($response.GetResponseStream())
290
+ $errorBody = $streamReader.ReadToEnd()
291
+ $streamReader.Dispose()
292
+
293
+ Write-Host "Error: 400 BadRequest"
294
+ Write-Host "Error Body:"
295
+ Write-Host $errorBody
296
+ }
297
+ else {
298
+ Write-Host "An error occurred while downloading the file:"
299
+ Write-Host $_.Exception.Message
300
+ }
301
+ Exit 1
302
+ }
270
303
  WGET_PS
271
304
 
272
305
  escape_and_echo(win_wget_ps)
@@ -297,11 +330,16 @@ class Chef
297
330
  # Build a URL that will redirect to the correct Chef Infra msi download.
298
331
  def msi_url(machine_os = nil, machine_arch = nil, download_context = nil)
299
332
  if config[:msi_url].nil? || config[:msi_url].empty?
300
- url = "https://omnitruck.chef.io/chef/download?p=windows"
333
+ url = if config[:license_url]
334
+ format(config[:license_url], config[:channel]) + "/chef/download?p=windows"
335
+ else
336
+ "https://omnitruck.chef.io/chef/download?p=windows"
337
+ end
301
338
  url += "&pv=#{machine_os}" unless machine_os.nil?
302
339
  url += "&m=#{machine_arch}" unless machine_arch.nil?
303
340
  url += "&DownloadContext=#{download_context}" unless download_context.nil?
304
- url += "&channel=#{config[:channel]}"
341
+ url += "&channel=#{config[:channel]}" if config[:license_url].blank?
342
+ url += "&license_id=#{config[:license_id]}" unless config[:license_id].blank?
305
343
  url += "&v=#{version_to_install}"
306
344
  else
307
345
  config[:msi_url]
@@ -0,0 +1,52 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
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
+
18
+ require_relative "../knife"
19
+
20
+ class Chef
21
+ class Knife
22
+ class License < Chef::Knife
23
+ category "license"
24
+ banner <<~BANNER
25
+ knife license [--chef-license-key <LICENSE_KEY>]
26
+ knife license list
27
+ knife license add [--chef-license-key <LICENSE_KEY>]
28
+ BANNER
29
+
30
+ deps do
31
+ require "chef/utils/licensing_handler" unless defined?(ChefLicensing)
32
+ end
33
+
34
+ option :chef_license_key,
35
+ long: "--chef-license-key <KEY>",
36
+ description: "Free/Trial/Commercial License key to activate the Chef product"
37
+
38
+ def run
39
+ case ARGV[1]
40
+ when "list"
41
+ ChefLicensing.list_license_keys_info
42
+ when "add"
43
+ ChefLicensing.add_license
44
+ else
45
+ ChefLicensing.fetch_and_persist.each do |key|
46
+ ui.msg("License_key: #{key}")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -17,7 +17,7 @@
17
17
  class Chef
18
18
  class Knife
19
19
  KNIFE_ROOT = File.expand_path("../..", __dir__)
20
- VERSION = "18.5.0".freeze
20
+ VERSION = "18.6.2".freeze
21
21
  end
22
22
  end
23
23
 
@@ -0,0 +1,9 @@
1
+ require "chef-licensing"
2
+
3
+ ChefLicensing.configure do |config|
4
+ config.chef_product_name = "Knife"
5
+ config.chef_entitlement_id = "x6f3bc76-a94f-4b6c-bc97-4b7ed2b045c0"
6
+ config.chef_executable_name = "knife"
7
+ config.license_server_url = "https://services.chef.io/licensing"
8
+ end
9
+
@@ -0,0 +1,46 @@
1
+ require_relative "licensing_config"
2
+
3
+ class Chef
4
+ class Utils
5
+ class LicensingHandler
6
+ LEGACY_OMNITRUCK_URL = "https://omnitruck.chef.io".freeze
7
+
8
+ OMNITRUCK_URLS = {
9
+ "free" => "https://chefdownload-trial.chef.io",
10
+ "trial" => "https://chefdownload-trial.chef.io",
11
+ "commercial" => "https://chefdownload-commerical.chef.io",
12
+ }.freeze
13
+
14
+ attr_reader :license_key, :license_type
15
+
16
+ def initialize(key, type)
17
+ @license_key = key
18
+ @license_type = type
19
+ end
20
+
21
+ def omnitruck_url
22
+ url = OMNITRUCK_URLS[license_type] || LEGACY_OMNITRUCK_URL
23
+
24
+ "#{url}/%s#{license_key ? "?license_id=#{license_key}" : ""}"
25
+ end
26
+
27
+ def install_sh_url
28
+ format(omnitruck_url, "install.sh")
29
+ end
30
+
31
+ class << self
32
+ def validate!
33
+ license_keys = ChefLicensing::LicenseKeyFetcher.fetch
34
+
35
+ return new(nil, nil) if license_keys.blank?
36
+
37
+ licenses_metadata = ChefLicensing::Api::Describe.list({
38
+ license_keys: license_keys,
39
+ })
40
+
41
+ new(licenses_metadata.last.id, licenses_metadata.last.license_type)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -50,7 +50,7 @@ describe Chef::Knife::Bootstrap do
50
50
  k
51
51
  end
52
52
 
53
- context "#check_license" do
53
+ context "#check_eula_license" do
54
54
  let(:acceptor) { instance_double(LicenseAcceptance::Acceptor) }
55
55
 
56
56
  before do
@@ -60,7 +60,7 @@ describe Chef::Knife::Bootstrap do
60
60
  describe "when a license is not required" do
61
61
  it "does not set the chef_license" do
62
62
  expect(acceptor).to receive(:license_required?).and_return(false)
63
- knife.check_license
63
+ knife.check_eula_license
64
64
  expect(Chef::Config[:chef_license]).to eq(nil)
65
65
  end
66
66
  end
@@ -71,7 +71,7 @@ describe Chef::Knife::Bootstrap do
71
71
  expect(acceptor).to receive(:id_from_mixlib).and_return("id")
72
72
  expect(acceptor).to receive(:check_and_persist)
73
73
  expect(acceptor).to receive(:acceptance_value).and_return("accept-no-persist")
74
- knife.check_license
74
+ knife.check_eula_license
75
75
  expect(Chef::Config[:chef_license]).to eq("accept-no-persist")
76
76
  end
77
77
  end
@@ -347,7 +347,7 @@ describe Chef::Knife::Bootstrap do
347
347
  knife.parse_options(["--json-attribute-file", jsonfile.path])
348
348
  knife.merge_configs
349
349
  allow(knife).to receive(:validate_name_args!)
350
- expect(knife).to receive(:check_license)
350
+ expect(knife).to receive(:check_eula_license)
351
351
 
352
352
  expect { knife.run }.to raise_error(Chef::Exceptions::BootstrapCommandInputError)
353
353
  jsonfile.close
@@ -1686,7 +1686,7 @@ describe Chef::Knife::Bootstrap do
1686
1686
  end
1687
1687
  describe "#run" do
1688
1688
  it "performs the steps we expect to run a bootstrap" do
1689
- expect(knife).to receive(:check_license)
1689
+ expect(knife).to receive(:check_eula_license)
1690
1690
  expect(knife).to receive(:validate_name_args!).ordered
1691
1691
  expect(knife).to receive(:validate_protocol!).ordered
1692
1692
  expect(knife).to receive(:validate_first_boot_attributes!).ordered
@@ -1956,7 +1956,7 @@ describe Chef::Knife::Bootstrap do
1956
1956
 
1957
1957
  it "verifies that a server to bootstrap was given as a command line arg" do
1958
1958
  knife.name_args = nil
1959
- expect(knife).to receive(:check_license)
1959
+ expect(knife).to receive(:check_eula_license)
1960
1960
  expect { knife.run }.to raise_error(SystemExit)
1961
1961
  expect(stderr.string).to match(/ERROR:.+FQDN or ip/)
1962
1962
  end
@@ -0,0 +1,90 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
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
+
18
+ require "knife_spec_helper"
19
+ require "chef-licensing"
20
+
21
+ describe Chef::Knife::License do
22
+ include SpecHelpers::Knife
23
+
24
+ let(:knife) { described_class.new }
25
+
26
+ context "arguments" do
27
+ it "should have the chef-license-key as an option" do
28
+ expect(knife.options).to include(:chef_license_key)
29
+ end
30
+ end
31
+
32
+ context "license command" do
33
+ it "should invoke the fetch and persist" do
34
+ expect(ChefLicensing).to receive(:fetch_and_persist).and_return([])
35
+
36
+ knife.run
37
+ end
38
+
39
+ it "should print the key returned from the chef-licensing" do
40
+ allow(ChefLicensing).to receive(:fetch_and_persist).and_return(["key-123"])
41
+
42
+ expect(knife.run).to eq(["key-123"])
43
+ expect(knife.ui).to receive(:msg).and_return("License Key: key-123")
44
+ knife.run
45
+ end
46
+
47
+ it "should fail if no license provided" do
48
+ allow(STDOUT).to receive(:isatty).and_return(false)
49
+ ChefLicensing.configure do |c|
50
+ c.output = STDOUT
51
+ end
52
+
53
+ expect { knife.run }.to raise_error(ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError, "Unable to obtain a License Key.")
54
+ end
55
+ end
56
+
57
+ context "license list command" do
58
+ before do
59
+ allow(STDOUT).to receive(:isatty).and_return(false)
60
+ ChefLicensing.configure do |c|
61
+ c.output = STDOUT
62
+ end
63
+ end
64
+
65
+ it "should invoke list command method" do
66
+ with_argv(%w{license list}) do
67
+ expect(ChefLicensing).to receive(:list_license_keys_info).and_return(["key-123"])
68
+
69
+ knife.run
70
+ end
71
+ end
72
+ end
73
+
74
+ context "license add command" do
75
+ before do
76
+ allow(STDOUT).to receive(:isatty).and_return(false)
77
+ ChefLicensing.configure do |c|
78
+ c.output = STDOUT
79
+ end
80
+ end
81
+
82
+ it "should invoke license add method" do
83
+ with_argv(%w{license add --chef-license-key key-123}) do
84
+ expect(ChefLicensing).to receive(:add_license).and_return(true)
85
+
86
+ knife.run
87
+ end
88
+ end
89
+ end
90
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife
3
3
  version: !ruby/object:Gem::Version
4
- version: 18.5.0
4
+ version: 18.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Jacob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-29 00:00:00.000000000 Z
11
+ date: 2024-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-config
@@ -368,6 +368,20 @@ dependencies:
368
368
  - - "~>"
369
369
  - !ruby/object:Gem::Version
370
370
  version: '1.1'
371
+ - !ruby/object:Gem::Dependency
372
+ name: chef-licensing
373
+ requirement: !ruby/object:Gem::Requirement
374
+ requirements:
375
+ - - "~>"
376
+ - !ruby/object:Gem::Version
377
+ version: '1.0'
378
+ type: :runtime
379
+ prerelease: false
380
+ version_requirements: !ruby/object:Gem::Requirement
381
+ requirements:
382
+ - - "~>"
383
+ - !ruby/object:Gem::Version
384
+ version: '1.0'
371
385
  description: The knife CLI for Chef Infra.
372
386
  email: adam@chef.io
373
387
  executables:
@@ -475,6 +489,7 @@ files:
475
489
  - lib/chef/knife/key_list.rb
476
490
  - lib/chef/knife/key_list_base.rb
477
491
  - lib/chef/knife/key_show.rb
492
+ - lib/chef/knife/license.rb
478
493
  - lib/chef/knife/list.rb
479
494
  - lib/chef/knife/node_bulk_delete.rb
480
495
  - lib/chef/knife/node_create.rb
@@ -553,6 +568,8 @@ files:
553
568
  - lib/chef/knife/version.rb
554
569
  - lib/chef/knife/xargs.rb
555
570
  - lib/chef/knife/yaml_convert.rb
571
+ - lib/chef/utils/licensing_config.rb
572
+ - lib/chef/utils/licensing_handler.rb
556
573
  - spec/data/apt/chef-integration-test-1.0/debian/changelog
557
574
  - spec/data/apt/chef-integration-test-1.0/debian/compat
558
575
  - spec/data/apt/chef-integration-test-1.0/debian/control
@@ -1063,6 +1080,7 @@ files:
1063
1080
  - spec/unit/knife/key_helper.rb
1064
1081
  - spec/unit/knife/key_list_spec.rb
1065
1082
  - spec/unit/knife/key_show_spec.rb
1083
+ - spec/unit/knife/license_spec.rb
1066
1084
  - spec/unit/knife/node_bulk_delete_spec.rb
1067
1085
  - spec/unit/knife/node_delete_spec.rb
1068
1086
  - spec/unit/knife/node_edit_spec.rb
@@ -1145,7 +1163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1145
1163
  - !ruby/object:Gem::Version
1146
1164
  version: '0'
1147
1165
  requirements: []
1148
- rubygems_version: 3.3.26
1166
+ rubygems_version: 3.3.27
1149
1167
  signing_key:
1150
1168
  specification_version: 4
1151
1169
  summary: The knife CLI for Chef Infra.