chef-config 13.6.4 → 13.7.16

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
  SHA1:
3
- metadata.gz: f0968dc4c615d0642e82e8462d97c17d78c158ef
4
- data.tar.gz: 13d09213de2fcaeb6098f2c5522a2d95445a5dfe
3
+ metadata.gz: c1d509df602bb95a13b5ac06864f420dd0ae1fcf
4
+ data.tar.gz: 4924ec21b6dc5c39efd835550d022df3555e0625
5
5
  SHA512:
6
- metadata.gz: 5e0bcd3c9823245148fe74fbeefe0cd3014727243f2faec5e22fec2a727434fc19c67fc171520488d09ea4e44a1df2dc328b110ddff3bd43f6fad651b0e3d15f
7
- data.tar.gz: cc4d1bcc23f499b3acbbde229b46bccc6fa1997435967918d62af16a315da4b64d15ed12e318fd55d15fb9040dbd7824b9251963f757ac2bcd3ac6edc965ef0b
6
+ metadata.gz: c2fbec33c4d7f638e18f55021bb13f9accfe0e5dfedd1c25b0c0cf7f9d04518949ba1ea39ac48422eb00fd8cbfad91661e7704b457aba4c2ebaf0988cc76e58e
7
+ data.tar.gz: 279f3af2f42c46c910215a5580032e7c90edde23ee9af3bc017ae58b66596fe3c160e3f222d29c27d16b133f4d38d36da5bdbe73762672a19f4e8e0c1ba70f18
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.add_dependency "mixlib-config", "~> 2.0"
20
20
  spec.add_dependency "fuzzyurl"
21
21
  spec.add_dependency "addressable"
22
+ spec.add_dependency "tomlrb", "~> 1.2"
22
23
 
23
24
  spec.add_development_dependency "rake", "~> 10.0"
24
25
 
@@ -592,6 +592,12 @@ module ChefConfig
592
592
  # If chef-zero is enabled, this defaults to nil (no authentication).
593
593
  default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
594
594
 
595
+ # A credentials file may contain a complete client key, rather than the path
596
+ # to one.
597
+ #
598
+ # We'll use this preferentially.
599
+ default :client_key_contents, nil
600
+
595
601
  # When registering the client, should we allow the client key location to
596
602
  # be a symlink? eg: /etc/chef/client.pem -> /etc/chef/prod-client.pem
597
603
  # If the path of the key goes through a directory like /tmp this should
@@ -631,6 +637,7 @@ module ChefConfig
631
637
  default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") }
632
638
  default :validation_client_name, "chef-validator"
633
639
 
640
+ default :validation_key_contents, nil
634
641
  # When creating a new client via the validation_client account, Chef 11
635
642
  # servers allow the client to generate a key pair locally and send the
636
643
  # public key to the server. This is more secure and helps offload work from
@@ -691,6 +698,9 @@ module ChefConfig
691
698
  # on running chef-client
692
699
  default :count_log_resource_updates, true
693
700
 
701
+ # The selected profile when using credentials.
702
+ default :profile, nil
703
+
694
704
  # knife configuration data
695
705
  config_context :knife do
696
706
  # XXX: none of these default values are applied to knife (and would create a backcompat
@@ -0,0 +1,57 @@
1
+ #
2
+ # Copyright:: Copyright 2017, 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 "tomlrb"
19
+ require "chef-config/path_helper"
20
+
21
+ module ChefConfig
22
+ module Mixin
23
+ module Credentials
24
+
25
+ def load_credentials(profile = nil)
26
+ credentials_file = PathHelper.home(".chef", "credentials").freeze
27
+ context_file = PathHelper.home(".chef", "context").freeze
28
+
29
+ return unless File.file?(credentials_file)
30
+
31
+ context = File.read(context_file) if File.file?(context_file)
32
+
33
+ environment = ENV.fetch("CHEF_PROFILE", nil)
34
+
35
+ profile = if !profile.nil?
36
+ profile
37
+ elsif !environment.nil?
38
+ environment
39
+ elsif !context.nil?
40
+ context
41
+ else
42
+ "default"
43
+ end
44
+
45
+ config = Tomlrb.load_file(credentials_file)
46
+ apply_credentials(config[profile], profile)
47
+ rescue ChefConfig::ConfigurationError
48
+ raise
49
+ rescue => e
50
+ # TOML's error messages are mostly rubbish, so we'll just give a generic one
51
+ message = "Unable to parse Credentials file: #{credentials_file}\n"
52
+ message << e.message
53
+ raise ChefConfig::ConfigurationError, message
54
+ end
55
+ end
56
+ end
57
+ end
@@ -235,7 +235,7 @@ module ChefConfig
235
235
  paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
236
236
 
237
237
  # Filter out duplicate paths and paths that don't exist.
238
- valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path.force_encoding("utf-8")) }
238
+ valid_paths = paths.select { |home_path| home_path && Dir.exist?(home_path.force_encoding("utf-8")) }
239
239
  valid_paths = valid_paths.uniq
240
240
 
241
241
  # Join all optional path elements at the end.
