chef 12.0.0.alpha.0 → 12.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +3 -5
  3. data/lib/chef/api_client.rb +1 -1
  4. data/lib/chef/application.rb +16 -8
  5. data/lib/chef/chef_fs/chef_fs_data_store.rb +1 -1
  6. data/lib/chef/chef_fs/command_line.rb +1 -1
  7. data/lib/chef/chef_fs/file_system.rb +1 -1
  8. data/lib/chef/chef_fs/file_system/acl_entry.rb +1 -1
  9. data/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +3 -3
  10. data/lib/chef/chef_fs/file_system/cookbook_file.rb +2 -2
  11. data/lib/chef/chef_fs/file_system/rest_list_dir.rb +2 -2
  12. data/lib/chef/chef_fs/file_system/rest_list_entry.rb +4 -4
  13. data/lib/chef/config.rb +6 -5
  14. data/lib/chef/config_fetcher.rb +1 -1
  15. data/lib/chef/cookbook/cookbook_version_loader.rb +126 -43
  16. data/lib/chef/cookbook/metadata.rb +102 -53
  17. data/lib/chef/cookbook/syntax_check.rb +1 -1
  18. data/lib/chef/cookbook_loader.rb +62 -14
  19. data/lib/chef/cookbook_site_streaming_uploader.rb +12 -1
  20. data/lib/chef/cookbook_version.rb +13 -4
  21. data/lib/chef/data_bag.rb +28 -15
  22. data/lib/chef/data_bag_item.rb +5 -7
  23. data/lib/chef/digester.rb +5 -9
  24. data/lib/chef/dsl/recipe.rb +14 -0
  25. data/lib/chef/encrypted_data_bag_item.rb +1 -0
  26. data/lib/chef/encrypted_data_bag_item/assertions.rb +57 -0
  27. data/lib/chef/encrypted_data_bag_item/decryptor.rb +52 -28
  28. data/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb +37 -0
  29. data/lib/chef/encrypted_data_bag_item/encryption_failure.rb +22 -0
  30. data/lib/chef/encrypted_data_bag_item/encryptor.rb +79 -8
  31. data/lib/chef/environment.rb +1 -3
  32. data/lib/chef/exceptions.rb +18 -3
  33. data/lib/chef/formatters/base.rb +7 -0
  34. data/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb +1 -1
  35. data/lib/chef/handler/json_file.rb +0 -1
  36. data/lib/chef/http/json_output.rb +1 -1
  37. data/lib/chef/json_compat.rb +24 -6
  38. data/lib/chef/knife/bootstrap.rb +2 -2
  39. data/lib/chef/knife/client_delete.rb +1 -1
  40. data/lib/chef/knife/cookbook_site_download.rb +1 -1
  41. data/lib/chef/knife/cookbook_site_list.rb +1 -1
  42. data/lib/chef/knife/cookbook_site_search.rb +1 -1
  43. data/lib/chef/knife/cookbook_site_share.rb +2 -2
  44. data/lib/chef/knife/cookbook_site_show.rb +3 -3
  45. data/lib/chef/knife/cookbook_site_unshare.rb +1 -1
  46. data/lib/chef/knife/core/node_editor.rb +2 -3
  47. data/lib/chef/knife/core/ui.rb +2 -2
  48. data/lib/chef/knife/deps.rb +2 -3
  49. data/lib/chef/mixin/shell_out.rb +1 -1
  50. data/lib/chef/mixin/windows_architecture_helper.rb +1 -0
  51. data/lib/chef/node.rb +1 -2
  52. data/lib/chef/platform/provider_mapping.rb +33 -6
  53. data/lib/chef/provider.rb +0 -2
  54. data/lib/chef/provider/cookbook_file/content.rb +1 -1
  55. data/lib/chef/provider/cron.rb +11 -0
  56. data/lib/chef/provider/deploy.rb +3 -2
  57. data/lib/chef/provider/deploy/revision.rb +2 -2
  58. data/lib/chef/provider/env.rb +1 -1
  59. data/lib/chef/provider/env/windows.rb +5 -9
  60. data/lib/chef/provider/file.rb +84 -33
  61. data/lib/chef/provider/git.rb +2 -1
  62. data/lib/chef/provider/group/aix.rb +17 -2
  63. data/lib/chef/provider/group/dscl.rb +27 -9
  64. data/lib/chef/provider/group/pw.rb +8 -1
  65. data/lib/chef/provider/http_request.rb +4 -4
  66. data/lib/chef/provider/log.rb +4 -14
  67. data/lib/chef/provider/mount/mount.rb +2 -2
  68. data/lib/chef/provider/package/ips.rb +17 -23
  69. data/lib/chef/provider/package/paludis.rb +2 -2
  70. data/lib/chef/provider/package/rpm.rb +2 -2
  71. data/lib/chef/provider/package/rubygems.rb +2 -0
  72. data/lib/chef/provider/package/yum.rb +2 -0
  73. data/lib/chef/provider/package/zypper.rb +1 -1
  74. data/lib/chef/provider/remote_file/cache_control_data.rb +2 -2
  75. data/lib/chef/provider/service/windows.rb +87 -21
  76. data/lib/chef/provider/user/aix.rb +95 -0
  77. data/lib/chef/provider/user/dscl.rb +544 -156
  78. data/lib/chef/provider/user/useradd.rb +1 -0
  79. data/lib/chef/providers.rb +1 -0
  80. data/lib/chef/resource.rb +4 -3
  81. data/lib/chef/resource/freebsd_package.rb +10 -2
  82. data/lib/chef/resource/paludis_package.rb +1 -0
  83. data/lib/chef/resource/scm.rb +10 -0
  84. data/lib/chef/resource/user.rb +27 -0
  85. data/lib/chef/resource/windows_service.rb +53 -0
  86. data/lib/chef/resource_collection.rb +23 -12
  87. data/lib/chef/resource_reporter.rb +10 -10
  88. data/lib/chef/resources.rb +1 -0
  89. data/lib/chef/role.rb +3 -3
  90. data/lib/chef/run_list.rb +6 -3
  91. data/lib/chef/user.rb +1 -1
  92. data/lib/chef/util/diff.rb +1 -2
  93. data/lib/chef/version.rb +1 -1
  94. data/lib/chef/version_constraint.rb +4 -4
  95. data/spec/data/cookbooks/angrybash/metadata.rb +2 -0
  96. data/spec/data/cookbooks/apache2/metadata.rb +2 -0
  97. data/spec/data/cookbooks/borken/metadata.rb +2 -0
  98. data/spec/data/cookbooks/ignorken/metadata.rb +2 -0
  99. data/spec/data/cookbooks/java/metadata.rb +2 -0
  100. data/spec/data/cookbooks/name-mismatch-versionnumber/README.md +4 -0
  101. data/spec/data/cookbooks/name-mismatch-versionnumber/metadata.rb +8 -0
  102. data/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb +8 -0
  103. data/spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb +2 -0
  104. data/spec/data/cookbooks/preseed/metadata.rb +2 -0
  105. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/README.md +4 -0
  106. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/metadata.rb +13 -0
  107. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb +8 -0
  108. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/README.md +4 -0
  109. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb +10 -0
  110. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb +8 -0
  111. data/spec/data/mac_users/10.7-8.plist.xml +559 -0
  112. data/spec/data/mac_users/10.7-8.shadow.xml +11 -0
  113. data/spec/data/mac_users/10.7.plist.xml +559 -0
  114. data/spec/data/mac_users/10.7.shadow.xml +11 -0
  115. data/spec/data/mac_users/10.8.plist.xml +559 -0
  116. data/spec/data/mac_users/10.8.shadow.xml +21 -0
  117. data/spec/data/mac_users/10.9.plist.xml +560 -0
  118. data/spec/data/mac_users/10.9.shadow.xml +21 -0
  119. data/spec/data/object_loader/environments/test.json +2 -0
  120. data/spec/data/object_loader/environments/test_json_class.json +2 -0
  121. data/spec/data/object_loader/nodes/test.json +2 -0
  122. data/spec/data/object_loader/nodes/test_json_class.json +2 -0
  123. data/spec/data/object_loader/roles/test.json +2 -0
  124. data/spec/data/object_loader/roles/test_json_class.json +2 -0
  125. data/spec/functional/resource/bff_spec.rb +1 -1
  126. data/spec/functional/resource/cron_spec.rb +20 -1
  127. data/spec/functional/resource/env_spec.rb +137 -0
  128. data/spec/functional/resource/group_spec.rb +7 -5
  129. data/spec/functional/resource/remote_file_spec.rb +12 -1
  130. data/spec/functional/resource/user/dscl_spec.rb +198 -0
  131. data/spec/functional/resource/{user_spec.rb → user/useradd_spec.rb} +175 -37
  132. data/spec/integration/client/client_spec.rb +6 -4
  133. data/spec/integration/client/ipv6_spec.rb +16 -14
  134. data/spec/integration/knife/chef_fs_data_store_spec.rb +57 -46
  135. data/spec/integration/knife/chef_repo_path_spec.rb +105 -78
  136. data/spec/integration/knife/chef_repository_file_system_spec.rb +100 -84
  137. data/spec/integration/knife/chefignore_spec.rb +76 -46
  138. data/spec/integration/knife/common_options_spec.rb +16 -21
  139. data/spec/integration/knife/cookbook_api_ipv6_spec.rb +3 -3
  140. data/spec/integration/knife/delete_spec.rb +66 -46
  141. data/spec/integration/knife/deps_spec.rb +145 -94
  142. data/spec/integration/knife/diff_spec.rb +176 -110
  143. data/spec/integration/knife/download_spec.rb +229 -133
  144. data/spec/integration/knife/list_spec.rb +62 -54
  145. data/spec/integration/knife/raw_spec.rb +24 -9
  146. data/spec/integration/knife/redirection_spec.rb +2 -2
  147. data/spec/integration/knife/serve_spec.rb +2 -2
  148. data/spec/integration/knife/show_spec.rb +32 -26
  149. data/spec/integration/knife/upload_spec.rb +308 -165
  150. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +10 -8
  151. data/spec/integration/solo/solo_spec.rb +22 -11
  152. data/spec/spec_helper.rb +3 -0
  153. data/spec/support/lib/chef/resource/zen_follower.rb +46 -0
  154. data/spec/support/platform_helpers.rb +12 -0
  155. data/spec/support/shared/functional/file_resource.rb +10 -0
  156. data/spec/support/shared/integration/chef_zero_support.rb +130 -0
  157. data/spec/support/shared/integration/integration_helper.rb +100 -98
  158. data/spec/support/shared/integration/knife_support.rb +0 -1
  159. data/spec/support/shared/unit/provider/file.rb +6 -4
  160. data/spec/support/shared/unit/provider/useradd_based_user_provider.rb +10 -1
  161. data/spec/unit/api_client/registration_spec.rb +83 -74
  162. data/spec/unit/application_spec.rb +32 -9
  163. data/spec/unit/cookbook/cookbook_version_loader_spec.rb +179 -0
  164. data/spec/unit/cookbook/metadata_spec.rb +190 -150
  165. data/spec/unit/cookbook/syntax_check_spec.rb +3 -2
  166. data/spec/unit/cookbook_loader_spec.rb +114 -53
  167. data/spec/unit/{cookbook_site_streaming_uploader.rb → cookbook_site_streaming_uploader_spec.rb} +21 -1
  168. data/spec/unit/data_bag_spec.rb +88 -13
  169. data/spec/unit/deprecation_spec.rb +1 -2
  170. data/spec/unit/encrypted_data_bag_item_spec.rb +145 -9
  171. data/spec/unit/environment_spec.rb +1 -1
  172. data/spec/unit/formatters/base_spec.rb +48 -0
  173. data/spec/unit/json_compat_spec.rb +48 -17
  174. data/spec/unit/knife/client_delete_spec.rb +4 -4
  175. data/spec/unit/knife/client_show_spec.rb +15 -5
  176. data/spec/unit/knife/cookbook_site_download_spec.rb +1 -1
  177. data/spec/unit/knife/cookbook_site_share_spec.rb +3 -3
  178. data/spec/unit/knife/data_bag_from_file_spec.rb +0 -2
  179. data/spec/unit/knife/data_bag_show_spec.rb +23 -14
  180. data/spec/unit/knife/node_show_spec.rb +32 -15
  181. data/spec/unit/knife/role_show_spec.rb +59 -0
  182. data/spec/unit/platform_spec.rb +10 -0
  183. data/spec/unit/provider/deploy_spec.rb +4 -0
  184. data/spec/unit/provider/env_spec.rb +19 -0
  185. data/spec/unit/provider/git_spec.rb +22 -2
  186. data/spec/unit/provider/group/dscl_spec.rb +38 -1
  187. data/spec/unit/provider/group/pw_spec.rb +2 -2
  188. data/spec/unit/provider/http_request_spec.rb +8 -8
  189. data/spec/unit/provider/log_spec.rb +33 -53
  190. data/spec/unit/provider/mount/mount_spec.rb +12 -3
  191. data/spec/unit/provider/package/ips_spec.rb +96 -63
  192. data/spec/unit/provider/package/paludis_spec.rb +5 -5
  193. data/spec/unit/provider/package/rpm_spec.rb +12 -0
  194. data/spec/unit/provider/package/zypper_spec.rb +28 -16
  195. data/spec/unit/provider/service/windows_spec.rb +77 -17
  196. data/spec/unit/provider/user/dscl_spec.rb +659 -264
  197. data/spec/unit/provider/user/useradd_spec.rb +1 -0
  198. data/spec/unit/recipe_spec.rb +41 -0
  199. data/spec/unit/resource/scm_spec.rb +11 -0
  200. data/spec/unit/resource/user_spec.rb +4 -0
  201. data/spec/unit/resource/windows_service_spec.rb +46 -0
  202. data/spec/unit/resource_collection_spec.rb +33 -0
  203. data/spec/unit/resource_reporter_spec.rb +48 -0
  204. data/spec/unit/resource_spec.rb +9 -2
  205. data/spec/unit/role_spec.rb +6 -0
  206. data/spec/unit/version_constraint_spec.rb +28 -0
  207. metadata +61 -4
@@ -46,7 +46,7 @@ describe Chef::Deprecation do
46
46
  end
47
47
 
48
48
  method_snapshot_file = File.join(CHEF_SPEC_DATA, "file-providers-method-snapshot-chef-11-4.json")
49
- method_snapshot = JSON.parse(File.open(method_snapshot_file).read())
49
+ method_snapshot = Chef::JSONCompat.parse(File.open(method_snapshot_file).read())
50
50
 
51
51
  method_snapshot.each do |class_name, old_methods|
52
52
  class_object = class_from_string(class_name)
@@ -83,4 +83,3 @@ describe Chef::Deprecation do
83
83
  end
84
84
 
85
85
  end
86
-
@@ -23,7 +23,7 @@ module Version0Encryptor
23
23
  def self.encrypt_value(plaintext_data, key)
24
24
  data = plaintext_data.to_yaml
25
25
 
26
- cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
26
+ cipher = OpenSSL::Cipher.new("aes-256-cbc")
27
27
  cipher.encrypt
28
28
  cipher.pkcs5_keyivgen(key)
29
29
  encrypted_bytes = cipher.update(data)
@@ -39,14 +39,14 @@ describe Chef::EncryptedDataBagItem::Encryptor do
39
39
  let(:key) { "passwd" }
40
40
 
41
41
  it "encrypts to format version 1 by default" do
42
- encryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor)
42
+ encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor)
43
43
  end
44
44
 
45
45
  describe "generating a random IV" do
46
46
  it "generates a new IV for each encryption pass" do
47
47
  encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key)
48
48
 
49
- # No API in ruby OpenSSL to get the iv it used for the encryption back
49
+ # No API in ruby OpenSSL to get the iv is used for the encryption back
50
50
  # out. Instead we test if the encrypted data is the same. If it *is* the
51
51
  # same, we assume the IV was the same each time.
52
52
  encryptor.encrypted_data.should_not eq encryptor2.encrypted_data
@@ -56,7 +56,7 @@ describe Chef::EncryptedDataBagItem::Encryptor do
56
56
  describe "when encrypting a non-hash non-array value" do
57
57
  let(:plaintext_data) { 5 }
58
58
  it "serializes the value in a de-serializable way" do
59
- Chef::JSONCompat.from_json(subject.serialized_data)["json_wrapper"].should eq 5
59
+ Chef::JSONCompat.from_json(encryptor.serialized_data)["json_wrapper"].should eq 5
60
60
  end
61
61
 
62
62
  end
@@ -78,10 +78,10 @@ describe Chef::EncryptedDataBagItem::Encryptor do
78
78
  end
79
79
 
80
80
  it "creates a version 2 encryptor" do
81
- encryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor)
81
+ encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor)
82
82
  end
83
83
 
84
- it "generates an hmac based on ciphertext including iv" do
84
+ it "generates an hmac based on ciphertext with different iv" do
85
85
  encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key)
86
86
  encryptor.hmac.should_not eq(encryptor2.hmac)
87
87
  end
@@ -92,6 +92,74 @@ describe Chef::EncryptedDataBagItem::Encryptor do
92
92
  end
93
93
  end
94
94
 
95
+ describe "when using version 3 format" do
96
+ before do
97
+ Chef::Config[:data_bag_encrypt_version] = 3
98
+ end
99
+
100
+ context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do
101
+
102
+ it "creates a version 3 encryptor" do
103
+ encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor)
104
+ end
105
+
106
+ it "generates different authentication tags" do
107
+ encryptor3 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key)
108
+ encryptor.for_encrypted_item # required to generate the auth_tag
109
+ encryptor3.for_encrypted_item
110
+ encryptor.auth_tag.should_not eq(encryptor3.auth_tag)
111
+ end
112
+
113
+ it "includes the auth_tag in the envelope" do
114
+ final_data = encryptor.for_encrypted_item
115
+ final_data["auth_tag"].should eq(Base64::encode64(encryptor.auth_tag))
116
+ end
117
+
118
+ it "throws an error if auth tag is read before encrypting the data" do
119
+ lambda { encryptor.auth_tag }.should raise_error(Chef::EncryptedDataBagItem::EncryptionFailure)
120
+ end
121
+
122
+ end # context on supported platforms
123
+
124
+ context "on unsupported platforms" do
125
+ let(:aead_algorithm) { Chef::EncryptedDataBagItem::AEAD_ALGORITHM }
126
+
127
+ it "throws an error warning about the Ruby version if it has no GCM support" do
128
+ # Force OpenSSL with AEAD support
129
+ OpenSSL::Cipher.stub(:ciphers).and_return([ aead_algorithm ])
130
+ # Ruby without AEAD support
131
+ OpenSSL::Cipher.should_receive(:method_defined?).with(:auth_data=).and_return(false)
132
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/)
133
+ end
134
+
135
+ it "throws an error warning about the OpenSSL version if it has no GCM support" do
136
+ # Force Ruby with AEAD support
137
+ OpenSSL::Cipher.stub(:method_defined?).with(:auth_data=).and_return(true)
138
+ # OpenSSL without AEAD support
139
+ OpenSSL::Cipher.should_receive(:ciphers).and_return([])
140
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/)
141
+ end
142
+
143
+ context "on platforms with old Ruby", :ruby_lt_20 do
144
+
145
+ it "throws an error warning about the Ruby version" do
146
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/)
147
+ end
148
+
149
+ end # context on platforms with old Ruby
150
+
151
+ context "on platforms with old OpenSSL", :openssl_lt_101 do
152
+
153
+ it "throws an error warning about the OpenSSL version" do
154
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/)
155
+ end
156
+
157
+ end # context on platforms with old OpenSSL
158
+
159
+ end # context on unsupported platforms
160
+
161
+ end # when using version 3 format
162
+
95
163
  end
