chef-vault 2.9.2 → 3.0.0.rc1

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -11
  3. data/Changelog.md +1 -6
  4. data/Gemfile +4 -5
  5. data/KNIFE_EXAMPLES.md +66 -14
  6. data/LICENSE +201 -177
  7. data/README.md +74 -4
  8. data/Rakefile +1 -1
  9. data/bin/chef-vault +3 -2
  10. data/chef-vault.gemspec +13 -15
  11. data/features/clean.feature +0 -1
  12. data/features/clean_on_refresh.feature +0 -1
  13. data/features/clean_unknown_clients.feature +0 -1
  14. data/features/detect_and_warn_v1_vault.feature +0 -1
  15. data/features/isvault.feature +0 -1
  16. data/features/itemtype.feature +0 -1
  17. data/features/vault_create.feature +1 -2
  18. data/features/vault_list.feature +0 -1
  19. data/features/vault_show.feature +0 -1
  20. data/features/vault_show_vaultname.feature +0 -1
  21. data/features/vault_update.feature +0 -1
  22. data/features/verify_id_matches.feature +0 -1
  23. data/features/wrong_private_key.feature +0 -1
  24. data/hooks/pre-commit +43 -0
  25. data/lib/chef-vault.rb +10 -2
  26. data/lib/chef-vault/actor.rb +149 -0
  27. data/lib/chef-vault/certificate.rb +1 -1
  28. data/lib/chef-vault/chef_api.rb +39 -0
  29. data/lib/chef-vault/item.rb +57 -71
  30. data/lib/chef-vault/item_keys.rb +14 -9
  31. data/lib/chef-vault/user.rb +1 -1
  32. data/lib/chef-vault/version.rb +1 -1
  33. data/lib/chef/knife/vault_base.rb +5 -2
  34. data/lib/chef/knife/{encrypt_delete.rb → vault_clients.rb} +6 -12
  35. data/lib/chef/knife/vault_create.rb +9 -1
  36. data/lib/chef/knife/vault_remove.rb +9 -1
  37. data/lib/chef/knife/vault_rotate_all_keys.rb +1 -1
  38. data/lib/chef/knife/vault_show.rb +4 -4
  39. data/lib/chef/knife/vault_update.rb +13 -5
  40. data/spec/chef-vault/actor_spec.rb +247 -0
  41. data/spec/chef-vault/certificate_spec.rb +2 -9
  42. data/spec/chef-vault/chef_api_spec.rb +39 -0
  43. data/spec/chef-vault/item_keys_spec.rb +52 -0
  44. data/spec/chef-vault/item_spec.rb +139 -85
  45. data/spec/chef-vault/user_spec.rb +2 -9
  46. data/spec/spec_helper.rb +1 -0
  47. metadata +36 -42
  48. data/CONTRIBUTING.md +0 -118
  49. data/lib/chef-vault/chef_patch/api_client.rb +0 -45
  50. data/lib/chef-vault/chef_patch/user.rb +0 -33
  51. data/lib/chef/knife/decrypt.rb +0 -32
  52. data/lib/chef/knife/encrypt_create.rb +0 -51
  53. data/lib/chef/knife/encrypt_remove.rb +0 -42
  54. data/lib/chef/knife/encrypt_rotate_keys.rb +0 -32
  55. data/lib/chef/knife/encrypt_update.rb +0 -51
  56. data/lib/chef/knife/mixin/compat.rb +0 -33
  57. data/lib/chef/knife/vault_decrypt.rb +0 -58
@@ -1,67 +1,12 @@
1
1
  require "openssl"