@@ -21,7 +21,7 @@
21
21
 
22
22
  module ChefConfig
23
23
  CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__)
24
- VERSION = "13.6.4"
24
+ VERSION = "13.7.16"
25
25
  end
26
26
 
27
27
  #
@@ -22,24 +22,31 @@ require "chef-config/logger"
22
22
  require "chef-config/path_helper"
23
23
  require "chef-config/windows"
24
24
  require "chef-config/mixin/dot_d"
25
+ require "chef-config/mixin/credentials"
25
26
 
26
27
  module ChefConfig
27
28
  class WorkstationConfigLoader
28
29
  include ChefConfig::Mixin::DotD
30
+ include ChefConfig::Mixin::Credentials
29
31
 
30
32
  # Path to a config file requested by user, (e.g., via command line option). Can be nil
31
33
  attr_accessor :explicit_config_file
34
+ # The name of a credentials profile. Can be nil
35
+ attr_accessor :profile
36
+ attr_reader :credentials_found
32
37
 
33
38
  # TODO: initialize this with a logger for Chef and Knife
34
- def initialize(explicit_config_file, logger = nil)
39
+ def initialize(explicit_config_file, logger = nil, profile: nil)
35
40
  @explicit_config_file = explicit_config_file
36
41
  @chef_config_dir = nil
37
42
  @config_location = nil
43
+ @profile = profile
38
44
  @logger = logger || NullLogger.new
45
+ @credentials_found = false
39
46
  end
40
47
 
41
48
  def no_config_found?
42
- config_location.nil?
49
+ config_location.nil? && !credentials_found
43
50
  end
44
51
 
45
52
  def config_location
@@ -62,6 +69,7 @@ module ChefConfig
62
69
  end
63
70
 
64
71
  def load
72
+ load_credentials(profile)
65
73
  # Ignore it if there's no explicit_config_file and can't find one at a
66
74
  # default path.
67
75
  if !config_location.nil?
@@ -138,6 +146,38 @@ module ChefConfig
138
146
  a
139
147
  end
140
148
 
149
+ def apply_credentials(creds, profile)
150
+ Config.profile ||= profile
151
+ if creds.key?("node_name") && creds.key?("client_name")
152
+ raise ChefConfig::ConfigurationError, "Do not specify both node_name and client_name. You should prefer client_name."
153
+ end
154
+ Config.node_name = creds.fetch("node_name") if creds.key?("node_name")
155
+ Config.node_name = creds.fetch("client_name") if creds.key?("client_name")
156
+ Config.chef_server_url = creds.fetch("chef_server_url") if creds.key?("chef_server_url")
157
+ Config.validation_client_name = creds.fetch("validation_client_name") if creds.key?("validation_client_name")
158
+
159
+ extract_key(creds, "validation_key", :validation_key, :validation_key_contents)
160
+ extract_key(creds, "validator_key", :validation_key, :validation_key_contents)
161
+ extract_key(creds, "client_key", :client_key, :client_key_contents)
162
+ @credentials_found = true
163
+ end
164
+
165
+ def extract_key(creds, name, config_path, config_contents)
166
+ return unless creds.has_key?(name)
167
+
168
+ val = creds.fetch(name)
169
+ if val.start_with?("-----BEGIN RSA PRIVATE KEY-----")
170
+ Config.send(config_contents, val)
171
+ else
172
+ abs_path = Pathname.new(val).expand_path(home_chef_dir)
173
+ Config.send(config_path, abs_path)
174
+ end
175
+ end
176
+
177
+ def home_chef_dir
178
+ @home_chef_dir ||= PathHelper.home(".chef")
179
+ end
180
+
141
181
  def apply_config(config_content, config_file_path)
142
182
  Config.from_string(config_content, config_file_path)
143
183
  rescue SignalException
@@ -38,6 +38,7 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
38
38
  before do
39
39
  # We set this to nil so that a dev workstation will
40
40
  # not interfere with the tests.
41
+ ChefConfig::Config.reset
41
42
  ChefConfig::Config[:config_d_dir] = nil
42
43
  end
43
44
 
@@ -363,4 +364,147 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
363
364
  end
364
365
  end
365
366
  end
367
+
368
+ describe "when loading a credentials file" do
369
+ if ChefConfig.windows?
370
+ let(:home) { "C:/Users/example.user" }
371
+ else
372
+ let(:home) { "/Users/example.user" }
373
+ end
374
+ let(:credentials_file) { "#{home}/.chef/credentials" }
375
+ let(:context_file) { "#{home}/.chef/context" }
376
+
377
+ before do
378
+ allow(ChefConfig::PathHelper).to receive(:home).with(".chef").and_return(File.join(home, ".chef"))
379
+ allow(ChefConfig::PathHelper).to receive(:home).with(".chef", "credentials").and_return(credentials_file)
380
+ allow(ChefConfig::PathHelper).to receive(:home).with(".chef", "context").and_return(context_file)
381
+ allow(File).to receive(:file?).with(context_file).and_return false
382
+ end
383
+
384
+ context "when the file exists" do
385
+ before do
386
+ expect(File).to receive(:read).with(credentials_file, { encoding: "utf-8" }).and_return(content)
387
+ allow(File).to receive(:file?).with(credentials_file).and_return true
388
+ end
389
+
390
+ context "and has a default profile" do
391
+ let(:content) do
392
+ content = <<EOH
393
+ [default]
394
+ node_name = 'barney'
395
+ client_key = "barney_rubble.pem"
396
+ chef_server_url = "https://api.chef.io/organizations/bedrock"
397
+ EOH
398
+ content
399
+ end
400
+
401
+ it "applies the expected config" do
402
+ expect { config_loader.load_credentials }.not_to raise_error
403
+ expect(ChefConfig::Config.chef_server_url).to eq("https://api.chef.io/organizations/bedrock")
404
+ expect(ChefConfig::Config.client_key.to_s).to eq("#{home}/.chef/barney_rubble.pem")
405
+ expect(ChefConfig::Config.profile.to_s).to eq("default")
406
+ end
407
+ end
408
+
409
+ context "and has a profile containing a full key" do
410
+ let(:content) do
411
+ content = <<EOH
412
+ [default]
413
+ client_key = """
414
+ -----BEGIN RSA PRIVATE KEY-----
415
+ foo
416
+ """
417
+ EOH
418
+ content
419
+ end
420
+
421
+ it "applies the expected config" do
422
+ expect { config_loader.load_credentials }.not_to raise_error
423
+ expect(ChefConfig::Config.client_key_contents).to eq(<<EOH
424
+ -----BEGIN RSA PRIVATE KEY-----
425
+ foo
426
+ EOH
427
+ )
428
+ end
429
+ end
430
+
431
+ context "and has several profiles" do
432
+ let(:content) do
433
+ content = <<EOH
434
+ [default]
435
+ client_name = "default"
436
+ [environment]
437
+ client_name = "environment"
438
+ [explicit]
439
+ client_name = "explicit"
440
+ [context]
441
+ client_name = "context"
442
+ EOH
443
+ content
444
+ end
445
+
446
+ let(:env) { {} }
447
+ before do
448
+ stub_const("ENV", env)
449
+ end
450
+
451
+ it "selects the correct profile explicitly" do
452
+ expect { config_loader.load_credentials("explicit") }.not_to raise_error
453
+ expect(ChefConfig::Config.node_name).to eq("explicit")
454
+ end
455
+
456
+ context "with an environment variable" do
457
+ let(:env) { { "CHEF_PROFILE" => "environment" } }
458
+
459
+ it "selects the correct profile" do
460
+ expect { config_loader.load_credentials }.not_to raise_error
461
+ expect(ChefConfig::Config.node_name).to eq("environment")
462
+ end
463
+ end
464
+
465
+ it "selects the correct profile with a context file" do
466
+ allow(File).to receive(:file?).with(context_file).and_return true
467
+ expect(File).to receive(:read).with(context_file).and_return "context"
468
+ expect { config_loader.load_credentials }.not_to raise_error
469
+ expect(ChefConfig::Config.node_name).to eq("context")
470
+ end
471
+
472
+ it "falls back to the default" do
473
+ expect { config_loader.load_credentials }.not_to raise_error
474
+ expect(ChefConfig::Config.node_name).to eq("default")
475
+ end
476
+ end
477
+
478
+ context "and contains both node_name and client_name" do
479
+ let(:content) do
480
+ content = <<EOH
481
+ [default]
482
+ node_name = 'barney'
483
+ client_name = 'barney'
484
+ EOH
485
+ content
486
+ end
487
+
488
+ it "raises a ConfigurationError" do
489
+ expect { config_loader.load_credentials }.to raise_error(ChefConfig::ConfigurationError)
490
+ end
491
+ end
492
+
493
+ context "and has a syntax error" do
494
+ let(:content) { "<<<<<" }
495
+
496
+ it "raises a ConfigurationError" do
497
+ expect { config_loader.load_credentials }.to raise_error(ChefConfig::ConfigurationError)
498
+ end
499
+ end
500
+ end
501
+
502
+ context "when the file does not exist" do
503
+ it "does not load anything" do
504
+ allow(File).to receive(:file?).with(credentials_file).and_return false
505
+ expect(Tomlrb).not_to receive(:load_file)
506
+ config_loader.load_credentials
507
+ end
508
+ end
509
+ end
366
510
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 13.6.4
4
+ version: 13.7.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Jacob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-06 00:00:00.000000000 Z
11
+ date: 2018-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-shellout
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: tomlrb
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -138,6 +152,7 @@ files:
138
152
  - lib/chef-config/exceptions.rb
139
153
  - lib/chef-config/fips.rb
140
154
  - lib/chef-config/logger.rb
155
+ - lib/chef-config/mixin/credentials.rb
141
156
  - lib/chef-config/mixin/dot_d.rb
142
157
  - lib/chef-config/mixin/fuzzy_hostname_matcher.rb
143
158
  - lib/chef-config/package_task.rb