clc-cheffish 0.8.clc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +4 -0
  4. data/Rakefile +23 -0
  5. data/lib/chef/provider/chef_acl.rb +434 -0
  6. data/lib/chef/provider/chef_client.rb +48 -0
  7. data/lib/chef/provider/chef_container.rb +50 -0
  8. data/lib/chef/provider/chef_data_bag.rb +50 -0
  9. data/lib/chef/provider/chef_data_bag_item.rb +273 -0
  10. data/lib/chef/provider/chef_environment.rb +78 -0
  11. data/lib/chef/provider/chef_group.rb +78 -0
  12. data/lib/chef/provider/chef_mirror.rb +138 -0
  13. data/lib/chef/provider/chef_node.rb +82 -0
  14. data/lib/chef/provider/chef_organization.rb +150 -0
  15. data/lib/chef/provider/chef_resolved_cookbooks.rb +41 -0
  16. data/lib/chef/provider/chef_role.rb +79 -0
  17. data/lib/chef/provider/chef_user.rb +53 -0
  18. data/lib/chef/provider/private_key.rb +219 -0
  19. data/lib/chef/provider/public_key.rb +82 -0
  20. data/lib/chef/resource/chef_acl.rb +65 -0
  21. data/lib/chef/resource/chef_client.rb +44 -0
  22. data/lib/chef/resource/chef_container.rb +18 -0
  23. data/lib/chef/resource/chef_data_bag.rb +18 -0
  24. data/lib/chef/resource/chef_data_bag_item.rb +114 -0
  25. data/lib/chef/resource/chef_environment.rb +71 -0
  26. data/lib/chef/resource/chef_group.rb +49 -0
  27. data/lib/chef/resource/chef_mirror.rb +47 -0
  28. data/lib/chef/resource/chef_node.rb +18 -0
  29. data/lib/chef/resource/chef_organization.rb +64 -0
  30. data/lib/chef/resource/chef_resolved_cookbooks.rb +31 -0
  31. data/lib/chef/resource/chef_role.rb +104 -0
  32. data/lib/chef/resource/chef_user.rb +51 -0
  33. data/lib/chef/resource/private_key.rb +44 -0
  34. data/lib/chef/resource/public_key.rb +21 -0
  35. data/lib/cheffish.rb +222 -0
  36. data/lib/cheffish/actor_provider_base.rb +131 -0
  37. data/lib/cheffish/basic_chef_client.rb +115 -0
  38. data/lib/cheffish/chef_provider_base.rb +231 -0
  39. data/lib/cheffish/chef_run_data.rb +19 -0
  40. data/lib/cheffish/chef_run_listener.rb +28 -0
  41. data/lib/cheffish/key_formatter.rb +109 -0
  42. data/lib/cheffish/merged_config.rb +94 -0
  43. data/lib/cheffish/recipe_dsl.rb +147 -0
  44. data/lib/cheffish/server_api.rb +52 -0
  45. data/lib/cheffish/version.rb +3 -0
  46. data/lib/cheffish/with_pattern.rb +21 -0
  47. data/spec/functional/fingerprint_spec.rb +64 -0
  48. data/spec/functional/merged_config_spec.rb +20 -0
  49. data/spec/integration/chef_acl_spec.rb +914 -0
  50. data/spec/integration/chef_client_spec.rb +110 -0
  51. data/spec/integration/chef_container_spec.rb +34 -0
  52. data/spec/integration/chef_group_spec.rb +324 -0
  53. data/spec/integration/chef_mirror_spec.rb +244 -0
  54. data/spec/integration/chef_node_spec.rb +211 -0
  55. data/spec/integration/chef_organization_spec.rb +244 -0
  56. data/spec/integration/chef_user_spec.rb +90 -0
  57. data/spec/integration/private_key_spec.rb +446 -0
  58. data/spec/integration/recipe_dsl_spec.rb +29 -0
  59. data/spec/support/key_support.rb +29 -0
  60. data/spec/support/repository_support.rb +103 -0
  61. data/spec/support/spec_support.rb +176 -0
  62. data/spec/unit/get_private_key_spec.rb +93 -0
  63. metadata +162 -0