96
164
 
97
165
  describe Chef::EncryptedDataBagItem::Decryptor do
@@ -101,17 +169,85 @@ describe Chef::EncryptedDataBagItem::Decryptor do
101
169
  let(:encryption_key) { "passwd" }
102
170
  let(:decryption_key) { encryption_key }
103
171
 
172
+ context "when decrypting a version 3 (JSON+aes-256-gcm+random iv+auth tag) encrypted value" do
173
+
174
+ context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do
175
+
176
+ let(:encrypted_value) do
177
+ Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor.new(plaintext_data, encryption_key).for_encrypted_item
178
+ end
179
+
180
+ let(:bogus_auth_tag) { "bogus_auth_tag" }
181
+
182
+ it "decrypts the encrypted value" do
183
+ decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json)
184
+ end
185
+
186
+ it "unwraps the encrypted data and returns it" do
187
+ decryptor.for_decrypted_item.should eq plaintext_data
188
+ end
189
+
190
+ it "rejects the data if the authentication tag is wrong" do
191
+ encrypted_value["auth_tag"] = bogus_auth_tag
192
+ lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure)
193
+ end
194
+
195
+ it "rejects the data if the authentication tag is missing" do
196
+ encrypted_value.delete("auth_tag")
197
+ lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure)
198
+ end
199
+
200
+ end # context on supported platforms
201
+
202
+ context "on unsupported platforms" do
203
+ let(:encrypted_value) do
204
+ {
205
+ "encrypted_data" => "",
206
+ "iv" => "",
207
+ "version" => 3,
208
+ "cipher" => "aes-256-cbc",
209
+ }
210
+ end
211
+
212
+ context "on platforms with old Ruby", :ruby_lt_20 do
213
+
214
+ it "throws an error warning about the Ruby version" do
215
+ lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/)
216
+ end
217
+
218
+ end # context on platforms with old Ruby
219
+
220
+ context "on platforms with old OpenSSL", :openssl_lt_101 do
221
+
222
+ it "throws an error warning about the OpenSSL version" do
223
+ lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/)
224
+ end
225
+
226
+ end # context on unsupported platforms
227
+
228
+ end # context on platforms with old OpenSSL
229
+
230
+ end # context when decrypting a version 3
231
+
104
232
  context "when decrypting a version 2 (JSON+aes-256-cbc+hmac-sha256+random iv) encrypted value" do
