chef-config 18.3.0 → 19.3.15
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 +4 -4
- data/chef-config.gemspec +2 -1
- data/lib/chef-config/config.rb +35 -20
- data/lib/chef-config/exceptions.rb +4 -1
- data/lib/chef-config/fips.rb +1 -1
- data/lib/chef-config/logger.rb +1 -1
- data/lib/chef-config/mixin/credentials.rb +125 -6
- data/lib/chef-config/mixin/dot_d.rb +1 -1
- data/lib/chef-config/mixin/fuzzy_hostname_matcher.rb +6 -1
- data/lib/chef-config/mixin/train_transport.rb +19 -11
- data/lib/chef-config/path_helper.rb +12 -8
- data/lib/chef-config/version.rb +2 -2
- data/lib/chef-config/windows.rb +1 -1
- data/lib/chef-config/workstation_config_loader.rb +1 -1
- data/lib/chef-config.rb +1 -1
- data/spec/unit/config_spec.rb +42 -17
- data/spec/unit/credentials_spec.rb +181 -0
- data/spec/unit/fips_spec.rb +1 -1
- data/spec/unit/fuzzy_hostname_matcher_spec.rb +70 -0
- data/spec/unit/path_helper_spec.rb +1 -1
- data/spec/unit/workstation_config_loader_spec.rb +3 -4
- metadata +29 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2b694ef61ad31b8917bea150e4327931d313d2e930417744dbb6b6ff4150e571
|
|
4
|
+
data.tar.gz: b60d0ccd47adfa4e046ffe14d2bd21f5965ea991b0f5bdd426cff0f336cecba1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21d1abd0ac079d9e9b78c1d967a18a95c73bb8f0c03bd161fdba41b655d590dbaec0194bd7d5bd641bcacfc34ca51497c08113e2296902bc9a97c0cd54a79892
|
|
7
|
+
data.tar.gz: 6e600ea85ccaa3140566b71b4068a81e50290e18140dce57e57a1af1c19fc64d3e68d20c573b04303a91a33388d029af7713d3ed7396918b3db46c13c3f87dbc
|
data/chef-config.gemspec
CHANGED
|
@@ -29,7 +29,8 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
spec.add_dependency "mixlib-config", ">= 2.2.12", "< 4.0"
|
|
30
30
|
spec.add_dependency "fuzzyurl"
|
|
31
31
|
spec.add_dependency "addressable"
|
|
32
|
-
spec.add_dependency "tomlrb", "
|
|
32
|
+
spec.add_dependency "tomlrb", ">= 1.2", "< 3.0"
|
|
33
|
+
spec.add_dependency "racc"
|
|
33
34
|
|
|
34
35
|
spec.files = %w{Rakefile LICENSE} + Dir.glob("*.gemspec") +
|
|
35
36
|
Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
|
data/lib/chef-config/config.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Author:: AJ Christensen (<aj@chef.io>)
|
|
5
5
|
# Author:: Mark Mzyk (<mmzyk@chef.io>)
|
|
6
6
|
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
|
|
7
|
-
# Copyright:: Copyright (c)
|
|
7
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
8
8
|
# License:: Apache License, Version 2.0
|
|
9
9
|
#
|
|
10
10
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -97,8 +97,11 @@ module ChefConfig
|
|
|
97
97
|
# @return [String] the platform-specific path
|
|
98
98
|
#
|
|
99
99
|
def self.var_chef_dir(windows: ChefUtils.windows?)
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
@var_chef_dir ||= {}
|
|
101
|
+
@var_chef_dir[windows] ||= begin
|
|
102
|
+
path = windows ? c_chef_dir : PathHelper.join("/var", ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
|
|
103
|
+
PathHelper.cleanpath(path, windows: windows)
|
|
104
|
+
end
|
|
102
105
|
end
|
|
103
106
|
|
|
104
107
|
# On *nix, /var, on Windows C:\
|
|
@@ -107,8 +110,11 @@ module ChefConfig
|
|
|
107
110
|
# @return [String] the platform-specific path
|
|
108
111
|
#
|
|
109
112
|
def self.var_root_dir(windows: ChefUtils.windows?)
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
@var_root_dir ||= {}
|
|
114
|
+
@var_root_dir[windows] ||= begin
|
|
115
|
+
path = windows ? "C:\\" : "/var"
|
|
116
|
+
PathHelper.cleanpath(path, windows: windows)
|
|
117
|
+
end
|
|
112
118
|
end
|
|
113
119
|
|
|
114
120
|
# On windows, C:/chef/
|
|
@@ -415,7 +421,14 @@ module ChefConfig
|
|
|
415
421
|
# If your `file_cache_path` resides on a NFS (or non-flock()-supporting
|
|
416
422
|
# fs), it's recommended to set this to something like
|
|
417
423
|
# '/tmp/chef-client-running.pid'
|
|
418
|
-
|
|
424
|
+
# In Target Mode, the node name will be used as a prefix to allow
|
|
425
|
+
# parallel execution of Chef against different targets
|
|
426
|
+
default(:lockfile) do
|
|
427
|
+
prefix = ""
|
|
428
|
+
prefix = "#{ChefConfig::Config.node_name}-" if ChefConfig::Config.target_mode?
|
|
429
|
+
|
|
430
|
+
PathHelper.join(file_cache_path, "#{prefix}#{ChefUtils::Dist::Infra::CLIENT}-running.pid")
|
|
431
|
+
end
|
|
419
432
|
|
|
420
433
|
## Daemonization Settings ##
|
|
421
434
|
# What user should Chef run as?
|
|
@@ -471,6 +484,14 @@ module ChefConfig
|
|
|
471
484
|
# toggle info level log items that can create a lot of output
|
|
472
485
|
default :verbose_logging, true
|
|
473
486
|
default :node_name, nil
|
|
487
|
+
|
|
488
|
+
# When target mode is active, these hold the operator's original Chef Server
|
|
489
|
+
# identity so that API auth uses the admin credentials rather than the
|
|
490
|
+
# target node name. Set in Chef::Application::Client#reconfigure before
|
|
491
|
+
# target_mode.enabled is flipped to true.
|
|
492
|
+
default :api_client_name, nil
|
|
493
|
+
default :api_client_key, nil
|
|
494
|
+
|
|
474
495
|
default :diff_disabled, false
|
|
475
496
|
default :diff_filesize_threshold, 10000000
|
|
476
497
|
default :diff_output_threshold, 1000000
|
|
@@ -911,7 +932,11 @@ module ChefConfig
|
|
|
911
932
|
default :profile, nil
|
|
912
933
|
|
|
913
934
|
default :chef_guid_path do
|
|
914
|
-
|
|
935
|
+
if target_mode?
|
|
936
|
+
PathHelper.join(config_dir, target_mode.host, "#{ChefUtils::Dist::Infra::SHORT}_guid")
|
|
937
|
+
else
|
|
938
|
+
PathHelper.join(config_dir, "#{ChefUtils::Dist::Infra::SHORT}_guid")
|
|
939
|
+
end
|
|
915
940
|
end
|
|
916
941
|
|
|
917
942
|
default :chef_guid, nil
|
|
@@ -1047,16 +1072,6 @@ module ChefConfig
|
|
|
1047
1072
|
default :blocked_normal_attributes, nil
|
|
1048
1073
|
default :blocked_override_attributes, nil
|
|
1049
1074
|
|
|
1050
|
-
# deprecated config options that will be removed in Chef Infra Client 18
|
|
1051
|
-
default :automatic_attribute_blacklist, nil
|
|
1052
|
-
default :default_attribute_blacklist, nil
|
|
1053
|
-
default :normal_attribute_blacklist, nil
|
|
1054
|
-
default :override_attribute_blacklist, nil
|
|
1055
|
-
default :automatic_attribute_whitelist, nil
|
|
1056
|
-
default :default_attribute_whitelist, nil
|
|
1057
|
-
default :normal_attribute_whitelist, nil
|
|
1058
|
-
default :override_attribute_whitelist, nil
|
|
1059
|
-
|
|
1060
1075
|
# Pull down all the rubygems versions from rubygems and cache them the first time we do a gem_package or
|
|
1061
1076
|
# chef_gem install. This is memory-expensive and will grow without bounds, but will reduce network
|
|
1062
1077
|
# round trips.
|
|
@@ -1205,7 +1220,7 @@ module ChefConfig
|
|
|
1205
1220
|
end
|
|
1206
1221
|
end
|
|
1207
1222
|
|
|
1208
|
-
|
|
1223
|
+
proxy unless fuzzy_hostname_match_any?(host, ENV["no_proxy"])
|
|
1209
1224
|
end
|
|
1210
1225
|
|
|
1211
1226
|
# Chef requires an English-language UTF-8 locale to function properly. We attempt
|
|
@@ -1299,7 +1314,9 @@ module ChefConfig
|
|
|
1299
1314
|
# sure Chef runs do not crash.
|
|
1300
1315
|
# @api private
|
|
1301
1316
|
def self.enable_fips_mode
|
|
1317
|
+
# Enable FIPS mode in OpenSSL.
|
|
1302
1318
|
OpenSSL.fips_mode = true
|
|
1319
|
+
|
|
1303
1320
|
require "digest" unless defined?(Digest)
|
|
1304
1321
|
require "digest/sha1" unless defined?(Digest::SHA1)
|
|
1305
1322
|
require "digest/md5" unless defined?(Digest::MD5)
|
|
@@ -1307,8 +1324,6 @@ module ChefConfig
|
|
|
1307
1324
|
# amount of log spam and warnings.
|
|
1308
1325
|
Digest.send(:remove_const, "SHA1") if Digest.const_defined?(:SHA1)
|
|
1309
1326
|
Digest.const_set(:SHA1, OpenSSL::Digest::SHA1)
|
|
1310
|
-
OpenSSL::Digest.send(:remove_const, "MD5") if OpenSSL::Digest.const_defined?(:MD5)
|
|
1311
|
-
OpenSSL::Digest.const_set(:MD5, Digest::MD5)
|
|
1312
1327
|
ChefConfig.logger.debug "FIPS mode is enabled."
|
|
1313
1328
|
end
|
|
1314
1329
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -23,5 +23,8 @@ module ChefConfig
|
|
|
23
23
|
class ConfigurationError < ArgumentError; end
|
|
24
24
|
class InvalidPath < StandardError; end
|
|
25
25
|
class UnparsableConfigOption < StandardError; end
|
|
26
|
+
class NoCredentialsFound < StandardError; end
|
|
26
27
|
|
|
28
|
+
class UnsupportedSecretsProvider < ConfigurationError; end
|
|
29
|
+
class UnresolvedSecret < ConfigurationError; end
|
|
27
30
|
end
|
data/lib/chef-config/fips.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Matt Wrock (<matt@mattwrock.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
data/lib/chef-config/logger.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -26,6 +26,8 @@ module ChefConfig
|
|
|
26
26
|
# @since 13.7
|
|
27
27
|
# @api internal
|
|
28
28
|
module Credentials
|
|
29
|
+
attr_reader :credentials_config
|
|
30
|
+
|
|
29
31
|
# Compute the active credentials profile name.
|
|
30
32
|
#
|
|
31
33
|
# The lookup order is argument (from --profile), environment variable
|
|
@@ -54,6 +56,11 @@ module ChefConfig
|
|
|
54
56
|
# @since 14.4
|
|
55
57
|
# @return [String]
|
|
56
58
|
def credentials_file_path
|
|
59
|
+
return Chef::Config[:credentials] if defined?(Chef::Config) && Chef::Config.key?(:credentials)
|
|
60
|
+
|
|
61
|
+
env_file = ENV["CHEF_CREDENTIALS_FILE"]
|
|
62
|
+
return env_file if env_file && File.file?(env_file)
|
|
63
|
+
|
|
57
64
|
PathHelper.home(ChefUtils::Dist::Infra::USER_CONF_DIR, "credentials").freeze
|
|
58
65
|
end
|
|
59
66
|
|
|
@@ -68,7 +75,7 @@ module ChefConfig
|
|
|
68
75
|
return nil unless File.file?(credentials_file)
|
|
69
76
|
|
|
70
77
|
begin
|
|
71
|
-
Tomlrb.load_file(credentials_file)
|
|
78
|
+
@credentials_config = Tomlrb.load_file(credentials_file)
|
|
72
79
|
rescue => e
|
|
73
80
|
# TOML's error messages are mostly rubbish, so we'll just give a generic one
|
|
74
81
|
message = "Unable to parse Credentials file: #{credentials_file}\n"
|
|
@@ -85,17 +92,129 @@ module ChefConfig
|
|
|
85
92
|
# @return [void]
|
|
86
93
|
def load_credentials(profile = nil)
|
|
87
94
|
profile = credentials_profile(profile)
|
|
88
|
-
cred_config = parse_credentials_file
|
|
89
|
-
return if cred_config.nil? # No credentials, nothing to do here.
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
parse_credentials_file
|
|
97
|
+
return if credentials_config.nil? # No credentials, nothing to do here.
|
|
98
|
+
|
|
99
|
+
if credentials_config[profile].nil?
|
|
92
100
|
# Unknown profile name. For "default" just silently ignore, otherwise
|
|
93
101
|
# raise an error.
|
|
94
102
|
return if profile == "default"
|
|
95
103
|
|
|
96
104
|
raise ChefConfig::ConfigurationError, "Profile #{profile} doesn't exist. Please add it to #{credentials_file_path}."
|
|
97
105
|
end
|
|
98
|
-
|
|
106
|
+
|
|
107
|
+
resolve_secrets(profile)
|
|
108
|
+
|
|
109
|
+
apply_credentials(credentials_config[profile], profile)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
GLOBAL_CONFIG_HASHES = %w{ default_secrets_provider }.freeze
|
|
113
|
+
|
|
114
|
+
# Extract global (non-profile) settings from credentials file.
|
|
115
|
+
#
|
|
116
|
+
# @since 19.1
|
|
117
|
+
# @return [Hash]
|
|
118
|
+
def global_options
|
|
119
|
+
globals = credentials_config.filter { |_, v| v.is_a? String }
|
|
120
|
+
globals.merge! credentials_config.filter { |k, _| GLOBAL_CONFIG_HASHES.include? k }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
SUPPORTED_SECRETS_PROVIDERS = %w{ hashicorp-vault }.freeze
|
|
124
|
+
|
|
125
|
+
# Resolve all secrets in a credentials file
|
|
126
|
+
#
|
|
127
|
+
# @since 19.1
|
|
128
|
+
# @param profile [String] Profile to resolve secrets in.
|
|
129
|
+
# @return [Hash]
|
|
130
|
+
def resolve_secrets(profile)
|
|
131
|
+
return unless credentials_config
|
|
132
|
+
raise NoCredentialsFound.new("No credentials found for profile '#{profile}'") unless credentials_config[profile]
|
|
133
|
+
|
|
134
|
+
secrets = credentials_config[profile].filter { |k, v| v.is_a?(Hash) && v.keys.include?("secret") }
|
|
135
|
+
return if secrets.empty?
|
|
136
|
+
|
|
137
|
+
secrets.each do |option, secrets_config|
|
|
138
|
+
unless valid_secrets_provider?(secrets_config)
|
|
139
|
+
raise UnsupportedSecretsProvider.new("Unsupported credentials secrets provider on '#{option}' for profile '#{profile}'")
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
secrets_config.merge!(default_secrets_provider)
|
|
143
|
+
|
|
144
|
+
logger.debug("Resolving credentials secret '#{option}' for profile '#{profile}'")
|
|
145
|
+
begin
|
|
146
|
+
resolved_value = resolve_secret(secrets_config)
|
|
147
|
+
ensure
|
|
148
|
+
raise UnresolvedSecret.new("Could not resolve secret '#{option}' for profile '#{profile}'") if resolved_value.nil?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
credentials_config[profile][option] = resolved_value
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Check, if referenced secrets provider is supported.
|
|
156
|
+
#
|
|
157
|
+
# @since 19.1
|
|
158
|
+
# @param secrets_config [Hash] Parsed contents of a secret in a profile.
|
|
159
|
+
# @return [true, false]
|
|
160
|
+
def valid_secrets_provider?(secrets_config)
|
|
161
|
+
provider_config = secrets_config["secrets_provider"] || default_secrets_provider
|
|
162
|
+
provider = provider_config["name"]
|
|
163
|
+
|
|
164
|
+
provider && SUPPORTED_SECRETS_PROVIDERS.include?(provider)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def default_secrets_provider
|
|
168
|
+
global_options["default_secrets_provider"]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Resolve a specific secret.
|
|
172
|
+
#
|
|
173
|
+
# To be replaced later by a Train-like framework to support multiple backends.
|
|
174
|
+
#
|
|
175
|
+
# @since 19.1
|
|
176
|
+
# @param secrets_config [Hash] Parsed contents of a secret in a profile.
|
|
177
|
+
# @return [String]
|
|
178
|
+
def resolve_secret(secrets_config)
|
|
179
|
+
resolve_secret_hashicorp(secrets_config)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Resolver logic for Hashicorp Vault.
|
|
183
|
+
#
|
|
184
|
+
# Local lazy loading of Gems which are not part of chef-config or chef-utils,
|
|
185
|
+
# but chef itself to be switched by a unified secrets mechanism for credentials
|
|
186
|
+
# and Chef DSL later. Showstopper mitigation for 19 GA.
|
|
187
|
+
#
|
|
188
|
+
# @since 19.1
|
|
189
|
+
# @param secrets_config [Hash] Parsed contents of a secret in a profile.
|
|
190
|
+
# @return [String]
|
|
191
|
+
def resolve_secret_hashicorp(secrets_config)
|
|
192
|
+
vault_config = secrets_config.transform_keys(&:to_sym)
|
|
193
|
+
vault_config[:address] = vault_config[:endpoint]
|
|
194
|
+
|
|
195
|
+
# Lazy require due to Gem being part of Chef and rarely used functionality
|
|
196
|
+
require "vault" unless defined? Vault
|
|
197
|
+
@vault ||= Vault::Client.new(vault_config)
|
|
198
|
+
|
|
199
|
+
secret = secrets_config["secret"]
|
|
200
|
+
engine = vault_config[:engine] || "secret"
|
|
201
|
+
engine_type = vault_config[:engine_type] || "kv2"
|
|
202
|
+
secret_value = case engine_type
|
|
203
|
+
when "kv", "kv1"
|
|
204
|
+
@vault.logical.read("#{engine_type}/#{secret}")
|
|
205
|
+
when "kv2"
|
|
206
|
+
@vault.kv(engine).read(secret)&.data
|
|
207
|
+
else
|
|
208
|
+
raise UnsupportedSecretsProvider.new("No support for secrets engine #{engine_type}")
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Always JSON for Hashicorp Vault, but this is future compatible to other providers
|
|
212
|
+
if secret_value.is_a?(Hash)
|
|
213
|
+
require "jmespath" unless defined? ::JMESPath
|
|
214
|
+
::JMESPath.search(secrets_config["field"], secret_value)
|
|
215
|
+
else
|
|
216
|
+
secret_value
|
|
217
|
+
end
|
|
99
218
|
end
|
|
100
219
|
end
|
|
101
220
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -42,6 +42,11 @@ module ChefConfig
|
|
|
42
42
|
# Do greedy matching by adding wildcard if it is not specified
|
|
43
43
|
match = "*" + match unless match.start_with?("*")
|
|
44
44
|
Fuzzyurl.matches?(Fuzzyurl.mask(hostname: match), hostname)
|
|
45
|
+
rescue ArgumentError
|
|
46
|
+
# Fuzzyurl cannot parse certain URL formats, notably IPv6 addresses
|
|
47
|
+
# (bare, bracketed, or embedded in URLs). When parsing fails, the URL
|
|
48
|
+
# cannot match a no_proxy pattern, so return false.
|
|
49
|
+
false
|
|
45
50
|
end
|
|
46
51
|
|
|
47
52
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Author:: Bryan McLellan <btm@loftninjas.org>
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -36,15 +36,17 @@ module ChefConfig
|
|
|
36
36
|
#
|
|
37
37
|
def load_credentials(profile)
|
|
38
38
|
# Tomlrb.load_file returns a hash with keys as strings
|
|
39
|
-
|
|
40
|
-
if contains_split_fqdn?(
|
|
39
|
+
credentials_config = parse_credentials_file
|
|
40
|
+
if contains_split_fqdn?(credentials_config, profile)
|
|
41
41
|
logger.warn("Credentials file #{credentials_file_path} contains target '#{profile}' as a Hash, expected a string.")
|
|
42
42
|
logger.warn("Hostnames must be surrounded by single quotes, e.g. ['host.example.org']")
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
resolve_secrets(profile)
|
|
46
|
+
|
|
45
47
|
# host names must be specified in credentials file as ['foo.example.org'] with quotes
|
|
46
|
-
if !
|
|
47
|
-
|
|
48
|
+
if !credentials_config.nil? && !credentials_config[profile].nil?
|
|
49
|
+
credentials_config[profile].transform_keys(&:to_sym) # return symbolized keys to match Train.options()
|
|
48
50
|
else
|
|
49
51
|
nil
|
|
50
52
|
end
|
|
@@ -59,6 +61,8 @@ module ChefConfig
|
|
|
59
61
|
# This will be a common mistake so we should catch it
|
|
60
62
|
#
|
|
61
63
|
def contains_split_fqdn?(hash, fqdn)
|
|
64
|
+
return unless fqdn.include?(".")
|
|
65
|
+
|
|
62
66
|
fqdn.split(".").reduce(hash) do |h, k|
|
|
63
67
|
v = h[k]
|
|
64
68
|
if Hash === v
|
|
@@ -74,21 +78,25 @@ module ChefConfig
|
|
|
74
78
|
#
|
|
75
79
|
# Credentials file preference:
|
|
76
80
|
#
|
|
77
|
-
# 1)
|
|
78
|
-
# 2)
|
|
79
|
-
# 3)
|
|
81
|
+
# 1) environment variable CHEF_CREDENTIALS_FILE
|
|
82
|
+
# 2) target_mode.credentials_file
|
|
83
|
+
# 3) /etc/chef/TARGET_MODE_HOST/credentials
|
|
84
|
+
# 4) user configuration ($HOME/.chef/target_credentials)
|
|
80
85
|
#
|
|
81
86
|
def credentials_file_path
|
|
82
87
|
tm_config = config.target_mode
|
|
83
88
|
profile = tm_config.host
|
|
84
89
|
|
|
90
|
+
env_file = ENV["CHEF_CREDENTIALS_FILE"]
|
|
85
91
|
credentials_file =
|
|
86
|
-
if
|
|
92
|
+
if env_file && File.exist?(env_file)
|
|
93
|
+
env_file
|
|
94
|
+
elsif tm_config.credentials_file && File.exist?(tm_config.credentials_file)
|
|
87
95
|
tm_config.credentials_file
|
|
88
96
|
elsif File.exist?(config.platform_specific_path("#{ChefConfig::Config.etc_chef_dir}/#{profile}/credentials"))
|
|
89
97
|
config.platform_specific_path("#{ChefConfig::Config.etc_chef_dir}/#{profile}/credentials")
|
|
90
98
|
else
|
|
91
|
-
|
|
99
|
+
PathHelper.home(ChefUtils::Dist::Infra::USER_CONF_DIR, "target_credentials").freeze
|
|
92
100
|
end
|
|
93
101
|
|
|
94
102
|
raise ArgumentError, "No credentials file found for target '#{profile}'" unless credentials_file
|
|
@@ -112,7 +120,7 @@ module ChefConfig
|
|
|
112
120
|
# Load the credentials file, and place any valid settings into the train configuration
|
|
113
121
|
credentials = load_credentials(tm_config.host)
|
|
114
122
|
|
|
115
|
-
protocol = credentials
|
|
123
|
+
protocol = credentials&.dig(:transport_protocol) || tm_config.protocol
|
|
116
124
|
train_config = tm_config.to_hash.select { |k| Train.options(protocol).key?(k) }
|
|
117
125
|
logger.trace("Using target mode options from #{ChefUtils::Dist::Infra::PRODUCT} config file: #{train_config.keys.join(", ")}") if train_config
|
|
118
126
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Bryan McLellan <btm@loftninjas.org>
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -57,13 +57,16 @@ module ChefConfig
|
|
|
57
57
|
|
|
58
58
|
def self.join(*args, windows: ChefUtils.windows?)
|
|
59
59
|
path_separator_regex = Regexp.escape(windows ? "#{File::SEPARATOR}#{BACKSLASH}" : File::SEPARATOR)
|
|
60
|
-
trailing_slashes_regex = /[#{path_separator_regex}]
|
|
61
|
-
leading_slashes_regex = /^[#{path_separator_regex}]
|
|
60
|
+
trailing_slashes_regex = /[#{path_separator_regex}]+$/
|
|
61
|
+
leading_slashes_regex = /^[#{path_separator_regex}]+/
|
|
62
|
+
separator = path_separator(windows: windows)
|
|
62
63
|
|
|
63
|
-
args.flatten
|
|
64
|
+
args.flatten!
|
|
65
|
+
args.inject do |joined_path, component|
|
|
64
66
|
joined_path = joined_path.sub(trailing_slashes_regex, "")
|
|
65
67
|
component = component.sub(leading_slashes_regex, "")
|
|
66
|
-
joined_path
|
|
68
|
+
joined_path << "#{separator}#{component}"
|
|
69
|
+
joined_path
|
|
67
70
|
end
|
|
68
71
|
end
|
|
69
72
|
|
|
@@ -149,11 +152,12 @@ module ChefConfig
|
|
|
149
152
|
path = Pathname.new(path).cleanpath.to_s
|
|
150
153
|
if windows
|
|
151
154
|
# ensure all forward slashes are backslashes
|
|
152
|
-
path.gsub(File::SEPARATOR, path_separator(windows: windows))
|
|
155
|
+
path.gsub!(File::SEPARATOR, path_separator(windows: windows))
|
|
153
156
|
else
|
|
154
157
|
# ensure all backslashes are forward slashes
|
|
155
|
-
path.gsub(BACKSLASH, File::SEPARATOR)
|
|
158
|
+
path.gsub!(BACKSLASH, File::SEPARATOR)
|
|
156
159
|
end
|
|
160
|
+
path
|
|
157
161
|
end
|
|
158
162
|
|
|
159
163
|
# This is not just escaping for something like use in Regexps, or in globs. For the former
|
|
@@ -248,7 +252,7 @@ module ChefConfig
|
|
|
248
252
|
paths << ENV[@@per_tool_home_environment] if defined?(@@per_tool_home_environment) && @@per_tool_home_environment && ENV[@@per_tool_home_environment]
|
|
249
253
|
paths << ENV["CHEF_HOME"] if ENV["CHEF_HOME"]
|
|
250
254
|
if windows
|
|
251
|
-
# By default, Ruby uses the
|
|
255
|
+
# By default, Ruby uses the following environment variables to determine Dir.home:
|
|
252
256
|
# HOME
|
|
253
257
|
# HOMEDRIVE HOMEPATH
|
|
254
258
|
# USERPROFILE
|
data/lib/chef-config/version.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright:: Copyright (c)
|
|
1
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
2
2
|
# License:: Apache License, Version 2.0
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
|
|
16
16
|
module ChefConfig
|
|
17
17
|
CHEFCONFIG_ROOT = File.expand_path("..", __dir__)
|
|
18
|
-
VERSION = "
|
|
18
|
+
VERSION = "19.3.15".freeze
|
|
19
19
|
end
|
data/lib/chef-config/windows.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Daniel DeLeo (<dan@chef.io>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
data/lib/chef-config.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
3
3
|
# License:: Apache License, Version 2.0
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
data/spec/unit/config_spec.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Adam Jacob (<adam@chef.io>)
|
|
3
3
|
# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>)
|
|
4
|
-
# Copyright:: Copyright (c)
|
|
4
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
5
5
|
# License:: Apache License, Version 2.0
|
|
6
6
|
#
|
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -22,8 +22,13 @@ require "chef-config/config"
|
|
|
22
22
|
require "date" unless defined?(Date)
|
|
23
23
|
|
|
24
24
|
RSpec.describe ChefConfig::Config do
|
|
25
|
+
let(:target_mode_host) { "fluffy.kittens.org".freeze }
|
|
26
|
+
|
|
25
27
|
before(:each) do
|
|
26
28
|
ChefConfig::Config.reset
|
|
29
|
+
ChefConfig::Config.instance_variable_set(:@var_chef_dir, nil)
|
|
30
|
+
ChefConfig::Config.instance_variable_set(:@etc_chef_dir, nil)
|
|
31
|
+
ChefConfig::Config.instance_variable_set(:@var_root_dir, nil)
|
|
27
32
|
|
|
28
33
|
# By default, treat deprecation warnings as errors in tests.
|
|
29
34
|
ChefConfig::Config.treat_deprecation_warnings_as_errors(true)
|
|
@@ -243,16 +248,18 @@ RSpec.describe ChefConfig::Config do
|
|
|
243
248
|
end
|
|
244
249
|
|
|
245
250
|
context "on windows", :windows_only do
|
|
246
|
-
|
|
247
|
-
|
|
251
|
+
let(:windows_drive) { ChefConfig::Config.windows_installation_drive || "C:" }
|
|
252
|
+
|
|
253
|
+
it "var_chef_dir is on the windows installation drive" do
|
|
254
|
+
expect(ChefConfig::Config.var_chef_dir).to eql("#{windows_drive}\\#{dirname}")
|
|
248
255
|
end
|
|
249
256
|
|
|
250
257
|
it "var_root_dir is C:\\" do
|
|
251
258
|
expect(ChefConfig::Config.var_root_dir).to eql("C:\\")
|
|
252
259
|
end
|
|
253
260
|
|
|
254
|
-
it "etc_chef_dir is
|
|
255
|
-
expect(ChefConfig::Config.etc_chef_dir).to eql("
|
|
261
|
+
it "etc_chef_dir is on the windows installation drive" do
|
|
262
|
+
expect(ChefConfig::Config.etc_chef_dir).to eql("#{windows_drive}\\#{dirname}")
|
|
256
263
|
end
|
|
257
264
|
end
|
|
258
265
|
|
|
@@ -271,16 +278,18 @@ RSpec.describe ChefConfig::Config do
|
|
|
271
278
|
end
|
|
272
279
|
|
|
273
280
|
context "when forced to windows" do
|
|
274
|
-
|
|
275
|
-
|
|
281
|
+
let(:windows_drive) { ChefConfig::Config.windows_installation_drive || "C:" }
|
|
282
|
+
|
|
283
|
+
it "var_chef_dir is on the windows installation drive" do
|
|
284
|
+
expect(ChefConfig::Config.var_chef_dir(windows: true)).to eql("#{windows_drive}\\#{dirname}")
|
|
276
285
|
end
|
|
277
286
|
|
|
278
287
|
it "var_root_dir is C:\\" do
|
|
279
288
|
expect(ChefConfig::Config.var_root_dir(windows: true)).to eql("C:\\")
|
|
280
289
|
end
|
|
281
290
|
|
|
282
|
-
it "etc_chef_dir is
|
|
283
|
-
expect(ChefConfig::Config.etc_chef_dir(windows: true)).to eql("
|
|
291
|
+
it "etc_chef_dir is on the windows installation drive" do
|
|
292
|
+
expect(ChefConfig::Config.etc_chef_dir(windows: true)).to eql("#{windows_drive}\\#{dirname}")
|
|
284
293
|
end
|
|
285
294
|
end
|
|
286
295
|
|
|
@@ -379,8 +388,6 @@ RSpec.describe ChefConfig::Config do
|
|
|
379
388
|
end
|
|
380
389
|
|
|
381
390
|
context "when target mode is enabled" do
|
|
382
|
-
let(:target_mode_host) { "fluffy.kittens.org" }
|
|
383
|
-
|
|
384
391
|
before do
|
|
385
392
|
ChefConfig::Config.target_mode.enabled = true
|
|
386
393
|
ChefConfig::Config.target_mode.host = target_mode_host
|
|
@@ -400,6 +407,25 @@ RSpec.describe ChefConfig::Config do
|
|
|
400
407
|
end
|
|
401
408
|
end
|
|
402
409
|
|
|
410
|
+
describe "ChefConfig::Config[:chef_guid_path]" do
|
|
411
|
+
it "sets the default path to the chef guid" do
|
|
412
|
+
expected_path = ChefConfig::PathHelper.join(ChefConfig::Config.config_dir, "chef_guid")
|
|
413
|
+
expect(ChefConfig::Config.chef_guid_path).to eq(expected_path)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
context "when target mode is enabled" do
|
|
417
|
+
before do
|
|
418
|
+
ChefConfig::Config.target_mode.enabled = true
|
|
419
|
+
ChefConfig::Config.target_mode.host = target_mode_host
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
it "sets the default path to the chef guid with the target host name" do
|
|
423
|
+
expected_path = ChefConfig::PathHelper.join(ChefConfig::Config.config_dir, target_mode_host, "chef_guid")
|
|
424
|
+
expect(ChefConfig::Config.chef_guid_path).to eq(expected_path)
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
403
429
|
describe "ChefConfig::Config[:fips]" do
|
|
404
430
|
let(:fips_enabled) { false }
|
|
405
431
|
|
|
@@ -495,7 +521,6 @@ RSpec.describe ChefConfig::Config do
|
|
|
495
521
|
end
|
|
496
522
|
|
|
497
523
|
describe "ChefConfig::Config[:cache_path]" do
|
|
498
|
-
let(:target_mode_host) { "fluffy.kittens.org" }
|
|
499
524
|
let(:target_mode_primary_cache_path) { ChefUtils.windows? ? "#{primary_cache_path}\\#{target_mode_host}" : "#{primary_cache_path}/#{target_mode_host}" }
|
|
500
525
|
let(:target_mode_secondary_cache_path) { ChefUtils.windows? ? "#{secondary_cache_path}\\#{target_mode_host}" : "#{secondary_cache_path}/#{target_mode_host}" }
|
|
501
526
|
|
|
@@ -710,9 +735,9 @@ RSpec.describe ChefConfig::Config do
|
|
|
710
735
|
|
|
711
736
|
end
|
|
712
737
|
|
|
713
|
-
# On Windows, we'll detect
|
|
738
|
+
# On Windows, we'll detect embedded install and set this to the
|
|
714
739
|
# cacert.pem included in the package, but it's nil if you're on Windows
|
|
715
|
-
# w/o
|
|
740
|
+
# w/o embedded install (e.g., doing development on Windows, custom build, etc.)
|
|
716
741
|
unless is_windows
|
|
717
742
|
it "ChefConfig::Config[:ssl_ca_file] defaults to nil" do
|
|
718
743
|
expect(ChefConfig::Config[:ssl_ca_file]).to be_nil
|
|
@@ -842,7 +867,7 @@ RSpec.describe ChefConfig::Config do
|
|
|
842
867
|
describe "finding the windows embedded dir" do
|
|
843
868
|
let(:default_config_location) { "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
|
|
844
869
|
let(:alternate_install_location) { "c:/my/alternate/install/place/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
|
|
845
|
-
let(:
|
|
870
|
+
let(:non_package_location) { "c:/my/dev/stuff/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
|
|
846
871
|
|
|
847
872
|
let(:default_ca_file) { "c:/opscode/chef/embedded/ssl/certs/cacert.pem" }
|
|
848
873
|
|
|
@@ -856,8 +881,8 @@ RSpec.describe ChefConfig::Config do
|
|
|
856
881
|
expect(ChefConfig::Config.embedded_dir).to eq("c:/my/alternate/install/place/chef/embedded")
|
|
857
882
|
end
|
|
858
883
|
|
|
859
|
-
it "doesn't error when not in an
|
|
860
|
-
allow(ChefConfig::Config).to receive(:_this_file).and_return(
|
|
884
|
+
it "doesn't error when not in an package install" do
|
|
885
|
+
allow(ChefConfig::Config).to receive(:_this_file).and_return(non_package_location)
|
|
861
886
|
expect(ChefConfig::Config.embedded_dir).to be_nil
|
|
862
887
|
end
|
|
863
888
|
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
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 "spec_helper"
|
|
19
|
+
require "chef-config/config"
|
|
20
|
+
require "chef-config/mixin/credentials"
|
|
21
|
+
|
|
22
|
+
module Vault
|
|
23
|
+
class Client; end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
RSpec.describe ChefConfig::Mixin::Credentials do
|
|
27
|
+
|
|
28
|
+
let(:test_class) { Class.new { include ChefConfig::Mixin::Credentials } }
|
|
29
|
+
subject(:test_obj) { test_class.new }
|
|
30
|
+
|
|
31
|
+
describe "#credentials_profile" do
|
|
32
|
+
context "when an explicit profile is given" do
|
|
33
|
+
it "passes it through" do
|
|
34
|
+
expect(test_obj.credentials_profile("webserver")).to eq("webserver")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "when an environment variable is set" do
|
|
39
|
+
before(:all) do
|
|
40
|
+
@original_env = ENV.to_hash
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
after(:all) do
|
|
44
|
+
ENV.clear
|
|
45
|
+
ENV.update(@original_env)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
before(:each) do
|
|
49
|
+
ENV["CHEF_PROFILE"] = "acme-server"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "picks the profile correctly" do
|
|
53
|
+
expect(test_obj.credentials_profile).to eq("acme-server")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context "when no profile is given" do
|
|
58
|
+
it "picks the default one" do
|
|
59
|
+
expect(test_obj.credentials_profile).to eq("default")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "#resolve_secrets" do
|
|
65
|
+
context "when no credentials were loaded" do
|
|
66
|
+
it "returns" do
|
|
67
|
+
allow(test_obj).to receive(:credentials_config).and_return(nil)
|
|
68
|
+
expect(test_obj.resolve_secrets("dummy")).to eq(nil)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "when credentials do not contain specified profile" do
|
|
73
|
+
it "raises an error" do
|
|
74
|
+
allow(test_obj).to receive(:credentials_config).and_return({ "webserver" => {} })
|
|
75
|
+
expect { test_obj.resolve_secrets("dummy") }.to raise_error(ChefConfig::NoCredentialsFound, /No credentials found for profile/)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context "when no secrets were referenced in profile" do
|
|
80
|
+
it "returns" do
|
|
81
|
+
allow(test_obj).to receive(:credentials_config).and_return({ "webserver2" => {} })
|
|
82
|
+
expect(test_obj.resolve_secrets("webserver2")).to eq(nil)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe "#valid_secrets_provider?" do
|
|
88
|
+
context "when global, valid configuration was provided" do
|
|
89
|
+
let(:global_options) { { "default_secrets_provider" => { "name" => "hashicorp-vault", "endpoint" => "https://198.51.100.5:8200", "token" => "hvs.1234567890" } } }
|
|
90
|
+
let(:secrets_config) { { "secret" => "/chef/sudo_password", "field" => "password" } }
|
|
91
|
+
|
|
92
|
+
it "returns true" do
|
|
93
|
+
allow(test_obj).to receive(:global_options).and_return(global_options)
|
|
94
|
+
expect(test_obj.valid_secrets_provider?(secrets_config)).to be(true)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
context "when global, invalid configuration was provided" do
|
|
99
|
+
let(:global_options) { { "default_secrets_provider" => { "name" => "hashicorp-consul" } } }
|
|
100
|
+
let(:secrets_config) { { "secret" => "/chef/sudo_password", "field" => "password" } }
|
|
101
|
+
|
|
102
|
+
it "returns false" do
|
|
103
|
+
allow(test_obj).to receive(:global_options).and_return(global_options)
|
|
104
|
+
expect(test_obj.valid_secrets_provider?(secrets_config)).to be(false)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context "when global, invalid configuration is overridden with a correct value" do
|
|
109
|
+
let(:global_options) { { "default_secrets_provider" => { "name" => "hashicorp-consul" } } }
|
|
110
|
+
let(:secrets_config) { { "secrets_provider" => { "name" => "hashicorp-vault" }, "secret" => "/chef/sudo_password", "field" => "password" } }
|
|
111
|
+
|
|
112
|
+
it "returns false" do
|
|
113
|
+
allow(test_obj).to receive(:global_options).and_return(global_options)
|
|
114
|
+
expect(test_obj.valid_secrets_provider?(secrets_config)).to be(true)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe "#resolve_secret" do
|
|
120
|
+
before do
|
|
121
|
+
allow(test_obj).to receive(:global_options).and_return(global_options)
|
|
122
|
+
|
|
123
|
+
# Simulate "vault" gem
|
|
124
|
+
allow(test_obj).to receive(:require).with("vault")
|
|
125
|
+
vault_double = double("Vault::Client")
|
|
126
|
+
allow(vault_double).to receive_message_chain("logical.read") { secrets_result }
|
|
127
|
+
allow(vault_double).to receive_message_chain("kv.read.data") { secrets_result }
|
|
128
|
+
test_obj.instance_variable_set(:@vault, vault_double)
|
|
129
|
+
|
|
130
|
+
# Simulate "jmespath" gem
|
|
131
|
+
allow(test_obj).to receive(:require).with("jmespath")
|
|
132
|
+
jmespath_double = double("JMESPath")
|
|
133
|
+
allow(jmespath_double).to receive_message_chain("search") { search_for = secrets_config["field"]; secrets_result[search_for] }
|
|
134
|
+
stub_const("::JMESPath", jmespath_double)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context "without default secrets provider being set" do
|
|
138
|
+
let(:global_options) {}
|
|
139
|
+
|
|
140
|
+
context "for a secret of type string" do
|
|
141
|
+
let(:secrets_result) { "secret" }
|
|
142
|
+
let(:secrets_config) { { "secrets_provider" => { "name" => "hashicorp-vault" }, "secret" => "/chef/sudo_password" } }
|
|
143
|
+
|
|
144
|
+
it "returns the complete value" do
|
|
145
|
+
expect(test_obj.resolve_secret(secrets_config)).to eq("secret")
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
context "for a secret of type hash" do
|
|
150
|
+
let(:secrets_result) { { "password" => "secret" } }
|
|
151
|
+
let(:secrets_config) { { "secrets_provider" => { "name" => "hashicorp-vault", "endpoint" => "https://198.51.100.5:8200", "token" => "hvs.1234567890" }, "secret" => "/chef/sudo_password", "field" => "password" } }
|
|
152
|
+
|
|
153
|
+
it "returns the correct subkey" do
|
|
154
|
+
expect(test_obj.resolve_secret(secrets_config)).to eq("secret")
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
context "with default secrets provider being set" do
|
|
160
|
+
let(:global_options) { { "default_secrets_provider" => { "name" => "hashicorp-vault", "endpoint" => "https://198.51.100.5:8200", "token" => "hvs.1234567890" } } }
|
|
161
|
+
|
|
162
|
+
context "for a secret of type string" do
|
|
163
|
+
let(:secrets_result) { "secret" }
|
|
164
|
+
let(:secrets_config) { { "secret" => "/chef/sudo_password" } }
|
|
165
|
+
|
|
166
|
+
it "returns the complete value" do
|
|
167
|
+
expect(test_obj.resolve_secret(secrets_config)).to eq("secret")
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
context "for a secret of type hash" do
|
|
172
|
+
let(:secrets_result) { { "password" => "secret" } }
|
|
173
|
+
let(:secrets_config) { { "secret" => "/chef/sudo_password", "field" => "password" } }
|
|
174
|
+
|
|
175
|
+
it "returns the correct subkey" do
|
|
176
|
+
expect(test_obj.resolve_secret(secrets_config)).to eq("secret")
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
data/spec/unit/fips_spec.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Matt Wrock (<matt@mattwrock.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
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
|
+
require "spec_helper"
|
|
18
|
+
require "chef-config/mixin/fuzzy_hostname_matcher"
|
|
19
|
+
|
|
20
|
+
RSpec.describe ChefConfig::Mixin::FuzzyHostnameMatcher do
|
|
21
|
+
let(:matcher) do
|
|
22
|
+
Class.new { include ChefConfig::Mixin::FuzzyHostnameMatcher }.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "#fuzzy_hostname_match?" do
|
|
26
|
+
it "matches a hostname with a wildcard pattern" do
|
|
27
|
+
expect(matcher.fuzzy_hostname_match?("foo.example.com", "example.com")).to be true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "does not match unrelated hostnames" do
|
|
31
|
+
expect(matcher.fuzzy_hostname_match?("foo.example.com", "other.com")).to be false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "returns false for bare IPv6 addresses instead of raising" do
|
|
35
|
+
expect(matcher.fuzzy_hostname_match?("2001:db8::1", "example.com")).to be false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "returns false for bracketed IPv6 addresses instead of raising" do
|
|
39
|
+
expect(matcher.fuzzy_hostname_match?("[2001:db8::1]", "example.com")).to be false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "returns false for IPv6 URLs instead of raising" do
|
|
43
|
+
expect(matcher.fuzzy_hostname_match?("https://[2001:db8::1]/path", "example.com")).to be false
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe "#fuzzy_hostname_match_any?" do
|
|
48
|
+
it "returns false when hostname is nil" do
|
|
49
|
+
expect(matcher.fuzzy_hostname_match_any?(nil, "example.com")).to be false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "returns false when matches is nil" do
|
|
53
|
+
expect(matcher.fuzzy_hostname_match_any?("foo.example.com", nil)).to be false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "matches against comma-separated patterns" do
|
|
57
|
+
expect(matcher.fuzzy_hostname_match_any?("foo.example.com", "other.com, example.com")).to be true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "returns false for IPv6 URLs with hostname no_proxy patterns" do
|
|
61
|
+
ipv6_url = "https://[2001:db8:abcd:ef01::1]/organizations/o3"
|
|
62
|
+
no_proxy = "gateway.example.net,internal.example.com"
|
|
63
|
+
expect(matcher.fuzzy_hostname_match_any?(ipv6_url, no_proxy)).to be false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "returns false for bare IPv6 with hostname no_proxy patterns" do
|
|
67
|
+
expect(matcher.fuzzy_hostname_match_any?("2001:db8::1", "example.com,other.net")).to be false
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Bryan McLellan <btm@loftninjas.org>
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Daniel DeLeo (<dan@chef.io>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -480,11 +480,10 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
|
|
|
480
480
|
node_name = 'barney'
|
|
481
481
|
client_key = "barney_rubble.pem"
|
|
482
482
|
chef_server_url = "https://api.chef.io/organizations/bedrock"
|
|
483
|
-
|
|
484
|
-
secret_file = "/home/barney/.chef/encrypted_data_bag_secret.pem"
|
|
485
|
-
}
|
|
483
|
+
|
|
486
484
|
[default.knife]
|
|
487
485
|
ssh_user = "knife_ssh_user"
|
|
486
|
+
secret_file = "/home/barney/.chef/encrypted_data_bag_secret.pem"
|
|
488
487
|
EOH
|
|
489
488
|
content
|
|
490
489
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chef-config
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 19.3.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adam Jacob
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: chef-utils
|
|
@@ -16,14 +15,14 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - '='
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
18
|
+
version: 19.3.15
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - '='
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
25
|
+
version: 19.3.15
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: mixlib-shellout
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -96,17 +95,36 @@ dependencies:
|
|
|
96
95
|
name: tomlrb
|
|
97
96
|
requirement: !ruby/object:Gem::Requirement
|
|
98
97
|
requirements:
|
|
99
|
-
- - "
|
|
98
|
+
- - ">="
|
|
100
99
|
- !ruby/object:Gem::Version
|
|
101
100
|
version: '1.2'
|
|
101
|
+
- - "<"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '3.0'
|
|
102
104
|
type: :runtime
|
|
103
105
|
prerelease: false
|
|
104
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
105
107
|
requirements:
|
|
106
|
-
- - "
|
|
108
|
+
- - ">="
|
|
107
109
|
- !ruby/object:Gem::Version
|
|
108
110
|
version: '1.2'
|
|
109
|
-
|
|
111
|
+
- - "<"
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '3.0'
|
|
114
|
+
- !ruby/object:Gem::Dependency
|
|
115
|
+
name: racc
|
|
116
|
+
requirement: !ruby/object:Gem::Requirement
|
|
117
|
+
requirements:
|
|
118
|
+
- - ">="
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: '0'
|
|
121
|
+
type: :runtime
|
|
122
|
+
prerelease: false
|
|
123
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
124
|
+
requirements:
|
|
125
|
+
- - ">="
|
|
126
|
+
- !ruby/object:Gem::Version
|
|
127
|
+
version: '0'
|
|
110
128
|
email:
|
|
111
129
|
- adam@chef.io
|
|
112
130
|
executables: []
|
|
@@ -131,7 +149,9 @@ files:
|
|
|
131
149
|
- lib/chef-config/workstation_config_loader.rb
|
|
132
150
|
- spec/spec_helper.rb
|
|
133
151
|
- spec/unit/config_spec.rb
|
|
152
|
+
- spec/unit/credentials_spec.rb
|
|
134
153
|
- spec/unit/fips_spec.rb
|
|
154
|
+
- spec/unit/fuzzy_hostname_matcher_spec.rb
|
|
135
155
|
- spec/unit/path_helper_spec.rb
|
|
136
156
|
- spec/unit/workstation_config_loader_spec.rb
|
|
137
157
|
homepage: https://github.com/chef/chef
|
|
@@ -143,7 +163,6 @@ metadata:
|
|
|
143
163
|
documentation_uri: https://github.com/chef/chef/tree/main/chef-config/README.md
|
|
144
164
|
homepage_uri: https://github.com/chef/chef/tree/main/chef-config
|
|
145
165
|
source_code_uri: https://github.com/chef/chef/tree/main/chef-config
|
|
146
|
-
post_install_message:
|
|
147
166
|
rdoc_options: []
|
|
148
167
|
require_paths:
|
|
149
168
|
- lib
|
|
@@ -158,8 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
158
177
|
- !ruby/object:Gem::Version
|
|
159
178
|
version: '0'
|
|
160
179
|
requirements: []
|
|
161
|
-
rubygems_version: 3.
|
|
162
|
-
signing_key:
|
|
180
|
+
rubygems_version: 3.6.9
|
|
163
181
|
specification_version: 4
|
|
164
182
|
summary: Chef Infra's default configuration and config loading library
|
|
165
183
|
test_files: []
|