@@ -0,0 +1,29 @@
1
+ require 'support/spec_support'
2
+ require 'chef/resource/chef_node'
3
+ require 'chef/provider/chef_node'
4
+ require 'tmpdir'
5
+
6
+ describe 'Cheffish Recipe DSL' do
7
+ extend SpecSupport
8
+
9
+ context 'when we include with_chef_local_server' do
10
+ before :each do
11
+ @tmp_repo = tmp_repo = Dir.mktmpdir('chef_repo')
12
+ load_recipe do
13
+ with_chef_local_server :chef_repo_path => tmp_repo
14
+ end
15
+ end
16
+
17
+ after :each do
18
+ FileUtils.remove_entry_secure @tmp_repo
19
+ end
20
+
21
+ it 'chef_nodes get put into said server' do
22
+ run_recipe do
23
+ chef_node 'blah'
24
+ end
25
+ expect(chef_run).to have_updated 'chef_node[blah]', :create
26
+ expect(File).to exist("#{@tmp_repo}/nodes/blah.json")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ RSpec::Matchers.define :be_public_key_for do |private_key, pass_phrase|
2
+ match do |public_key|
3
+ if public_key.is_a?(String)
4
+ public_key, public_key_format = Cheffish::KeyFormatter.decode(IO.read(File.expand_path(public_key)), pass_phrase, public_key)
5
+ end
6
+ if private_key.is_a?(String)
7
+ private_key, private_key_format = Cheffish::KeyFormatter.decode(IO.read(File.expand_path(private_key)), pass_phrase, private_key)
8
+ end
9
+
10
+ encrypted = public_key.public_encrypt('hi there')
11
+ expect(private_key.private_decrypt(encrypted)).to eq('hi there')
12
+ end
13
+ end
14
+
15
+ RSpec::Matchers.define :match_private_key do |expected, pass_phrase|
16
+ match do |actual|
17
+ if expected.is_a?(String)
18
+ expected, format = Cheffish::KeyFormatter.decode(IO.read(File.expand_path(expected)), pass_phrase, expected)
19
+ end
20
+ if actual.is_a?(String)
21
+ actual, format = Cheffish::KeyFormatter.decode(IO.read(File.expand_path(actual)), pass_phrase, actual)
22
+ end
23
+
24
+ encrypted = actual.public_encrypt('hi there')
25
+ expect(expected.private_decrypt(encrypted)).to eq('hi there')
26
+ encrypted = expected.public_encrypt('hi there')
27
+ expect(actual.private_decrypt(encrypted)).to eq('hi there')
28
+ end
29
+ end
@@ -0,0 +1,103 @@
1
+ module RepositorySupport
2
+ def when_the_repository(desc, *tags, &block)
3
+ context("when the chef repo #{desc}", *tags) do
4
+ include_context "with a chef repo"
5
+ extend WhenTheRepositoryClassMethods
6
+ module_eval(&block)
7
+ end
8
+ end
9
+
10
+ RSpec.shared_context "with a chef repo" do
11
+ before :each do
12
+ raise "Can only create one directory per test" if @repository_dir
13
+ @repository_dir = Dir.mktmpdir('chef_repo')
14
+ Chef::Config.chef_repo_path = @repository_dir
15
+ %w(client cookbook data_bag environment node role user).each do |object_name|
16
+ Chef::Config.delete("#{object_name}_path".to_sym)
17
+ end
18
+ end
19
+
20
+ after :each do
21
+ if @repository_dir
22
+ begin
23
+ %w(client cookbook data_bag environment node role user).each do |object_name|
24
+ Chef::Config.delete("#{object_name}_path".to_sym)
25
+ end
26
+ Chef::Config.delete(:chef_repo_path)
27
+ FileUtils.remove_entry_secure(@repository_dir)
28
+ ensure
29
+ @repository_dir = nil
30
+ end
31
+ end
32
+ Dir.chdir(@old_cwd) if @old_cwd
33
+ end
34
+
35
+ def directory(relative_path, &block)
36
+ old_parent_path = @parent_path
37
+ @parent_path = path_to(relative_path)
38
+ FileUtils.mkdir_p(@parent_path)
39
+ instance_eval(&block) if block
40
+ @parent_path = old_parent_path
41
+ end
42
+
43
+ def file(relative_path, contents)
44
+ filename = path_to(relative_path)
45
+ dir = File.dirname(filename)
46
+ FileUtils.mkdir_p(dir) unless dir == '.'
47
+ File.open(filename, 'w') do |file|
48
+ raw = case contents
49
+ when Hash
50
+ JSON.pretty_generate(contents)
51
+ when Array
52
+ contents.join("\n")
53
+ else
54
+ contents
55
+ end
56
+ file.write(raw)
57
+ end
58
+ end
59
+
60
+ def symlink(relative_path, relative_dest)
61
+ filename = path_to(relative_path)
62
+ dir = File.dirname(filename)
63
+ FileUtils.mkdir_p(dir) unless dir == '.'
64
+ dest_filename = path_to(relative_dest)
65
+ File.symlink(dest_filename, filename)
66
+ end
67
+
68
+ def path_to(relative_path)
69
+ File.expand_path(relative_path, (@parent_path || @repository_dir))
70
+ end
71
+
72
+ def cwd(relative_path)
73
+ @old_cwd = Dir.pwd
74
+ Dir.chdir(path_to(relative_path))
75
+ end
76
+
77
+ module WhenTheRepositoryClassMethods
78
+ def directory(*args, &block)
79
+ before :each do
80
+ directory(*args, &block)
81
+ end
82
+ end
83
+
84
+ def file(*args, &block)
85
+ before :each do
86
+ file(*args, &block)
87
+ end
88
+ end
89
+
90
+ def symlink(*args, &block)
91
+ before :each do
92
+ symlink(*args, &block)
93
+ end
94
+ end
95
+
96
+ def path_to(*args, &block)
97
+ before :each do
98
+ file(*args, &block)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,176 @@
1
+ require 'chef_zero/rspec'
2
+ require 'chef/server_api'
3
+ require 'cheffish'
4
+ require 'cheffish/basic_chef_client'
5
+ require 'chef/provider/chef_acl'
6
+ require 'uri'
7
+ require 'support/repository_support'
8
+
9
+ module SpecSupport
10
+ include ChefZero::RSpec
11
+
12
+ def self.extended(klass)
13
+ klass.class_eval do
14
+ extend RepositorySupport
15
+
16
+ def rest
17
+ Chef::ServerAPI.new
18
+ end
19
+
20
+ def get(path, *args)
21
+ if path[0] == '/'
22
+ path = URI.join(rest.url, path)
23
+ end
24
+ rest.get(path, *args)
25
+ end
26
+
27
+ def chef_run
28
+ converge if !@converged
29
+ event_sink.events
30
+ end
31
+
32
+ def event_sink
33
+ @event_sink ||= EventSink.new
34
+ end
35
+
36
+ def basic_chef_client
37
+ @basic_chef_client ||= begin
38
+ Cheffish::BasicChefClient.new(nil, event_sink)
39
+ end
40
+ end
41
+
42
+ def load_recipe(&block)
43
+ basic_chef_client.load_block(&block)
44
+ end
45
+
46
+ def run_recipe(&block)
47
+ load_recipe(&block)
48
+ converge
49
+ end
50
+
51
+ def reset_chef_client
52
+ @event_sink = nil
53
+ @basic_chef_client = nil
54
+ @converged = false
55
+ end
56
+
57
+ def converge
58
+ if @converged
59
+ raise "Already converged! Cannot converge twice, that's bad mojo."
60
+ end
61
+ @converged = true
62
+ basic_chef_client.converge
63
+ end
64
+ end
65
+ end
66
+
67
+ def with_recipe(&block)
68
+ before :each do
69
+ load_recipe(&block)
70
+ end
71
+
72
+ after :each do
73
+ if !@converged
74
+ raise "Never tried to converge!"
75
+ end
76
+ end
77
+ end
78
+
79
+ def with_converge(&block)
80
+ before :each do
81
+ load_recipe(&block) if block_given?
82
+ converge
83
+ end
84
+ end
85
+
86
+ class EventSink
87
+ def initialize
88
+ @events = []
89
+ end
90
+
91
+ attr_reader :events
92
+
93
+ def method_missing(method, *args)
94
+ @events << [ method, *args ]
95
+ end
96
+ end
97
+ end
98
+
99
+ RSpec::Matchers.define :have_updated do |resource_name, *expected_actions|
100
+ match do |actual|
101
+ actual_actions = actual.select { |event, resource, action| event == :resource_updated && resource.to_s == resource_name }.map { |event, resource, action| action }
102
+ expect(actual_actions).to eq(expected_actions)
103
+ end
104
+ failure_message do |actual|
105
+ updates = actual.select { |event, resource, action| event == :resource_updated }.to_a
106
+ result = "expected that the chef_run would #{expected_actions.join(',')} #{resource_name}."
107
+ if updates.size > 0
108
+ result << " Actual updates were #{updates.map { |event, resource, action| "#{resource.to_s} => #{action.inspect}" }.join(', ')}"
109
+ else
110
+ result << " Nothing was updated."
111
+ end
112
+ result
113
+ end
114
+ failure_message_when_negated do |actual|
115
+ updates = actual.select { |event, resource, action| event == :resource_updated }.to_a
116
+ result = "expected that the chef_run would not #{expected_actions.join(',')} #{resource_name}."
117
+ if updates.size > 0
118
+ result << " Actual updates were #{updates.map { |event, resource, action| "#{resource.to_s} => #{action.inspect}" }.join(', ')}"
119
+ else
120
+ result << " Nothing was updated."
121
+ end
122
+ result
123
+ end
124
+ end
125
+
126
+ RSpec::Matchers.define :update_acls do |acl_paths, expected_acls|
127
+
128
+ errors = []
129
+
130
+ match do |block|
131
+ orig_json = {}
132
+ Array(acl_paths).each do |acl_path|
133
+ orig_json[acl_path] = get(acl_path)
134
+ end
135
+
136
+ block.call
137
+
138
+ orig_json.each_pair do |acl_path, orig|
139
+ changed = get(acl_path)
140
+ expected_acls.each do |permission, hash|
141
+ hash.each do |type, actors|
142
+ actors.each do |actor|
143
+ if actor[0] == '-'
144
+ actor = actor[1..-1]
145
+ errors << "#{acl_path} expected to remove #{type} #{actor} from #{permission} permissions" if changed[permission][type].include?(actor)
146
+ orig[permission][type].delete(actor)
147
+ else
148
+ errors << "#{acl_path} expected to add #{type} #{actor} to #{permission} permissions" if !changed[permission][type].include?(actor)
149
+ changed[permission][type].delete(actor)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ # After checking everything, see if the remaining acl is the same as before
155
+ errors << "#{acl_path} updated more than expected!\nActual:\n#{changed}\nExpected:\n#{orig}" if changed != orig
156
+ end
157
+ errors.size == 0
158
+ end
159
+
160
+ failure_message do |block|
161
+ errors.join("\n")
162
+ end
163
+
164
+ supports_block_expectations
165
+ end
166
+
167
+ RSpec.configure do |config|
168
+ config.filter_run :focus => true
169
+ config.run_all_when_everything_filtered = true
170
+
171
+ config.before :each do
172
+ Chef::Config.reset
173
+ end
174
+ end
175
+
176
+ require 'chef/providers'
@@ -0,0 +1,93 @@
1
+ require 'support/spec_support'
2
+
3
+ describe Cheffish do
4
+ let(:directory_that_exists) {
5
+ Dir.mktmpdir("cheffish-rspec")
6
+ }
7
+
8
+ let(:directory_that_does_not_exist) {
9
+ dir = Dir.mktmpdir("cheffish-rspec")
10
+ FileUtils.remove_entry dir
11
+ dir
12
+ }
13
+
14
+ let(:private_key_contents) { "contents of private key" }
15
+
16
+ let(:private_key_pem_contents) { "contents of private key pem" }
17
+
18
+ let(:private_key_garbage_contents) { "da vinci virus" }
19
+
20
+ def setup_key
21
+ key_file = File.expand_path("ned_stark", directory_that_exists)
22
+ File.open(key_file, "w+") do |f|
23
+ f.write private_key_contents
24
+ end
25
+ end
26
+
27
+ def setup_pem_key
28
+ key_file = File.expand_path("ned_stark.pem", directory_that_exists)
29
+ File.open(key_file, "w+") do |f|
30
+ f.write private_key_pem_contents
31
+ end
32
+ end
33
+
34
+ def setup_garbage_key
35
+ key_file = File.expand_path("ned_stark.pem.bak", directory_that_exists)
36
+ File.open(key_file, "w+") do |f|
37
+ f.write private_key_garbage_contents
38
+ end
39
+ end
40
+
41
+ shared_examples_for "returning the contents of the key file if it finds one" do
42
+ it "returns nil if it cannot find the private key file" do
43
+ expect(Cheffish.get_private_key("ned_stark", config)).to be_nil
44
+ end
45
+
46
+ it "returns the contents of the key if it doesn't have an extension" do
47
+ setup_key
48
+ expect(Cheffish.get_private_key("ned_stark", config)).to eq(private_key_contents)
49
+ end
50
+
51
+ it "returns the contents of the key if it has an extension" do
52
+ setup_pem_key
53
+ expect(Cheffish.get_private_key("ned_stark", config)).to eq(private_key_pem_contents)
54
+ end
55
+
56
+ # we arbitrarily prefer "ned_stark" over "ned_stark.pem" for deterministic behavior
57
+ it "returns the contents of the key that does not have an extension if both exist" do
58
+ setup_key
59
+ setup_pem_key
60
+ expect(Cheffish.get_private_key("ned_stark", config)).to eq(private_key_contents)
61
+ end
62
+ end
63
+
64
+ context "#get_private_key" do
65
+ context "when private_key_paths has a directory which is empty" do
66
+ let(:config) {
67
+ { :private_key_paths => [ directory_that_exists ] }
68
+ }
69
+
70
+ it_behaves_like "returning the contents of the key file if it finds one"
71
+
72
+ context "when it also has a garbage file" do
73
+ before { setup_garbage_key }
74
+
75
+ it "does not return the da vinci virus if we find only the garbage file" do
76
+ setup_garbage_key
77
+ expect(Cheffish.get_private_key("ned_stark", config)).to be_nil
78
+ end
79
+
80
+ it_behaves_like "returning the contents of the key file if it finds one"
81
+ end
82
+
83
+ end
84
+
85
+ context "when private_key_paths leads with a directory that does not exist and then an empty directory" do
86
+ let(:config) {
87
+ { :private_key_paths => [ directory_that_does_not_exist, directory_that_exists ] }
88
+ }
89
+
90
+ it_behaves_like "returning the contents of the key file if it finds one"
91
+ end
92
+ end
93
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clc-cheffish
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.clc
5
+ platform: ruby
6
+ authors:
7
+ - John Keiser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '11.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '11.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: chef-zero
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
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'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: A library to manipulate Chef in Chef.
70
+ email: jkeiser@opscode.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files:
74
+ - README.md
75
+ - LICENSE
76
+ files:
77
+ - LICENSE
78
+ - README.md
79
+ - Rakefile
80
+ - lib/chef/provider/chef_acl.rb
81
+ - lib/chef/provider/chef_client.rb
82
+ - lib/chef/provider/chef_container.rb
83
+ - lib/chef/provider/chef_data_bag.rb
84
+ - lib/chef/provider/chef_data_bag_item.rb
85
+ - lib/chef/provider/chef_environment.rb
86
+ - lib/chef/provider/chef_group.rb
87
+ - lib/chef/provider/chef_mirror.rb
88
+ - lib/chef/provider/chef_node.rb
89
+ - lib/chef/provider/chef_organization.rb
90
+ - lib/chef/provider/chef_resolved_cookbooks.rb
91
+ - lib/chef/provider/chef_role.rb
92
+ - lib/chef/provider/chef_user.rb
93
+ - lib/chef/provider/private_key.rb
94
+ - lib/chef/provider/public_key.rb
95
+ - lib/chef/resource/chef_acl.rb
96
+ - lib/chef/resource/chef_client.rb
97
+ - lib/chef/resource/chef_container.rb
98
+ - lib/chef/resource/chef_data_bag.rb
99
+ - lib/chef/resource/chef_data_bag_item.rb
100
+ - lib/chef/resource/chef_environment.rb
101
+ - lib/chef/resource/chef_group.rb
102
+ - lib/chef/resource/chef_mirror.rb
103
+ - lib/chef/resource/chef_node.rb
104
+ - lib/chef/resource/chef_organization.rb
105
+ - lib/chef/resource/chef_resolved_cookbooks.rb
106
+ - lib/chef/resource/chef_role.rb
107
+ - lib/chef/resource/chef_user.rb
108
+ - lib/chef/resource/private_key.rb
109
+ - lib/chef/resource/public_key.rb
110
+ - lib/cheffish.rb
111
+ - lib/cheffish/actor_provider_base.rb
112
+ - lib/cheffish/basic_chef_client.rb
113
+ - lib/cheffish/chef_provider_base.rb
114
+ - lib/cheffish/chef_run_data.rb
115
+ - lib/cheffish/chef_run_listener.rb
116
+ - lib/cheffish/key_formatter.rb
117
+ - lib/cheffish/merged_config.rb
118
+ - lib/cheffish/recipe_dsl.rb
119
+ - lib/cheffish/server_api.rb
120
+ - lib/cheffish/version.rb
121
+ - lib/cheffish/with_pattern.rb
122
+ - spec/functional/fingerprint_spec.rb
123
+ - spec/functional/merged_config_spec.rb
124
+ - spec/integration/chef_acl_spec.rb
125
+ - spec/integration/chef_client_spec.rb
126
+ - spec/integration/chef_container_spec.rb
127
+ - spec/integration/chef_group_spec.rb
128
+ - spec/integration/chef_mirror_spec.rb
129
+ - spec/integration/chef_node_spec.rb
130
+ - spec/integration/chef_organization_spec.rb
131
+ - spec/integration/chef_user_spec.rb
132
+ - spec/integration/private_key_spec.rb
133
+ - spec/integration/recipe_dsl_spec.rb
134
+ - spec/support/key_support.rb
135
+ - spec/support/repository_support.rb
136
+ - spec/support/spec_support.rb
137
+ - spec/unit/get_private_key_spec.rb
138
+ homepage: http://wiki.opscode.com/display/chef
139
+ licenses: []
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">"
153
+ - !ruby/object:Gem::Version
154
+ version: 1.3.1
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.2.1
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: A library to manipulate Chef in Chef.
161
+ test_files: []
162
+ has_rdoc: