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 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