chef-vault 3.0.0.rc1 → 3.0.0.rc2

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
  SHA1:
3
- metadata.gz: 013e6523217845790623a20fd102c256e77b89fd
4
- data.tar.gz: 0813f2bc7c28752f527da0e3b20bb8f22199debf
3
+ metadata.gz: a6dd267f10f94be45c16f2a088e476226b4b0cf5
4
+ data.tar.gz: 27fc5a1ee95c7be2ad1af5f967d4bbda96427b6a
5
5
  SHA512:
6
- metadata.gz: 85295a103f851bbeed80e9c60eb167081576f9701d3bc05ff84d960c387f44c38dba856d329d572c8c7abf5a08a94f2d718eeec4c930a3e5ee8d396578f85a2b
7
- data.tar.gz: c3b14961386e91c2aa572311f9da1c83ccf07f8e43fd74cfd16fed72c338c74950af5fd0b6e6f8077aa602ebbe31ae4338909547c05b27031032d6be9bebac4b
6
+ metadata.gz: 9397b282b2497e73b1fef2cb86f09f84df98bc9333513cd4648767436e15138f9c9cee187c56854ee3e2197a61ee992e6cdd4f502145b89d194eb428c0ccb07c
7
+ data.tar.gz: 6a978b6a18e4a1a4b4eb8e3ddd3ce48318126e3f152dd5080ee20e19993afece13540df9b33b9a64b6873b483876c9041653ba91739a64ca3d0bc94b632a4dfd
data/.gitignore CHANGED
@@ -29,3 +29,5 @@ Gemfile.lock
29
29
 
30
30
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
31
31
  .rvmrc
32
+
33
+ .chef
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source "https://rubygems.org/"
2
2
 
3
3
  group :development do
4
4
  gem "chefstyle", git: "https://github.com/chef/chefstyle.git"
5
+ gem "chef-zero"
5
6
  end
6
7
 
7
8
  group :changelog do
@@ -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 search_or_client.is_a?(Chef::ApiClient)
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
- elsif search_or_client.is_a?(Array)
87
+ else
82
88
  search_or_client.each do |name|
83
- client = load_actor(name, "clients")
84
- handle_client_action(client, action)
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
- else
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, search_or_client) do |node|
106
+ query.search(:node, statement, filter_result: { name: ["name"] }, rows: 100000) do |node|
90
107
  results_returned = true
91
- case action
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
- "got what you expected!!"
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.each do |client|
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[:solo]
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[:solo]
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(search)
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
- # the node does not exist if a search for the node with that
417
- # name returns no results
418
- query = Chef::Search::Query.new
419
- numresults = query.search(:node, "name:#{nodename}")[2]
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
- begin
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 [Chef::ApiClient, Chef::Node] the API client or node to remove
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(client_or_node)
466
- client = load_actor(client_or_node.name, "clients")
462
+ def delete_client_or_node(name)
463
+ client = load_actor(name, "clients")
467
464
  keys.delete(client)
468
465
  end
469
466
  end
@@ -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
- self[chef_key.name] = ChefVault::ItemKeys.encode_key(chef_key.key, data_bag_shared_secret)
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
- raw_data.delete(chef_key.name)
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 Chef::Config[:solo]
71
- save_solo(item_id)
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[:solo]
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))
@@ -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
@@ -15,6 +15,6 @@
15
15
  # limitations under the License.
16
16
 
17
17
  class ChefVault
18
- VERSION = "3.0.0.rc1"
18
+ VERSION = "3.0.0.rc2"
19
19
  MAJOR, MINOR, TINY = VERSION.split(".")
20
20
  end
@@ -18,9 +18,9 @@ class ChefVault
18
18
  module Helper
19
19
  def set_mode(mode)
20
20
  if mode == "client"
21
- Chef::Config[:solo] = false
21
+ Chef::Config[:solo_legacy_mode] = false
22
22
  else
23
- Chef::Config[:solo] = true
23
+ Chef::Config[:solo_legacy_mode] = true
24
24
  end
25
25
  end
26
26
 
@@ -88,7 +88,7 @@ class Chef
88
88
  end
89
89
 
90
90
  vault_item.search(search) if search
91
- vault_item.clients(search) if search
91
+ vault_item.clients if search
92
92
  vault_item.clients(clients) if clients
93
93
  vault_item.admins(admins) if admins
94
94
 
@@ -79,7 +79,7 @@ class Chef
79
79
  end
80
80
 
81
81
  vault_item.search(search) if search
82
- vault_item.clients(search) if search
82
+ vault_item.clients if search
83
83
  vault_item.clients(clients) if clients
84
84
  vault_item.admins(admins) if admins
85
85
 
@@ -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
- describe "key mgmt operations" do
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
- expect(File).to receive(:exist?).with(File.join(data_bag_path, "foo")).and_call_original
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) { double("chef node valid") }
206
- let(:node_without_valid_client) { double("chef node no 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 "default to add and properly add the client" do
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
@@ -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.rc1
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-10-21 00:00:00.000000000 Z
11
+ date: 2016-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake