knife-briefcase 0.0.1

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 (47) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +13 -0
  4. data/CHANGELOG.md +6 -0
  5. data/CONTRIBUTING.md +43 -0
  6. data/Gemfile +13 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +83 -0
  9. data/Thorfile +60 -0
  10. data/knife-briefcase.gemspec +32 -0
  11. data/lib/chef/knife/briefcase_delete.rb +14 -0
  12. data/lib/chef/knife/briefcase_get.rb +34 -0
  13. data/lib/chef/knife/briefcase_list.rb +10 -0
  14. data/lib/chef/knife/briefcase_put.rb +32 -0
  15. data/lib/chef/knife/briefcase_reload.rb +45 -0
  16. data/lib/knife-briefcase.rb +5 -0
  17. data/lib/knife-briefcase/knife.rb +69 -0
  18. data/lib/knife-briefcase/version.rb +3 -0
  19. data/spec/chef/knife/briefcase_delete_spec.rb +44 -0
  20. data/spec/chef/knife/briefcase_get_spec.rb +43 -0
  21. data/spec/chef/knife/briefcase_list_spec.rb +17 -0
  22. data/spec/chef/knife/briefcase_put_spec.rb +60 -0
  23. data/spec/chef/knife/briefcase_reload_spec.rb +32 -0
  24. data/spec/fixtures/.gitignore +1 -0
  25. data/spec/fixtures/briefcase.pem +27 -0
  26. data/spec/fixtures/gnupg.1/.gitignore +1 -0
  27. data/spec/fixtures/gnupg.1/pubring.gpg +0 -0
  28. data/spec/fixtures/gnupg.1/secring.gpg +0 -0
  29. data/spec/fixtures/gnupg.1/trustdb.gpg +0 -0
  30. data/spec/fixtures/gnupg.2/.gitignore +1 -0
  31. data/spec/fixtures/gnupg.2/pubring.gpg +0 -0
  32. data/spec/fixtures/gnupg.2/secring.gpg +0 -0
  33. data/spec/fixtures/gnupg.2/trustdb.gpg +0 -0
  34. data/spec/fixtures/gnupg.without-1/.gitignore +1 -0
  35. data/spec/fixtures/gnupg.without-1/pubring.gpg +0 -0
  36. data/spec/fixtures/gnupg.without-1/secring.gpg +0 -0
  37. data/spec/fixtures/gnupg.without-1/trustdb.gpg +0 -0
  38. data/spec/fixtures/gnupg/.gitignore +1 -0
  39. data/spec/fixtures/gnupg/pubring.gpg +0 -0
  40. data/spec/fixtures/gnupg/secring.gpg +0 -0
  41. data/spec/fixtures/gnupg/trustdb.gpg +0 -0
  42. data/spec/fixtures/knife.rb +4 -0
  43. data/spec/knife-briefcase/version_spec.rb +11 -0
  44. data/spec/knife_helper.rb +140 -0
  45. data/spec/smoke_spec.rb +9 -0
  46. data/spec/spec_helper.rb +62 -0
  47. metadata +271 -0
