knife-briefcase 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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