chef-vault 3.0.0.rc1 → 3.0.0.rc2
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/.gitignore +2 -0
- data/Gemfile +1 -0
- data/lib/chef-vault/item.rb +43 -46
- data/lib/chef-vault/item_keys.rb +97 -6
- data/lib/chef-vault/mixins.rb +11 -1
- data/lib/chef-vault/version.rb +1 -1
- data/lib/chef/knife/mixin/helper.rb +2 -2
- data/lib/chef/knife/vault_create.rb +1 -1
- data/lib/chef/knife/vault_update.rb +1 -1
- data/spec/chef-vault/item_keys_spec.rb +73 -6
- data/spec/chef-vault/item_spec.rb +5 -7
- data/spec/chef-vault_spec.rb +30 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6dd267f10f94be45c16f2a088e476226b4b0cf5
|
4
|
+
data.tar.gz: 27fc5a1ee95c7be2ad1af5f967d4bbda96427b6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9397b282b2497e73b1fef2cb86f09f84df98bc9333513cd4648767436e15138f9c9cee187c56854ee3e2197a61ee992e6cdd4f502145b89d194eb428c0ccb07c
|
7
|
+
data.tar.gz: 6a978b6a18e4a1a4b4eb8e3ddd3ce48318126e3f152dd5080ee20e19993afece13540df9b33b9a64b6873b483876c9041653ba91739a64ca3d0bc94b632a4dfd
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/lib/chef-vault/item.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Author:: Kevin Moser <kevin.moser@nordstrom.com>
|
2
2
|
# Copyright:: Copyright 2013-15, Nordstrom, Inc.
|
3
|
+
# Copyright:: Copyright 2015-16, Chef Software, Inc.
|
3
4
|
# License:: Apache License, Version 2.0
|
4
5
|
|
5
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -67,6 +68,7 @@ class ChefVault
|
|
67
68
|
}.merge(opts)
|
68
69
|
@node_name = opts[:node_name]
|
69
70
|
@client_key_path = opts[:client_key_path]
|
71
|
+
@current_query = search
|
70
72
|
end
|
71
73
|
|
72
74
|
# private
|
@@ -75,39 +77,42 @@ class ChefVault
|
|
75
77
|
@secret = secret
|
76
78
|
end
|
77
79
|
|
78
|
-
def clients(search_or_client, action = :add)
|
79
|
-
if
|
80
|
+
def clients(search_or_client = search_results, action = :add)
|
81
|
+
# for backwards compatibility, if we're handed a string
|
82
|
+
# do a search using that string and recurse
|
83
|
+
if search_or_client.is_a?(String)
|
84
|
+
clients(search_results(search_or_client), action)
|
85
|
+
elsif search_or_client.is_a?(Chef::ApiClient)
|
80
86
|
handle_client_action(search_or_client, action)
|
81
|
-
|
87
|
+
else
|
82
88
|
search_or_client.each do |name|
|
83
|
-
|
84
|
-
|
89
|
+
begin
|
90
|
+
client = load_actor(name, "clients")
|
91
|
+
handle_client_action(client, action)
|
92
|
+
rescue ChefVault::Exceptions::ClientNotFound
|
93
|
+
ChefVault::Log.warn "node '#{name}' has no private key; skipping"
|
94
|
+
end
|
85
95
|
end
|
86
|
-
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def search_results(statement = search)
|
100
|
+
@search_results = nil if statement != @current_query
|
101
|
+
@current_query = statement
|
102
|
+
@search_results ||= begin
|
87
103
|
results_returned = false
|
104
|
+
results = []
|
88
105
|
query = Chef::Search::Query.new
|
89
|
-
query.search(:node,
|
106
|
+
query.search(:node, statement, filter_result: { name: ["name"] }, rows: 100000) do |node|
|
90
107
|
results_returned = true
|
91
|
-
|
92
|
-
when :add
|
93
|
-
begin
|
94
|
-
client_key = load_actor(node.name, "clients")
|
95
|
-
add_client(client_key)
|
96
|
-
rescue ChefVault::Exceptions::ClientNotFound
|
97
|
-
ChefVault::Log.warn "node '#{node.name}' has no private key; skipping"
|
98
|
-
end
|
99
|
-
when :delete
|
100
|
-
delete_client_or_node(node)
|
101
|
-
else
|
102
|
-
raise ChefVault::Exceptions::KeysActionNotValid,
|
103
|
-
"#{action} is not a valid action"
|
104
|
-
end
|
108
|
+
results << node["name"]
|
105
109
|
end
|
106
110
|
|
107
111
|
unless results_returned
|
108
112
|
ChefVault::Log.warn "No clients were returned from search, you may not have "\
|
109
|
-
|
113
|
+
"got what you expected!!"
|
110
114
|
end
|
115
|
+
results
|
111
116
|
end
|
112
117
|
end
|
113
118
|
|
@@ -172,9 +177,7 @@ class ChefVault
|
|
172
177
|
# admins, just clients which are nodes
|
173
178
|
remove_unknown_nodes if clean_unknown_clients
|
174
179
|
# re-encrypt the new shared secret for all remaining clients
|
175
|
-
get_clients
|
176
|
-
clients("name:#{client}")
|
177
|
-
end
|
180
|
+
clients(get_clients)
|
178
181
|
end
|
179
182
|
|
180
183
|
unless get_admins.empty?
|
@@ -211,7 +214,7 @@ class ChefVault
|
|
211
214
|
encrypt! unless @encrypted
|
212
215
|
|
213
216
|
# Now save the encrypted data
|
214
|
-
if Chef::Config[:
|
217
|
+
if Chef::Config[:solo_legacy_mode]
|
215
218
|
save_solo(item_id)
|
216
219
|
else
|
217
220
|
begin
|
@@ -257,7 +260,7 @@ class ChefVault
|
|
257
260
|
def destroy
|
258
261
|
keys.destroy
|
259
262
|
|
260
|
-
if Chef::Config[:
|
263
|
+
if Chef::Config[:solo_legacy_mode]
|
261
264
|
data_bag_path = File.join(Chef::Config[:data_bag_path],
|
262
265
|
data_bag)
|
263
266
|
data_bag_item_path = File.join(data_bag_path, @raw_data["id"])
|
@@ -362,7 +365,7 @@ class ChefVault
|
|
362
365
|
remove_unknown_nodes if clean_unknown_clients
|
363
366
|
|
364
367
|
# re-process the search query to add new clients
|
365
|
-
clients
|
368
|
+
clients
|
366
369
|
|
367
370
|
# save the updated keys only
|
368
371
|
save_keys(@raw_data["id"])
|
@@ -413,14 +416,10 @@ class ChefVault
|
|
413
416
|
# @param nodename [String] the name of the node
|
414
417
|
# @return [Boolean] whether the node exists or not
|
415
418
|
def node_exists?(nodename)
|
416
|
-
#
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
return false unless numresults > 0
|
421
|
-
# if the node search does return results, predicate node
|
422
|
-
# existence on the existence of a like-named client
|
423
|
-
client_exists?(nodename)
|
419
|
+
# if we don't have a client it really doesn't matter if we have a node.
|
420
|
+
if client_exists?(nodename)
|
421
|
+
search_results.include?(nodename)
|
422
|
+
end
|
424
423
|
end
|
425
424
|
|
426
425
|
# checks if a client exists on the Chef server. If we get back
|
@@ -429,13 +428,11 @@ class ChefVault
|
|
429
428
|
# @param clientname [String] the name of the client
|
430
429
|
# @return [Boolean] whether the client exists or not
|
431
430
|
def client_exists?(clientname)
|
432
|
-
|
433
|
-
Chef::ApiClient.load(clientname)
|
434
|
-
rescue Net::HTTPServerException => http_error
|
435
|
-
return false if http_error.response.code == "404"
|
436
|
-
raise http_error
|
437
|
-
end
|
431
|
+
Chef::ApiClient.load(clientname)
|
438
432
|
true
|
433
|
+
rescue Net::HTTPServerException => http_error
|
434
|
+
return false if http_error.response.code == "404"
|
435
|
+
raise http_error
|
439
436
|
end
|
440
437
|
|
441
438
|
# adds or deletes an API client from the vault item keys
|
@@ -448,7 +445,7 @@ class ChefVault
|
|
448
445
|
client = load_actor(api_client.name, "clients")
|
449
446
|
add_client(client)
|
450
447
|
when :delete
|
451
|
-
delete_client_or_node(api_client)
|
448
|
+
delete_client_or_node(api_client.name)
|
452
449
|
end
|
453
450
|
end
|
454
451
|
|
@@ -460,10 +457,10 @@ class ChefVault
|
|
460
457
|
end
|
461
458
|
|
462
459
|
# removes a client to the vault item keys
|
463
|
-
# @param client_or_node [
|
460
|
+
# @param client_or_node [String] the name of the API client or node to remove
|
464
461
|
# @return [void]
|
465
|
-
def delete_client_or_node(
|
466
|
-
client = load_actor(
|
462
|
+
def delete_client_or_node(name)
|
463
|
+
client = load_actor(name, "clients")
|
467
464
|
keys.delete(client)
|
468
465
|
end
|
469
466
|
end
|
data/lib/chef-vault/item_keys.rb
CHANGED
@@ -28,9 +28,33 @@ class ChefVault
|
|
28
28
|
@raw_data["admins"] = []
|
29
29
|
@raw_data["clients"] = []
|
30
30
|
@raw_data["search_query"] = []
|
31
|
+
@raw_data["mode"] = "default"
|
32
|
+
@cache = {} # write-back cache for keys
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](key)
|
36
|
+
# return options immediately
|
37
|
+
return @raw_data[key] if %w{id admins clients search_query mode}.include?(key)
|
38
|
+
# check if the key is in the write-back cache
|
39
|
+
ckey = @cache[key]
|
40
|
+
return ckey unless ckey.nil?
|
41
|
+
# check if the key is saved in sparse mode
|
42
|
+
skey = sparse_key(sparse_id(key))
|
43
|
+
if skey
|
44
|
+
skey[key]
|
45
|
+
else
|
46
|
+
# fallback to raw data
|
47
|
+
@raw_data[key]
|
48
|
+
end
|
31
49
|
end
|
32
50
|
|
33
51
|
def include?(key)
|
52
|
+
# check if the key is in the write-back cache
|
53
|
+
ckey = @cache[key]
|
54
|
+
return (ckey ? true : false) unless ckey.nil?
|
55
|
+
# check if the key is saved in sparse mode
|
56
|
+
return true unless sparse_key(sparse_id(key)).nil?
|
57
|
+
# fallback to non-sparse mode if sparse key is not found
|
34
58
|
@raw_data.keys.include?(key)
|
35
59
|
end
|
36
60
|
|
@@ -40,16 +64,24 @@ class ChefVault
|
|
40
64
|
raise ChefVault::Exceptions::V1Format,
|
41
65
|
"cannot manage a v1 vault. See UPGRADE.md for help"
|
42
66
|
end
|
43
|
-
|
67
|
+
@cache[chef_key.name] = ChefVault::ItemKeys.encode_key(chef_key.key, data_bag_shared_secret)
|
44
68
|
@raw_data[type] << chef_key.name unless @raw_data[type].include?(chef_key.name)
|
45
69
|
@raw_data[type]
|
46
70
|
end
|
47
71
|
|
48
72
|
def delete(chef_key)
|
49
|
-
|
73
|
+
@cache[chef_key.name] = false
|
50
74
|
raw_data[chef_key.type].delete(chef_key.name)
|
51
75
|
end
|
52
76
|
|
77
|
+
def mode(mode = nil)
|
78
|
+
if mode
|
79
|
+
@raw_data["mode"] = mode
|
80
|
+
else
|
81
|
+
@raw_data["mode"]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
53
85
|
def search_query(search_query = nil)
|
54
86
|
if search_query
|
55
87
|
@raw_data["search_query"] = search_query
|
@@ -67,9 +99,8 @@ class ChefVault
|
|
67
99
|
end
|
68
100
|
|
69
101
|
def save(item_id = @raw_data["id"])
|
70
|
-
if
|
71
|
-
|
72
|
-
else
|
102
|
+
# create data bag if not running in solo mode
|
103
|
+
unless Chef::Config[:solo_legacy_mode]
|
73
104
|
begin
|
74
105
|
Chef::DataBag.load(data_bag)
|
75
106
|
rescue Net::HTTPServerException => http_error
|
@@ -79,13 +110,57 @@ class ChefVault
|
|
79
110
|
chef_data_bag.create
|
80
111
|
end
|
81
112
|
end
|
113
|
+
end
|
82
114
|
|
115
|
+
# write cached keys to data
|
116
|
+
@cache.each do |key, val|
|
117
|
+
# delete across all modes on key deletion
|
118
|
+
if val == false
|
119
|
+
# sparse mode key deletion
|
120
|
+
if Chef::Config[:solo_legacy_mode]
|
121
|
+
delete_solo(sparse_id(key))
|
122
|
+
else
|
123
|
+
begin
|
124
|
+
Chef::DataBagItem.from_hash("data_bag" => data_bag,
|
125
|
+
"id" => sparse_id(key))
|
126
|
+
.destroy(data_bag, sparse_id(key))
|
127
|
+
rescue Net::HTTPServerException => http_error
|
128
|
+
raise http_error unless http_error.response.code == "404"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
# default mode key deletion
|
132
|
+
@raw_data.delete(key)
|
133
|
+
else
|
134
|
+
if @raw_data["mode"] == "sparse"
|
135
|
+
# sparse mode key creation
|
136
|
+
skey = Chef::DataBagItem.from_hash(
|
137
|
+
"data_bag" => data_bag,
|
138
|
+
"id" => sparse_id(key),
|
139
|
+
key => val
|
140
|
+
)
|
141
|
+
if Chef::Config[:solo_legacy_mode]
|
142
|
+
save_solo(skey.id, skey.raw_data)
|
143
|
+
else
|
144
|
+
skey.save
|
145
|
+
end
|
146
|
+
else
|
147
|
+
# default mode key creation
|
148
|
+
@raw_data[key] = val
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
# save raw data
|
153
|
+
if Chef::Config[:solo_legacy_mode]
|
154
|
+
save_solo(item_id)
|
155
|
+
else
|
83
156
|
super
|
84
157
|
end
|
158
|
+
# clear write-back cache
|
159
|
+
@cache = {}
|
85
160
|
end
|
86
161
|
|
87
162
|
def destroy
|
88
|
-
if Chef::Config[:
|
163
|
+
if Chef::Config[:solo_legacy_mode]
|
89
164
|
data_bag_path = File.join(Chef::Config[:data_bag_path],
|
90
165
|
data_bag)
|
91
166
|
data_bag_item_path = File.join(data_bag_path, @raw_data["id"])
|
@@ -129,6 +204,22 @@ class ChefVault
|
|
129
204
|
|
130
205
|
# @private
|
131
206
|
|
207
|
+
def sparse_id(key, item_id = @raw_data["id"])
|
208
|
+
"#{item_id}_key_#{key}"
|
209
|
+
end
|
210
|
+
|
211
|
+
def sparse_key(sid)
|
212
|
+
if Chef::Config[:solo_legacy_mode]
|
213
|
+
load_solo(sid)
|
214
|
+
else
|
215
|
+
begin
|
216
|
+
Chef::DataBagItem.load(@data_bag, sid)
|
217
|
+
rescue Net::HTTPServerException => http_error
|
218
|
+
nil if http_error.response.code == "404"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
132
223
|
def self.encode_key(key_string, data_bag_shared_secret)
|
133
224
|
public_key = OpenSSL::PKey::RSA.new(key_string)
|
134
225
|
Base64.encode64(public_key.public_encrypt(data_bag_shared_secret))
|
data/lib/chef-vault/mixins.rb
CHANGED
@@ -22,7 +22,7 @@ class ChefVault
|
|
22
22
|
[data_bag_path, data_bag_item_path]
|
23
23
|
end
|
24
24
|
|
25
|
-
def save_solo(item_id = @raw_data["id"])
|
25
|
+
def save_solo(item_id = @raw_data["id"], raw_data = @raw_data)
|
26
26
|
data_bag_path, data_bag_item_path = find_solo_path(item_id)
|
27
27
|
|
28
28
|
FileUtils.mkdir(data_bag_path) unless File.exist?(data_bag_path)
|
@@ -32,5 +32,15 @@ class ChefVault
|
|
32
32
|
|
33
33
|
raw_data
|
34
34
|
end
|
35
|
+
|
36
|
+
def delete_solo(item_id = @raw_data["id"])
|
37
|
+
_data_bag_path, data_bag_item_path = find_solo_path(item_id)
|
38
|
+
FileUtils.rm(data_bag_item_path) if File.exist?(data_bag_item_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_solo(item_id = @raw_data["id"])
|
42
|
+
_data_bag_path, data_bag_item_path = find_solo_path(item_id)
|
43
|
+
JSON.parse(File.read(data_bag_item_path)) if File.exist?(data_bag_item_path)
|
44
|
+
end
|
35
45
|
end
|
36
46
|
end
|
data/lib/chef-vault/version.rb
CHANGED
@@ -2,6 +2,9 @@ RSpec.describe ChefVault::ItemKeys do
|
|
2
2
|
describe "#new" do
|
3
3
|
let(:keys) { ChefVault::ItemKeys.new("foo", "bar") }
|
4
4
|
let(:shared_secret) { "super_secret" }
|
5
|
+
let(:public_key_string) do
|
6
|
+
"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMXT9IOV9pkQsxsnhSx8\n8RX6GW3caxkjcXFfHg6E7zUVBFAsfw4B1D+eHAks3qrDB7UrUxsmCBXwU4dQHaQy\ngAn5Sv0Jc4CejDNL2EeCBLZ4TF05odHmuzyDdPkSZP6utpR7+uF7SgVQedFGySIB\nih86aM+HynhkJqgJYhoxkrdo/JcWjpk7YEmWb6p4esnvPWOpbcjIoFs4OjavWBOF\niTfpkS0SkygpLi/iQu9RQfd4hDMWCc6yh3Th/1nVMUd+xQCdUK5wxluAWSv8U0zu\nhiIlZNazpCGHp+3QdP3f6rebmQA8pRM8qT5SlOvCYPk79j+IMUVSYrR4/DTZ+VM+\naQIDAQAB\n-----END PUBLIC KEY-----\n"
|
7
|
+
end
|
5
8
|
|
6
9
|
it "'foo' is assigned to @data_bag" do
|
7
10
|
expect(keys.data_bag).to eq "foo"
|
@@ -19,10 +22,7 @@ RSpec.describe ChefVault::ItemKeys do
|
|
19
22
|
expect(keys["admins"]).to eq []
|
20
23
|
end
|
21
24
|
|
22
|
-
|
23
|
-
let(:public_key_string) do
|
24
|
-
"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyMXT9IOV9pkQsxsnhSx8\n8RX6GW3caxkjcXFfHg6E7zUVBFAsfw4B1D+eHAks3qrDB7UrUxsmCBXwU4dQHaQy\ngAn5Sv0Jc4CejDNL2EeCBLZ4TF05odHmuzyDdPkSZP6utpR7+uF7SgVQedFGySIB\nih86aM+HynhkJqgJYhoxkrdo/JcWjpk7YEmWb6p4esnvPWOpbcjIoFs4OjavWBOF\niTfpkS0SkygpLi/iQu9RQfd4hDMWCc6yh3Th/1nVMUd+xQCdUK5wxluAWSv8U0zu\nhiIlZNazpCGHp+3QdP3f6rebmQA8pRM8qT5SlOvCYPk79j+IMUVSYrR4/DTZ+VM+\naQIDAQAB\n-----END PUBLIC KEY-----\n"
|
25
|
-
end
|
25
|
+
shared_context "key mgmt operations" do
|
26
26
|
|
27
27
|
shared_examples_for "proper key management" do
|
28
28
|
let(:chef_key) { ChefVault::Actor.new(type, name) }
|
@@ -41,6 +41,7 @@ RSpec.describe ChefVault::ItemKeys do
|
|
41
41
|
keys.add(chef_key, shared_secret)
|
42
42
|
expect(keys[name]).to eq("encrypted_result")
|
43
43
|
expect(keys[type].include?(name)).to eq(true)
|
44
|
+
expect(keys.include?(name)).to eq(true)
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
@@ -53,6 +54,7 @@ RSpec.describe ChefVault::ItemKeys do
|
|
53
54
|
keys.delete(chef_key)
|
54
55
|
expect(keys.has_key?(chef_key.name)).to eq(false)
|
55
56
|
expect(keys[type].include?(name)).to eq(false)
|
57
|
+
expect(keys.include?(name)).to eq(false)
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
@@ -70,7 +72,52 @@ RSpec.describe ChefVault::ItemKeys do
|
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
75
|
+
context "when running with chef-zero" do
|
76
|
+
let(:server) { chef_zero }
|
77
|
+
before { server.start_background }
|
78
|
+
after { server.stop }
|
79
|
+
|
80
|
+
include_context "key mgmt operations"
|
81
|
+
|
82
|
+
describe "#save" do
|
83
|
+
let(:client_name) { "client_name" }
|
84
|
+
let(:chef_key) { ChefVault::Actor.new("clients", client_name) }
|
85
|
+
|
86
|
+
before do
|
87
|
+
allow(chef_key).to receive(:key) { public_key_string }
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should save the key data" do
|
91
|
+
keys.add(chef_key, shared_secret)
|
92
|
+
keys.save("bar")
|
93
|
+
expect(Chef::DataBagItem.load("foo", "bar").to_hash).to include("id" => "bar")
|
94
|
+
expect(keys[client_name]).not_to be_empty
|
95
|
+
keys.delete(chef_key)
|
96
|
+
keys.save("bar")
|
97
|
+
expect(keys[client_name]).to be_nil
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should save the key data in sparse mode" do
|
101
|
+
keys.add(chef_key, shared_secret)
|
102
|
+
keys.mode("sparse")
|
103
|
+
keys.save("bar")
|
104
|
+
expect(Chef::DataBagItem.load("foo", "bar").to_hash).to include("id" => "bar")
|
105
|
+
expect(Chef::DataBagItem.load("foo", "bar_key_client_name").to_hash).to include("id" => "bar_key_client_name")
|
106
|
+
expect(keys[client_name]).not_to be_empty
|
107
|
+
keys.delete(chef_key)
|
108
|
+
keys.save("bar")
|
109
|
+
expect(keys[client_name]).to be_nil
|
110
|
+
keys.mode("default")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
73
115
|
context "when running with chef-solo" do
|
116
|
+
before { Chef::Config[:solo_legacy_mode] = true }
|
117
|
+
after { Chef::Config[:solo_legacy_mode] = false }
|
118
|
+
|
119
|
+
include_context "key mgmt operations"
|
120
|
+
|
74
121
|
describe "#find_solo_path" do
|
75
122
|
context "when data_bag_path is an array" do
|
76
123
|
before do
|
@@ -103,16 +150,36 @@ RSpec.describe ChefVault::ItemKeys do
|
|
103
150
|
end
|
104
151
|
|
105
152
|
describe "#save" do
|
153
|
+
let(:client_name) { "client_name" }
|
154
|
+
let(:chef_key) { ChefVault::Actor.new("clients", client_name) }
|
106
155
|
let(:data_bag_path) { Dir.mktmpdir("vault_item_keys") }
|
156
|
+
|
107
157
|
before do
|
108
|
-
Chef::Config[:solo] = true
|
109
158
|
Chef::Config[:data_bag_path] = data_bag_path
|
159
|
+
allow(chef_key).to receive(:key) { public_key_string }
|
110
160
|
end
|
111
161
|
|
112
162
|
it "should save the key data" do
|
113
|
-
|
163
|
+
keys.add(chef_key, shared_secret)
|
164
|
+
keys.save("bar")
|
165
|
+
expect(File.read(File.join(data_bag_path, "foo", "bar.json"))).to match(/"id":.*"bar"/)
|
166
|
+
expect(keys[client_name]).not_to be_empty
|
167
|
+
keys.delete(chef_key)
|
168
|
+
keys.save("bar")
|
169
|
+
expect(keys[client_name]).to be_nil
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should save the key data in sparse mode" do
|
173
|
+
keys.add(chef_key, shared_secret)
|
174
|
+
keys.mode("sparse")
|
114
175
|
keys.save("bar")
|
115
176
|
expect(File.read(File.join(data_bag_path, "foo", "bar.json"))).to match(/"id":.*"bar"/)
|
177
|
+
expect(File.read(File.join(data_bag_path, "foo", "bar_key_client_name.json"))).to match(/"id":.*"bar_key_client_name"/)
|
178
|
+
expect(keys[client_name]).not_to be_empty
|
179
|
+
keys.delete(chef_key)
|
180
|
+
keys.save("bar")
|
181
|
+
expect(keys[client_name]).to be_nil
|
182
|
+
keys.mode("default")
|
116
183
|
end
|
117
184
|
end
|
118
185
|
end
|
@@ -172,6 +172,7 @@ RSpec.describe ChefVault::Item do
|
|
172
172
|
end
|
173
173
|
|
174
174
|
describe "#refresh" do
|
175
|
+
let(:node) { { "name" => "testnode" } }
|
175
176
|
|
176
177
|
it "saves only the keys" do
|
177
178
|
keys = double("keys",
|
@@ -184,7 +185,6 @@ RSpec.describe ChefVault::Item do
|
|
184
185
|
|
185
186
|
item = ChefVault::Item.new("foo", "bar")
|
186
187
|
|
187
|
-
node = double("node", name: "testnode")
|
188
188
|
query = double("query")
|
189
189
|
allow(Chef::Search::Query).to receive(:new).and_return(query)
|
190
190
|
allow(query).to receive(:search).and_yield(node)
|
@@ -202,14 +202,13 @@ RSpec.describe ChefVault::Item do
|
|
202
202
|
|
203
203
|
describe "#clients" do
|
204
204
|
context "when search returns a node with a valid client backing it and one without a valid client" do
|
205
|
-
let(:node_with_valid_client) {
|
206
|
-
let(:node_without_valid_client) {
|
205
|
+
let(:node_with_valid_client) { { "name" => "foo" } }
|
206
|
+
let(:node_without_valid_client) { { "name" => "bar" } }
|
207
207
|
let(:query_result) { double("chef search results") }
|
208
208
|
let(:client_key) { double("chef key") }
|
209
209
|
|
210
210
|
before do
|
211
211
|
# node with valid client proper loads client key
|
212
|
-
allow(node_with_valid_client).to receive(:name).and_return("foo")
|
213
212
|
allow(item).to receive(:load_actor).with("foo", "clients").and_return(client_key)
|
214
213
|
privkey = OpenSSL::PKey::RSA.new(1024)
|
215
214
|
pubkey = privkey.public_key
|
@@ -218,12 +217,11 @@ RSpec.describe ChefVault::Item do
|
|
218
217
|
allow(client_key).to receive(:type).and_return("clients")
|
219
218
|
|
220
219
|
# node without client throws relevant error on key load
|
221
|
-
allow(node_without_valid_client).to receive(:name).and_return("bar")
|
222
220
|
allow(item).to receive(:load_actor).with("bar", "clients").and_raise(ChefVault::Exceptions::ClientNotFound)
|
223
221
|
|
224
222
|
allow(query_result)
|
225
223
|
.to receive(:search)
|
226
|
-
.with(Symbol, String)
|
224
|
+
.with(Symbol, String, Hash)
|
227
225
|
.and_yield(node_with_valid_client).and_yield(node_without_valid_client)
|
228
226
|
allow(Chef::Search::Query)
|
229
227
|
.to receive(:new)
|
@@ -306,7 +304,7 @@ RSpec.describe ChefVault::Item do
|
|
306
304
|
end
|
307
305
|
|
308
306
|
context "when no action is passed" do
|
309
|
-
it "
|
307
|
+
it "defaults to add and properly adds the client" do
|
310
308
|
item.clients(clients)
|
311
309
|
expect(item.get_clients).to include(client_name)
|
312
310
|
end
|
data/spec/chef-vault_spec.rb
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
#
|
2
|
+
# Helper for configuring the Chef Zero server
|
3
|
+
# (inspired by ChefSpec)
|
4
|
+
#
|
5
|
+
def chef_zero
|
6
|
+
require "socket"
|
7
|
+
require "tmpdir"
|
8
|
+
require "fileutils"
|
9
|
+
require "chef_zero/server"
|
10
|
+
# Find a free TCP port
|
11
|
+
server = TCPServer.new("127.0.0.1", 0)
|
12
|
+
port = server.addr[1].to_i
|
13
|
+
server.close
|
14
|
+
# Define a Chef Zero Server
|
15
|
+
server = ChefZero::Server.new(port: port)
|
16
|
+
# Write the private key
|
17
|
+
tmp = Dir.mktmpdir
|
18
|
+
key = File.join(tmp, "client.pem")
|
19
|
+
File.write(key, ChefZero::PRIVATE_KEY)
|
20
|
+
# Configure the server
|
21
|
+
Chef::Config[:client_key] = key
|
22
|
+
Chef::Config[:client_name] = "chefvault"
|
23
|
+
Chef::Config[:node_name] = "chefvault"
|
24
|
+
Chef::Config[:chef_server_url] = server.url
|
25
|
+
# Exit handlers
|
26
|
+
at_exit { FileUtils.rm_rf(tmp) }
|
27
|
+
at_exit { server.stop if server.running? }
|
28
|
+
server
|
29
|
+
end
|
30
|
+
|
1
31
|
RSpec.describe ChefVault do
|
2
32
|
let(:vault) { ChefVault.new("foo") }
|
3
33
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-vault
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0.
|
4
|
+
version: 3.0.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thom May
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|