@@ -0,0 +1,5 @@
1
+ require "knife-briefcase/version"
2
+
3
+ module KnifeBriefcase
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,69 @@
1
+ require 'chef/knife'
2
+
3
+ module KnifeBriefcase
4
+ module Knife
5
+ def self.deps
6
+ super do
7
+ yield if block_given?
8
+ end
9
+ end
10
+
11
+ def self.inherited(c)
12
+ super
13
+
14
+ c.class_eval do
15
+ deps do
16
+ require 'chef/data_bag'
17
+ require 'chef/data_bag_item'
18
+ require 'gpgme'
19
+ require 'highline'
20
+ end
21
+
22
+ category 'briefcase'
23
+ option :data_bag,
24
+ :long => '--data-bag DATA_BAG_NAME',
25
+ :description => 'Name of the data bag'
26
+ end
27
+ end
28
+
29
+ def data_bag_name
30
+ config[:data_bag] || Chef::Config[:briefcase_data_bag] || 'briefcase'
31
+ end
32
+
33
+ def signers
34
+ Chef::Config[:briefcase_signers]
35
+ end
36
+
37
+ def recipients
38
+ Chef::Config[:briefcase_holders]
39
+ end
40
+
41
+ def item_name
42
+ @name_args.first
43
+ end
44
+
45
+ def highline
46
+ super
47
+ rescue NameError
48
+ @highline ||= HighLine.new
49
+ end
50
+
51
+ def file
52
+ rv = @name_args[1]
53
+ rv == '-' ? nil : rv
54
+ end
55
+
56
+ private
57
+
58
+ def crypto
59
+ @crypto ||= GPGME::Crypto.new :armor => true, :passphrase_callback => method(:gpgme_passfunc)
60
+ end
61
+
62
+ def gpgme_passfunc(hook, uid_hint, passphrase_info, prev_was_bad, fd)
63
+ pass = highline.ask("GPG passphrase for #{uid_hint}: ") { |q| q.echo = '.' }
64
+ io = IO.for_fd(fd, 'w')
65
+ io.write "#{pass}\n"
66
+ io.flush
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module KnifeBriefcase
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ require 'tempfile'
4
+
5
+ require 'chef/knife/briefcase_delete'
6
+
7
+ describe Chef::Knife::BriefcaseDelete do
8
+ before do
9
+ knife_config do
10
+ briefcase_signers 'test+knife-briefcase-1@3ofcoins.net'
11
+ briefcase_holders [
12
+ 'test+knife-briefcase-2@3ofcoins.net',
13
+ 'test+knife-briefcase-1@3ofcoins.net' ]
14
+ end
15
+ end
16
+
17
+ it 'deletes a previously uploaded item' do
18
+ expect { knife('briefcase', 'put', 'an-item-id', __FILE__).zero? }
19
+ expect { ridley.data_bag.find('briefcase').item.find('an-item-id') }
20
+ expect { knife('briefcase', 'delete', '--yes', 'an-item-id').zero? }
21
+ deny { ridley.data_bag.find('briefcase').item.find('an-item-id') }
22
+ end
23
+
24
+ it 'fails when item does not exist' do
25
+ expect { rescuing { knife('briefcase', 'delete', '--yes', 'an-item-id') } }
26
+ end
27
+
28
+ it 'deletes multiple items' do
29
+ items = %w[item-1 item-2 item-3]
30
+ items.each do |item|
31
+ expect { knife('briefcase', 'put', item, __FILE__).zero? }
32
+ end
33
+
34
+ items.each do |item|
35
+ expect { ridley.data_bag.find('briefcase').item.find(item) }
36
+ end
37
+
38
+ expect { knife('briefcase', 'delete', '--yes', *items).zero? }
39
+
40
+ items.each do |item|
41
+ deny { ridley.data_bag.find('briefcase').item.find(item) }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ require 'tempfile'
4
+
5
+ require 'chef/knife/briefcase_get'
6
+
7
+ describe Chef::Knife::BriefcaseGet do
8
+ let(:file_path) { __FILE__ }
9
+
10
+ before do
11
+ knife_config do
12
+ briefcase_signers 'test+knife-briefcase-1@3ofcoins.net'
13
+ briefcase_holders [
14
+ 'test+knife-briefcase-2@3ofcoins.net',
15
+ 'test+knife-briefcase-1@3ofcoins.net' ]
16
+ end
17
+ expect { knife('briefcase', 'put', 'an-item-id', file_path).zero? }
18
+ end
19
+
20
+ it 'retrieves the stored encrypted file from the data bag' do
21
+ expect { knife('briefcase', 'get', 'an-item-id').zero? }
22
+ expect { knife_stdout == File.read(file_path) }
23
+ end
24
+
25
+ it 'writes to a provided file' do
26
+ Tempfile.open('output') do |outf|
27
+ expect { knife('briefcase', 'get', 'an-item-id', outf.path).zero? }
28
+ expect { outf.read == File.read(file_path) }
29
+ end
30
+ end
31
+
32
+ it 'writes to stdout for file named "-"' do
33
+ expect { knife('briefcase', 'get', 'an-item-id', '-').zero? }
34
+ expect { knife_stdout == File.read(file_path) }
35
+ end
36
+
37
+ it 'fails when it cannot verify signature' do
38
+ with_gnupg_home('without-1') do
39
+ deny { knife('briefcase', 'get', 'an-item-id').zero? }
40
+ expect { knife_stderr =~ /Cannot verify signature/ }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ require 'chef/knife/briefcase_list'
4
+
5
+ describe Chef::Knife::BriefcaseList do
6
+ it "shows names of briefcase data bag's items" do
7
+ knife_config do
8
+ briefcase_signers 'test+knife-briefcase-1@3ofcoins.net'
9
+ briefcase_holders [
10
+ 'test+knife-briefcase-2@3ofcoins.net',
11
+ 'test+knife-briefcase-1@3ofcoins.net' ]
12
+ end
13
+ expect { knife('briefcase', 'put', 'an-item-id', __FILE__).zero? }
14
+ expect { knife('briefcase', 'list').zero? }
15
+ expect { knife_stdout =~ /an-item-id/ }
16
+ end
17
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ require 'chef/knife/briefcase_put'
4
+
5
+ describe Chef::Knife::BriefcasePut do
6
+ before do
7
+ knife_config do
8
+ briefcase_signers 'test+knife-briefcase-1@3ofcoins.net'
9
+ briefcase_holders [
10
+ 'test+knife-briefcase-2@3ofcoins.net',
11
+ 'test+knife-briefcase-1@3ofcoins.net' ]
12
+ end
13
+ end
14
+
15
+ it 'stores encrypted file to a data bag' do
16
+ expect { knife('briefcase', 'put', 'an-item-id', __FILE__).zero? }
17
+
18
+ briefcase = ridley.data_bag.find('briefcase')
19
+ expect { briefcase }
20
+
21
+ item = briefcase.item.find('an-item-id')
22
+ expect { item }
23
+ expect { item['id'] == 'an-item-id' }
24
+ expect { item['content'] =~ /^-----BEGIN PGP MESSAGE-----/ }
25
+
26
+ executed_block = false
27
+ expect { crypto.decrypt(GPGME::Data.from_str(item['content'])).to_s == File.read(__FILE__) }
28
+
29
+ _verify_yields = false
30
+ expect { crypto.verify(GPGME::Data.from_str(item['content'])) { |sig| _verify_yields = true ; sig.valid? } }
31
+ expect { _verify_yields }
32
+ end
33
+
34
+ it 'reads from stdin when no file given' do
35
+ @knife_stdin = 'whatever'
36
+ expect { knife('briefcase', 'put', 'an-item-id').zero? }
37
+
38
+ encrypted = ridley.data_bag.find('briefcase').item.find('an-item-id')['content']
39
+ expect { crypto.decrypt(GPGME::Data.from_str(encrypted)).to_s == 'whatever' }
40
+ end
41
+
42
+ it 'reads from stdin for file named "-"' do
43
+ @knife_stdin = 'whatever'
44
+ expect { knife('briefcase', 'put', 'an-item-id', '-').zero? }
45
+
46
+ encrypted = ridley.data_bag.find('briefcase').item.find('an-item-id')['content']
47
+ expect { crypto.decrypt(GPGME::Data.from_str(encrypted)).to_s == 'whatever' }
48
+ end
49
+
50
+ it 'overwrites previously stored value' do
51
+ spec_helper = Pathname.new(__FILE__).dirname.dirname.dirname.join('spec_helper.rb')
52
+
53
+ expect { knife('briefcase', 'put', 'an-item-id', __FILE__).zero? }
54
+ expect { knife('briefcase', 'put', 'an-item-id', spec_helper.to_s).zero? }
55
+
56
+ encrypted = ridley.data_bag.find('briefcase').item.find('an-item-id')['content']
57
+ deny { crypto.decrypt(GPGME::Data.from_str(encrypted)).to_s == File.read(__FILE__) }
58
+ expect { crypto.decrypt(GPGME::Data.from_str(encrypted)).to_s == spec_helper.read }
59
+ end
60
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ require 'chef/knife/briefcase_reload'
4
+
5
+ describe Chef::Knife::BriefcaseReload do
6
+ let(:file_path) { __FILE__ }
7
+
8
+ it "re-encrypts data bag's items" do
9
+ knife_config do
10
+ briefcase_signers 'test+knife-briefcase-2@3ofcoins.net'
11
+ briefcase_holders [ 'test+knife-briefcase-1@3ofcoins.net' ]
12
+ end
13
+ expect { knife('briefcase', 'put', 'an-item-id', file_path).zero? }
14
+
15
+ with_gnupg_home('without-1') do
16
+ deny { knife('briefcase', 'get', 'an-item-id').zero? }
17
+ end
18
+
19
+ knife_config do
20
+ briefcase_holders [
21
+ 'test+knife-briefcase-2@3ofcoins.net',
22
+ 'test+knife-briefcase-1@3ofcoins.net' ]
23
+ end
24
+
25
+ expect { knife('briefcase', 'reload', 'an-item-id').zero? }
26
+
27
+ with_gnupg_home('without-1') do
28
+ expect { knife('briefcase', 'get', 'an-item-id').zero? }
29
+ expect { knife_stdout == File.read(file_path) }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1 @@
1
+ /gnupg*/random_seed
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEowIBAAKCAQEAoNxmevJz7m3Qe8+aWjamx2pLzr8MM3gNakOo6yd7ap3416uF
3
+ S2eTfNSn7Hbr8JEztFqzgBho/UiU7Dg4rKQezKgzRM/SGWtLVJgJPfHNKPllfOLp
4
+ nxWzv+TlZXNX0C64ebK9t4PFaDEiEMKL/XGyd7zCk9eA8A2AEXkpKkMv3xCRQgHu
5
+ 9bhgFxTWZa1EvPsXihx7JSN2gjBfnfYobnLjeIHj2B+Mj5c2L93zB6m4C4qIE5hj
6
+ ipgRkr0o8BS9RqJ88cmZtEMqm/ZsxyTFi10LTPqIhdAnq67Trr0ORfeIyR9H/AnY
7
+ MuLUTwME0PikPdmyrt9uTZ/a1R2EHrJDI10HzwIDAQABAoIBAHegD/IEleRM9Aru
8
+ 80l9dP+9c8y3VLp93/QThu4BeY1rFyBD5KeTyiG9/3chZQqM4NeR0AVFoeYh8OXO
9
+ VY9FqcXmm+HjbsoKeYXaXp0bUcfT1/5MvRHaUMc20MVmRnqCFBwkqWNs8gQu7bdr
10
+ BjIfOGpFDKpnS/K5B3F3Gf7c4h/Og2szNOgASUdS4rOvOvSkI0VDz8TQ7FLZN0rp
11
+ EQUs/+X5kehqdFVGLZ05Z9AOLb77+Qq4i8JUuS3eZHtjFf8byQYs3fOkIN2WBuYB
12
+ U/oNH4y4hu5RBTdciRExByHGWRylgvpbI/su7Xmxz6g+HnGbfHk8y1kTisCsh8eS
13
+ xi4DzhECgYEAzhqFkyHi74rTGCHjmjOAT1a/T59r4r6rPp6rYds3J3S8CX8hSX91
14
+ 0+VjUQzQAaEpDRuhivCMFoph4a+BkOcpIpVxr/4TBhevHmMiDE5930MvwH6wiULM
15
+ Fa3/DObo8T2VIZL7RJhyBtsqfuzGQUPqrZzBBsKGaknOPwFuTzV4oecCgYEAx83r
16
+ Q2bCwncr8x/y9ZqSRGn5xJ/NtL3FUOFJcR4yvc+wp1lywzV5a2RHtTEYTfho2C8w
17
+ F7KXDZ5oLVTXjlWfA5Yrt1il2kQrjGoHbhn2P8it8NIr5ZIwWSyAdpYCD0ZWaGfh
18
+ NRcORkbW3H9R+lgkEkxpYNC6wXM62Fy7DwjCfdkCgYEAxrdjmpzNhVBAf8ANBpwp
19
+ VlW5VzfKeXCFA3dQnqUR5IT01+MvYQH3xToiK/9Cfo+4WN8PPjr3lrQN89+X+PIo
20
+ AyQ73QgHp5QmUBIcvejgC+dnnx2HcJBq3WxJwVLRvec2Zoykn1qsdlfR/ValQEAP
21
+ gRzmL3JWzxwiMzVZ+h0AFnkCgYBf7NTOfz9x7ZUEHIqgr50Zi2eGptIzvAhHVGHW
22
+ FRF3X4cIUUFvxvSMQpDKxM9OX7y2TbFhLzSmLS8G1HzIsQKuziIe3EiECcZ+m0kF
23
+ 6yD2bnpT7BN3HEBqD5t9U3eZrcM+TOEqg+8ufkQZiGbrMfXfcyAEgzGmPpQ53AtS
24
+ pHn7wQKBgH9HraJ2VQQBSt146Ui0M2ZQTe1xs5FZG8bK6zLRQRa1JhZiMRcykONL
25
+ mp4YJxm5GKDIL2M8NC97R5W5P1D6lCDyBWDhnCgwkRFn7Hbe7Styam8K0G2naZC4
26
+ psJp5QUEswOerf94tIZ0FGVM6yBX0eydEsOPeVRaE/EYyJvwYRZS
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1 @@
1
+ S.gpg-agent
@@ -0,0 +1 @@
1
+ S.gpg-agent
@@ -0,0 +1 @@
1
+ S.gpg-agent
@@ -0,0 +1 @@
1
+ S.gpg-agent
@@ -0,0 +1,4 @@
1
+ $__KNIFE_INTEGRATION_FAILSAFE_CHECK << " ole"
2
+
3
+ node_name 'briefcase'
4
+ client_key File.join(File.dirname(__FILE__), 'briefcase.pem')
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ # A smoke test spec to make sure tests actually work
4
+
5
+ module KnifeBriefcase
6
+ describe VERSION do
7
+ it 'is equal to itself' do
8
+ expect { VERSION == KnifeBriefcase::VERSION }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,140 @@
1
+ # Modified from: https://github.com/jkeiser/knife-essentials/blob/master/spec/support/knife_support.rb
2
+
3
+ require 'logger'
4
+ require 'pathname'
5
+ require 'shellwords'
6
+
7
+ require 'chef_zero/server'
8
+ require 'chef/application/knife'
9
+ require 'chef/config'
10
+ require 'chef/knife'
11
+ require 'chef/log'
12
+
13
+ module KnifeBriefcase
14
+ module Spec
15
+ module KnifeHelper
16
+ extend MiniTest::Spec::DSL
17
+
18
+ class << self
19
+ def chef_zero_server?
20
+ !!@chef_zero_server
21
+ end
22
+
23
+ def chef_zero_server
24
+ @chef_zero_server ||= start_chef_zero_server!
25
+ end
26
+
27
+ def chef_zero_port
28
+ @chef_zero_port ||= chef_zero_server.
29
+ server.
30
+ instance_variable_get(:@ios).
31
+ find { |io| io.class == TCPServer }.
32
+ addr[1]
33
+ end
34
+
35
+ private
36
+
37
+ def start_chef_zero_server!
38
+ @chef_zero_server = @chef_zero_port = nil
39
+ server = ChefZero::Server.new(:port => 0)
40
+ server.start_background
41
+ server
42
+ end
43
+ end
44
+
45
+ DEBUG = !!ENV['DEBUG']
46
+
47
+ before do
48
+ if ::KnifeBriefcase::Spec::KnifeHelper.chef_zero_server?
49
+ ::KnifeBriefcase::Spec::KnifeHelper.chef_zero_server.clear_data
50
+ end
51
+ @chef_configuration = Chef::Config.configuration.dup
52
+ end
53
+
54
+ after do
55
+ Chef::Config.configuration = @chef_configuration
56
+ end
57
+
58
+ def knife_config(&block)
59
+ Chef::Config.instance_eval(&block)
60
+ end
61
+
62
+ def chef_server_url
63
+ "http://127.0.0.1:#{KnifeHelper::chef_zero_port}/"
64
+ end
65
+
66
+ attr_reader :knife_stdout, :knife_stderr
67
+ attr_accessor :knife_stdin
68
+
69
+ def knife(*args, &block)
70
+ args = Shellwords.split(args.first) if args.length == 1
71
+ Dir.mktmpdir('checksums') do |checksums_cache_dir|
72
+ Chef::Config[:cache_options] = {
73
+ :path => checksums_cache_dir,
74
+ :skip_expires => true
75
+ }
76
+
77
+ # This is Chef::Knife.run without load_commands--we'll load stuff
78
+ # ourselves, thank you very much
79
+ stdout = StringIO.new
80
+ stderr = StringIO.new
81
+ stdin = knife_stdin ? StringIO.new(knife_stdin) : STDIN
82
+ old_loggers = Chef::Log.loggers
83
+ old_log_level = Chef::Log.level
84
+ begin
85
+ puts "knife: #{args.join(' ')}" if DEBUG
86
+ subcommand_class = Chef::Knife.subcommand_class_from(args)
87
+ subcommand_class.options = Chef::Application::Knife.options.merge(subcommand_class.options)
88
+ subcommand_class.load_deps
89
+ instance = subcommand_class.new(args)
90
+
91
+ # Capture stdout/stderr
92
+ instance.ui = Chef::Knife::UI.new(stdout, stderr, stdin, instance.config)
93
+
94
+ # Don't print stuff
95
+ Chef::Config[:verbosity] = ( DEBUG ? 2 : 0 )
96
+ instance.config[:config_file] = Pathname.new(__FILE__).dirname.join('fixtures', 'knife.rb').to_s
97
+ instance.config[:chef_server_url] = chef_server_url
98
+
99
+
100
+ # Configure chef with a (mostly) blank knife.rb
101
+ # We set a global and then mutate it in our stub knife.rb so we can be
102
+ # extra sure that we're not loading someone's real knife.rb and then
103
+ # running test scenarios against a real chef server. If things don't
104
+ # smell right, abort.
105
+
106
+ $__KNIFE_INTEGRATION_FAILSAFE_CHECK = "ole"
107
+ instance.configure_chef
108
+
109
+ unless $__KNIFE_INTEGRATION_FAILSAFE_CHECK == "ole ole"
110
+ raise Exception, "Potential misconfiguration of integration tests detected. Aborting test."
111
+ end
112
+ logger = Logger.new(stderr)
113
+ logger.formatter = proc { |severity, datetime, progname, msg| "#{severity}: #{msg}\n" }
114
+ Chef::Log.use_log_devices([logger])
115
+ Chef::Log.level = ( DEBUG ? :debug : :warn )
116
+ Chef::Log::Formatter.show_time = false
117
+
118
+ instance.run
119
+
120
+ exit_code = 0
121
+
122
+ # This is how rspec catches exit()
123
+ rescue SystemExit => e
124
+ exit_code = e.status
125
+ ensure
126
+ Chef::Log.use_log_devices(old_loggers)
127
+ Chef::Log.level = old_log_level
128
+ end
129
+
130
+
131
+ @knife_stdout = stdout.string
132
+ @knife_stderr = stderr.string
133
+
134
+ puts "STDOUT:\n#{knife_stdout}\n\nSTDERR:\n#{knife_stderr}" if DEBUG
135
+ exit_code
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end