2
- require "rspec/core/shared_context"
3
-
4
- # it turns out that simulating a node that doesn't have a public
5
- # key is not a simple thing
6
- module BorkedNodeWithoutPublicKey
7
- extend RSpec::Core::SharedContext
8
-
9
- before do
10
- # a node 'foo' with a public key
11
- node_foo = double("chef node foo")
12
- allow(node_foo).to receive(:name).and_return("foo")
13
- client_foo = double("chef apiclient foo")
14
- allow(client_foo).to receive(:name).and_return("foo")
15
- privkey = OpenSSL::PKey::RSA.new(1024)
16
- pubkey = privkey.public_key
17
- allow(client_foo).to receive(:public_key).and_return(pubkey.to_pem)
18
- # a node 'bar' without a public key
19
- node_bar = double("chef node bar")
20
- allow(node_bar).to receive(:name).and_return("bar")
21
- # fake out searches to return both of our nodes
22
- query_result = double("chef search results")
23
- allow(query_result)
24
- .to receive(:search)
25
- .with(Symbol, String)
26
- .and_yield(node_foo).and_yield(node_bar)
27
- allow(Chef::Search::Query)
28
- .to receive(:new)
29
- .and_return(query_result)
30
- # create a new vault item
31
- @vaultitem = ChefVault::Item.new("foo", "bar")
32
- @vaultitem["foo"] = "bar"
33
- # make the vault item return the apiclient for foo but raise for bar
34
- allow(@vaultitem).to receive(:load_client).with("foo")
35
- .and_return(client_foo)
36
- allow(@vaultitem).to receive(:load_client).with("bar")
37
- .and_raise(ChefVault::Exceptions::ClientNotFound)
38
- # make the vault item fall back to 'load-admin-as-client' behaviour
39
- http_response = double("http not found")
40
- allow(http_response).to receive(:code).and_return("404")
41
- http_not_found = Net::HTTPServerException.new("not found", http_response)
42
- allow(ChefVault::ChefPatch::User)
43
- .to receive(:load)
44
- .with("foo")
45
- .and_return(client_foo)
46
- allow(ChefVault::ChefPatch::User)
47
- .to receive(:load)
48
- .with("bar")
49
- .and_raise(http_not_found)
50
- end
51
- end
52
2
 
53
3
  RSpec.describe ChefVault::Item do
54
- before do
55
- @orig_stdout = $stdout
56
- $stdout = File.open(File::NULL, "w")
57
- end
4
+ subject(:item) { ChefVault::Item.new("foo", "bar") }
58
5
 
59
- after do
60
- $stdout = @orig_stdout
6
+ before do
7
+ item["foo"] = "bar"
61
8
  end
62
9
 
63
- subject(:item) { ChefVault::Item.new("foo", "bar") }
64
-
65
10
  describe "vault probe predicates" do
66
11
  before do
67
12
  # a normal data bag item
@@ -214,8 +159,7 @@ RSpec.describe ChefVault::Item do
214
159
  context 'when item["id"] is bar.bar' do
215
160
  let(:item) { ChefVault::Item.new("foo", "bar.bar") }
216
161
  it "raises an error on save with an invalid item['id']" do
217
- expect { item.save }.to raise_error
218
-
162
+ expect { item.save }.to raise_error(RuntimeError)
219
163
  end
220
164
  end
221
165
 
@@ -245,10 +189,10 @@ RSpec.describe ChefVault::Item do
245
189
  allow(Chef::Search::Query).to receive(:new).and_return(query)
246
190
  allow(query).to receive(:search).and_yield(node)
247
191
 
248
- client = double("client",
249
- name: "testclient",
250
- public_key: OpenSSL::PKey::RSA.new(1024).public_key)
251
- allow(ChefVault::ChefPatch::ApiClient).to receive(:load).and_return(client)
192
+ client_key = double("client_key",
193
+ name: "testnode",
194
+ public_key: OpenSSL::PKey::RSA.new(1024).public_key)
195
+ allow(item).to receive(:load_actor).with("testnode", "clients").and_return(client_key)
252
196
 
253
197
  expect(item).not_to receive(:save)
254
198
  expect(keys).to receive(:save)
@@ -257,38 +201,148 @@ RSpec.describe ChefVault::Item do
257
201
  end
258
202
 
259
203
  describe "#clients" do
260
- include BorkedNodeWithoutPublicKey
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") }
207
+ let(:query_result) { double("chef search results") }
208
+ let(:client_key) { double("chef key") }
209
+
210
+ before do
211
+ # node with valid client proper loads client key
212
+ allow(node_with_valid_client).to receive(:name).and_return("foo")
213
+ allow(item).to receive(:load_actor).with("foo", "clients").and_return(client_key)
214
+ privkey = OpenSSL::PKey::RSA.new(1024)
215
+ pubkey = privkey.public_key
216
+ allow(client_key).to receive(:key).and_return(pubkey.to_pem)
217
+ allow(client_key).to receive(:name).and_return("foo")
218
+ allow(client_key).to receive(:type).and_return("clients")
219
+
220
+ # node without client throws relevant error on key load
221
+ allow(node_without_valid_client).to receive(:name).and_return("bar")
222
+ allow(item).to receive(:load_actor).with("bar", "clients").and_raise(ChefVault::Exceptions::ClientNotFound)
223
+
224
+ allow(query_result)
225
+ .to receive(:search)
226
+ .with(Symbol, String)
227
+ .and_yield(node_with_valid_client).and_yield(node_without_valid_client)
228
+ allow(Chef::Search::Query)
229
+ .to receive(:new)
230
+ .and_return(query_result)
231
+ end
232
+
233
+ it "should not blow up when search returns a node without a public key" do
234
+ # try to set clients when we know a node is missing a public key
235
+ # this should not die as of v2.4.1
236
+ expect { item.clients("*:*") }.not_to raise_error
237
+ end
261
238
 
262
- it "should not blow up when search returns a node without a public key" do
263
- # try to set clients when we know a node is missing a public key
264
- # this should not die as of v2.4.1
265
- expect { @vaultitem.clients("*:*") }.not_to raise_error
239
+ it "should emit a warning if search returns a node without a public key" do
240
+ # it should however emit a warning that you have a borked node
241
+ expect(ChefVault::Log).to receive(:warn).with(/node 'bar' has no private key; skipping/)
242
+ item.clients("*:*")
243
+ end
266
244
  end
267
245
 
268
- it "should emit a warning if search returns a node without a public key" do
269
- # it should however emit a warning that you have a borked node
270
- expect { @vaultitem.clients("*:*") }
271
- .to output(/node 'bar' has no private key; skipping/).to_stdout
246
+ context "when a Chef::ApiClient is passed" do
247
+ let(:client) { Chef::ApiClient.new }
248
+ let(:client_name) { "foo" }
249
+ let(:client_key) { double("chef key") }
250
+
251
+ before do
252
+ client.name client_name
253
+ privkey = OpenSSL::PKey::RSA.new(1024)
254
+ pubkey = privkey.public_key
255
+ allow(item).to receive(:load_actor).with(client_name, "clients").and_return(client_key)
256
+ allow(client_key).to receive(:key).and_return(pubkey.to_pem)
257
+ allow(client_key).to receive(:name).and_return(client_name)
258
+ allow(client_key).to receive(:type).and_return("clients")
259
+ end
260
+
261
+ context "when no action is passed" do
262
+ it "default to add and properly add the client" do
263
+ item.clients(client)
264
+ expect(item.get_clients).to include(client_name)
265
+ end
266
+
267
+ it "does not perform a query" do
268
+ expect(Chef::Search::Query).not_to receive(:new)
269
+ item.clients(client)
270
+ end
271
+ end
272
+
273
+ context "when the delete action is passed on an existing client" do
274
+ before do
275
+ # add the client
276
+ item.clients(client)
277
+ end
278
+
279
+ it "properly deletes the client" do
280
+ item.clients(client, :delete)
281
+ expect(item.get_clients).to_not include(client_name)
282
+ end
283
+
284
+ it "does not perform a query" do
285
+ expect(Chef::Search::Query).not_to receive(:new)
286
+ item.clients(client, :delete)
287
+ end
288
+ end
272
289
  end
273
290
 
274
- it "should accept a client object and not perform a search" do
275
- client = Chef::ApiClient.new
276
- client.name "foo"
277
- privkey = OpenSSL::PKey::RSA.new(1024)
278
- pubkey = privkey.public_key
279
- client.public_key(pubkey.to_pem)
280
- expect(Chef::Search::Query).not_to receive(:new)
281
- expect(ChefVault::ChefPatch::User).not_to receive(:load)
282
- @vaultitem.clients(client)
283
- expect(@vaultitem.clients).to include("foo")
291
+ context "when an Array with named clients is passed" do
292
+ let(:client) { Chef::ApiClient.new }
293
+ let(:clients) { Array.new }
294
+ let(:client_name) { "foo" }
295
+ let(:client_key) { double("chef key") }
296
+
297
+ before do
298
+ clients << client_name
299
+ client.name client_name
300
+ privkey = OpenSSL::PKey::RSA.new(1024)
301
+ pubkey = privkey.public_key
302
+ allow(item).to receive(:load_actor).with(client_name, "clients").and_return(client_key)
303
+ allow(client_key).to receive(:key).and_return(pubkey.to_pem)
304
+ allow(client_key).to receive(:name).and_return(client_name)
305
+ allow(client_key).to receive(:type).and_return("clients")
306
+ end
307
+
308
+ context "when no action is passed" do
309
+ it "default to add and properly add the client" do
310
+ item.clients(clients)
311
+ expect(item.get_clients).to include(client_name)
312
+ end
313
+
314
+ it "does not perform a query" do
315
+ expect(Chef::Search::Query).not_to receive(:new)
316
+ item.clients(clients)
317
+ end
318
+ end
319
+
320
+ context "when the delete action is passed on an existing client" do
321
+ before do
322
+ # add the client
323
+ item.clients(clients)
324
+ end
325
+
326
+ it "properly deletes the client" do
327
+ item.clients(clients, :delete)
328
+ expect(item.get_clients).to_not include(client_name)
329
+ end
330
+
331
+ it "does not perform a query" do
332
+ expect(Chef::Search::Query).not_to receive(:new)
333
+ item.clients(clients, :delete)
334
+ end
335
+ end
284
336
  end
285
337
  end
286
338
 
287
339
  describe "#admins" do
288
- include BorkedNodeWithoutPublicKey
340
+ before do
341
+ allow(item).to receive(:load_actor).with("foo", "admins").and_raise(ChefVault::Exceptions::AdminNotFound)
342
+ end
289
343
 
290
344
  it "should blow up if you try to use a node without a public key as an admin" do
291
- expect { @vaultitem.admins("foo,bar") }
345
+ expect { item.admins("foo,bar") }
292
346
  .to raise_error(ChefVault::Exceptions::AdminNotFound)
293
347
  end
294
348
  end
@@ -6,12 +6,6 @@ RSpec.describe ChefVault::User do
6
6
  allow(ChefVault::Item).to receive(:load).with("foo", "bar") { item }
7
7
  allow(item).to receive(:[]).with("id") { "bar" }
8
8
  allow(item).to receive(:[]).with("password") { "baz" }
9
- @orig_stdout = $stdout
10
- $stdout = File.open(File::NULL, "w")
11
- end
12
-
13
- after do
14
- $stdout = @orig_stdout
15
9
  end
16
10
 
17
11
  describe "#new" do
@@ -30,9 +24,8 @@ RSpec.describe ChefVault::User do
30
24
 
31
25
  describe "decrypt_password" do
32
26
  it "echoes warning" do
33
- expect { user.decrypt_password }
34
- .to output("WARNING: This method is deprecated, please switch to item['value'] calls\n")
35
- .to_stdout
27
+ expect(ChefVault::Log).to receive(:warn).with("This method is deprecated, please switch to item['value'] calls")
28
+ user.decrypt_password
36
29
  end
37
30
 
38
31
  it "returns items password" do
@@ -39,6 +39,7 @@ RSpec.configure do |config|
39
39
  # a real object. This is generally recommended, and will default to
40
40
  # `true` in RSpec 4.
41
41
  mocks.verify_partial_doubles = true
42
+ mocks.allow_message_expectations_on_nil = true
42
43
  end
43
44
 
44
45
  # The settings below are suggested to provide a good initial experience
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-vault
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.2
4
+ version: 3.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
- - Kevin Moser
8
- - James FitzGibbon
7
+ - Thom May
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2017-06-21 00:00:00.000000000 Z
11
+ date: 2016-10-21 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
@@ -17,28 +16,42 @@ dependencies:
17
16
  requirements:
18
17
  - - "~>"
19
18
  - !ruby/object:Gem::Version
20
- version: '10.4'
19
+ version: '11.0'
21
20
  type: :development
22
21
  prerelease: false
23
22
  version_requirements: !ruby/object:Gem::Requirement
24
23
  requirements:
25
24
  - - "~>"
26
25
  - !ruby/object:Gem::Version
27
- version: '10.4'
26
+ version: '11.0'
28
27
  - !ruby/object:Gem::Dependency
29
28
  name: rspec
30
29
  requirement: !ruby/object:Gem::Requirement
31
30
  requirements:
32
31
  - - "~>"
33
32
  - !ruby/object:Gem::Version
34
- version: '3.2'
33
+ version: '3.4'
35
34
  type: :development
36
35
  prerelease: false
37
36
  version_requirements: !ruby/object:Gem::Requirement
38
37
  requirements:
39
38
  - - "~>"
40
39
  - !ruby/object:Gem::Version
41
- version: '3.2'
40
+ version: '3.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mutant-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
42
55
  - !ruby/object:Gem::Dependency
43
56
  name: aruba
44
57
  requirement: !ruby/object:Gem::Requirement
@@ -82,36 +95,22 @@ dependencies:
82
95
  - !ruby/object:Gem::Version
83
96
  version: '0.2'
84
97
  - !ruby/object:Gem::Dependency
85
- name: rubocop
98
+ name: chef
86
99
  requirement: !ruby/object:Gem::Requirement
87
100
  requirements:
88
101
  - - "~>"
89
102
  - !ruby/object:Gem::Version
90
- version: '0.30'
91
- type: :development
103
+ version: '12'
104
+ type: :runtime
92
105
  prerelease: false
93
106
  version_requirements: !ruby/object:Gem::Requirement
94
107
  requirements:
95
108
  - - "~>"
96
109
  - !ruby/object:Gem::Version
97
- version: '0.30'
98
- - !ruby/object:Gem::Dependency
99
- name: chef
100
- requirement: !ruby/object:Gem::Requirement
101
- requirements:
102
- - - ">="
103
- - !ruby/object:Gem::Version
104
- version: 0.10.10
105
- type: :development
106
- prerelease: false
107
- version_requirements: !ruby/object:Gem::Requirement
108
- requirements:
109
- - - ">="
110
- - !ruby/object:Gem::Version
111
- version: 0.10.10
110
+ version: '12'
112
111
  description: Data encryption support for Chef using data bags
113
112
  email:
114
- - techcheftm@nordstrom.com
113
+ - thom@chef.io
115
114
  executables:
116
115
  - chef-vault
117
116
  extensions: []
@@ -122,7 +121,6 @@ files:
122
121
  - ".rubocop.yml"
123
122
  - ".simplecov"
124
123
  - ".travis.yml"
125
- - CONTRIBUTING.md
126
124
  - Changelog.md
127
125
  - DEMO.md
128
126
  - Gemfile
@@ -152,28 +150,22 @@ files:
152
150
  - features/vault_update.feature
153
151
  - features/verify_id_matches.feature
154
152
  - features/wrong_private_key.feature
153
+ - hooks/pre-commit
155
154
  - lib/chef-vault.rb
155
+ - lib/chef-vault/actor.rb
156
156
  - lib/chef-vault/certificate.rb
157
- - lib/chef-vault/chef_patch/api_client.rb
158
- - lib/chef-vault/chef_patch/user.rb
157
+ - lib/chef-vault/chef_api.rb
159
158
  - lib/chef-vault/exceptions.rb
160
159
  - lib/chef-vault/item.rb
161
160
  - lib/chef-vault/item_keys.rb
162
161
  - lib/chef-vault/mixins.rb
163
162
  - lib/chef-vault/user.rb
164
163
  - lib/chef-vault/version.rb
165
- - lib/chef/knife/decrypt.rb
166
- - lib/chef/knife/encrypt_create.rb
167
- - lib/chef/knife/encrypt_delete.rb
168
- - lib/chef/knife/encrypt_remove.rb
169
- - lib/chef/knife/encrypt_rotate_keys.rb
170
- - lib/chef/knife/encrypt_update.rb
171
- - lib/chef/knife/mixin/compat.rb
172
164
  - lib/chef/knife/mixin/helper.rb
173
165
  - lib/chef/knife/vault_admins.rb
174
166
  - lib/chef/knife/vault_base.rb
167
+ - lib/chef/knife/vault_clients.rb
175
168
  - lib/chef/knife/vault_create.rb
176
- - lib/chef/knife/vault_decrypt.rb
177
169
  - lib/chef/knife/vault_delete.rb
178
170
  - lib/chef/knife/vault_download.rb
179
171
  - lib/chef/knife/vault_edit.rb
@@ -186,7 +178,9 @@ files:
186
178
  - lib/chef/knife/vault_rotate_keys.rb
187
179
  - lib/chef/knife/vault_show.rb
188
180
  - lib/chef/knife/vault_update.rb
181
+ - spec/chef-vault/actor_spec.rb
189
182
  - spec/chef-vault/certificate_spec.rb
183
+ - spec/chef-vault/chef_api_spec.rb
190
184
  - spec/chef-vault/item_keys_spec.rb
191
185
  - spec/chef-vault/item_spec.rb
192
186
  - spec/chef-vault/user_spec.rb
@@ -205,15 +199,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
205
199
  requirements:
206
200
  - - ">="
207
201
  - !ruby/object:Gem::Version
208
- version: '0'
202
+ version: 2.2.0
209
203
  required_rubygems_version: !ruby/object:Gem::Requirement
210
204
  requirements:
211
- - - ">="
205
+ - - ">"
212
206
  - !ruby/object:Gem::Version
213
- version: '0'
207
+ version: 1.3.1
214
208
  requirements: []
215
209
  rubyforge_project:
216
- rubygems_version: 2.6.11
210
+ rubygems_version: 2.5.1
217
211
  signing_key:
218
212
  specification_version: 4
219
213
  summary: Data encryption support for Chef using data bags