105
233
  let(:encrypted_value) do
106
234
  Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor.new(plaintext_data, encryption_key).for_encrypted_item
107
235
  end
108
236
 
109
237
  let(:bogus_hmac) do
110
- digest = OpenSSL::Digest::Digest.new("sha256")
238
+ digest = OpenSSL::Digest.new("sha256")
111
239
  raw_hmac = OpenSSL::HMAC.digest(digest, "WRONG", encrypted_value["encrypted_data"])
112
240
  Base64.encode64(raw_hmac)
113
241
  end
114
242
 
243
+ it "decrypts the encrypted value" do
244
+ decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json)
245
+ end
246
+
247
+ it "unwraps the encrypted data and returns it" do
248
+ decryptor.for_decrypted_item.should eq plaintext_data
249
+ end
250
+
115
251
  it "rejects the data if the hmac is wrong" do
116
252
  encrypted_value["hmac"] = bogus_hmac
117
253
  lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure)
@@ -131,7 +267,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
131
267
  end
132
268
 
133
269
  it "selects the correct strategy for version 1" do
134
- decryptor.should be_a_kind_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor
270
+ decryptor.should be_a_instance_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor
135
271
  end
136
272
 
137
273
  it "decrypts the encrypted value" do
@@ -191,7 +327,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
191
327
  end
192
328
 
193
329
  it "selects the correct strategy for version 0" do
194
- decryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Decryptor::Version0Decryptor)
330
+ decryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Decryptor::Version0Decryptor)
195
331
  end
196
332
 
197
333
  it "decrypts the encrypted value" do
@@ -420,7 +420,7 @@ describe Chef::Environment do
420
420
  "description" => "desc",
421
421
  "chef_type" => "environment"
422
422
  }
423
- IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(JSON.dump(environment_hash))
423
+ IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(Chef::JSONCompat.to_json(environment_hash))
424
424
  environment = Chef::Environment.load('foo')
425
425
 
426
426
  environment.should be_a_kind_of(Chef::Environment)
@@ -0,0 +1,48 @@
1
+ #
2
+ # Author:: Lamont Granquist (<lamont@getchef.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2012 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ describe Chef::Formatters::Base do
23
+ let(:out) { double("out") }
24
+ let(:err) { double("err") }
25
+ let(:formatter) { Chef::Formatters::Base.new(out, err) }
26
+
27
+ it "starts with an indentation of zero" do
28
+ expect(formatter.output.indent).to eql(0)
29
+ end
30
+
31
+ it "increments it to two correctly" do
32
+ formatter.indent_by(2)
33
+ expect(formatter.output.indent).to eql(2)
34
+ end
35
+
36
+ it "increments it and then decrements it corectly" do
37
+ formatter.indent_by(2)
38
+ formatter.indent_by(-2)
39
+ expect(formatter.output.indent).to eql(0)
40
+ end
41
+
42
+ it "does not allow negative indentation" do
43
+ formatter.indent_by(-2)
44
+ expect(formatter.output.indent).to eql(0)
45
+ end
46
+ end
47
+
48
+
@@ -21,48 +21,79 @@ require 'chef/json_compat'
21
21
 
22
22
  describe Chef::JSONCompat do
23
23
 
24
- describe "with JSON containing an existing class" do
25
- let(:json){'{"json_class": "Chef::Role"}'}
24
+ describe "#from_json with JSON containing an existing class" do
25
+ let(:json) { '{"json_class": "Chef::Role"}' }
26
+
27
+ it "returns an instance of the class instead of a Hash" do
28
+ expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role
29
+ end
30
+ end
31
+
32
+ describe "#from_json with JSON containing comments" do
33
+ let(:json) { %Q{{\n/* comment */\n// comment 2\n"json_class": "Chef::Role"}} }
34
+
26
35
  it "returns an instance of the class instead of a Hash" do
27
- Chef::JSONCompat.from_json(json).class.should eq Chef::Role
36
+ expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role
37
+ end
38
+ end
39
+
40
+ describe "#parse with JSON containing comments" do
41
+ let(:json) { %Q{{\n/* comment */\n// comment 2\n"json_class": "Chef::Role"}} }
42
+
43
+ it "returns a Hash" do
44
+ expect(Chef::JSONCompat.parse(json).class).to eq Hash
28
45
  end
29
46
  end
30
47
 
31
48
  describe 'with JSON containing "Chef::Sandbox" as a json_class value' do
32
49
  require 'chef/sandbox' # Only needed for this test
33
- let(:json){'{"json_class": "Chef::Sandbox", "arbitrary": "data"}'}
50
+
51
+ let(:json) { '{"json_class": "Chef::Sandbox", "arbitrary": "data"}' }
52
+
34
53
  it "returns a Hash, because Chef::Sandbox is a dummy class" do
35
- Chef::JSONCompat.from_json(json).should eq({"json_class" => "Chef::Sandbox", "arbitrary" => "data"})
54
+ expect(Chef::JSONCompat.from_json(json)).to eq({"json_class" => "Chef::Sandbox", "arbitrary" => "data"})
36
55
  end
37
56
  end
38
57
 
39
- describe "with a file with 300 or less nested entries" do
40
- before(:all) do
41
- @json = IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json'))
42
- @hash = Chef::JSONCompat.from_json(@json)
58
+ describe "when pretty printing an object that defines #to_json" do
59
+ class Foo
60
+ def to_json(*a)
61
+ {'foo' => 1234}.to_json(*a)
62
+ end
63
+ end
64
+
65
+ it "should work" do
66
+ f = Foo.new
67
+ expect(Chef::JSONCompat.to_json_pretty(f)).to eql("{\n \"foo\": 1234\n}\n")
43
68
  end
69
+ end
70
+
71
+ describe "with a file with 300 or less nested entries" do
72
+ let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json')) }
73
+ let(:hash) { Chef::JSONCompat.from_json(json) }
44
74
 
45
75
  describe "when a big json file is loaded" do
46
76
  it "should create a Hash from the file" do
47
- @hash.should be_kind_of(Hash)
77
+ expect(hash).to be_kind_of(Hash)
48
78
  end
79
+
49
80
  it "should has 'test' as a 300th nested value" do
50
- @hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key'].should == 'test'
81
+ expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
51
82
  end
52
83
  end
53
84
  end
85
+
54
86
  describe "with a file with more than 300 nested entries" do
55
- before(:all) do
56
- @json = IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json'))
57
- @hash = Chef::JSONCompat.from_json(@json, {:max_nesting => 301})
58
- end
87
+ let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) }
88
+ let(:hash) { Chef::JSONCompat.from_json(json, {:max_nesting => 301}) }
59
89
 
60
90
  describe "when a big json file is loaded" do
61
91
  it "should create a Hash from the file" do
62
- @hash.should be_kind_of(Hash)
92
+ expect(hash).to be_kind_of(Hash)
63
93
  end
94
+
64
95
  it "should has 'test' as a 301st nested value" do
65
- @hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key'].should == 'test'
96
+ expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
66
97
  end
67
98
  end
68
99
  end
@@ -50,7 +50,7 @@ describe Chef::Knife::ClientDelete do
50
50
  Chef::ApiClient.should_receive(:load).and_return(@client)
51
51
  end
52
52
 
53
- it 'should delete non-validator client if --force is not set' do
53
+ it 'should delete non-validator client if --delete-validators is not set' do
54
54
  @knife.config[:delete_validators] = false
55
55
  @client.should_receive(:destroy).and_return(@client)
56
56
  @knife.should_receive(:msg)
@@ -58,7 +58,7 @@ describe Chef::Knife::ClientDelete do
58
58
  @knife.run
59
59
  end
60
60
 
61
- it 'should delete non-validator client if --force is set' do
61
+ it 'should delete non-validator client if --delete-validators is set' do
62
62
  @knife.config[:delete_validators] = true
63
63
  @client.should_receive(:destroy).and_return(@client)
64
64
  @knife.should_receive(:msg)
@@ -66,13 +66,13 @@ describe Chef::Knife::ClientDelete do
66
66
  @knife.run
67
67
  end
68
68
 
69
- it 'should not delete validator client if --force is not set' do
69
+ it 'should not delete validator client if --delete-validators is not set' do
70
70
  @client.validator(true)
71
71
  @knife.ui.should_receive(:fatal)
72
72
  lambda { @knife.run}.should raise_error(SystemExit)
73
73
  end
74
74
 
75
- it 'should delete validator client if --force is set' do
75
+ it 'should delete validator client if --delete-validators is set' do
76
76
  @knife.config[:delete_validators] = true
77
77
  @client.should_receive(:destroy).and_return(@client)
78
78
  @knife.should_receive(:msg)
@@ -27,16 +27,26 @@ describe Chef::Knife::ClientShow do
27
27
 
28
28
  describe 'run' do
29
29
  it 'should list the client' do
30
- Chef::ApiClient.should_receive(:load).with('adam').and_return(@client_mock)
31
- @knife.should_receive(:format_for_display).with(@client_mock)
30
+ expect(Chef::ApiClient).to receive(:load).with('adam').and_return(@client_mock)
31
+ expect(@knife).to receive(:format_for_display).with(@client_mock)
32
32
  @knife.run
33
33
  end
34
34
 
35
+ it 'should pretty print json' do
36
+ @knife.config[:format] = 'json'
37
+ @stdout = StringIO.new
38
+ allow(@knife.ui).to receive(:stdout).and_return(@stdout)
39
+ fake_client_contents = {"foo"=>"bar", "baz"=>"qux"}
40
+ expect(Chef::ApiClient).to receive(:load).with('adam').and_return(fake_client_contents)
41
+ @knife.run
42
+ expect(@stdout.string).to eql("{\n \"foo\": \"bar\",\n \"baz\": \"qux\"\n}\n")
43
+ end
44
+
35
45
  it 'should print usage and exit when a client name is not provided' do
36
46
  @knife.name_args = []
37
- @knife.should_receive(:show_usage)
38
- @knife.ui.should_receive(:fatal)
39
- lambda { @knife.run }.should raise_error(SystemExit)
47
+ expect(@knife).to receive(:show_usage)
48
+ expect(@knife.ui).to receive(:fatal)
49
+ expect { @knife.run }.to raise_error(SystemExit)
40
50
  end
41
51
  end
42
52
  end