diff options
-rw-r--r-- | cspell.json | 1 | ||||
-rw-r--r-- | lib/chef/knife/core/formatting_options.rb | 49 | ||||
-rw-r--r-- | lib/chef/knife/core/node_presenter.rb | 25 | ||||
-rw-r--r-- | lib/chef/knife/core/status_presenter.rb | 25 | ||||
-rw-r--r-- | lib/chef/knife/node_show.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/search.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/status.rb | 19 | ||||
-rw-r--r-- | lib/chef/policy_builder/policyfile.rb | 2 | ||||
-rw-r--r-- | lib/chef/resource/windows_certificate.rb | 14 | ||||
-rw-r--r-- | spec/data/rubygems.org/latest_specs.4.8.gz | bin | 0 -> 86 bytes | |||
-rw-r--r-- | spec/data/rubygems.org/nonexistent_gem | bin | 0 -> 4 bytes | |||
-rw-r--r-- | spec/data/rubygems.org/sexp_processor | bin | 0 -> 2737 bytes | |||
-rw-r--r-- | spec/data/rubygems.org/sexp_processor-4.15.1.gemspec.rz | bin | 0 -> 519 bytes | |||
-rw-r--r-- | spec/functional/resource/windows_certificate_spec.rb | 588 | ||||
-rw-r--r-- | spec/unit/provider/package/rubygems_spec.rb | 46 | ||||
-rw-r--r-- | tasks/spellcheck.rb | 7 |
16 files changed, 308 insertions, 474 deletions
diff --git a/cspell.json b/cspell.json index 2c34043b30..a55b2bfc40 100644 --- a/cspell.json +++ b/cspell.json @@ -625,7 +625,6 @@ "HHOOK", "HIBYTE", "HICON", - "hidemins", "Hinderliter", "HINSTANCE", "hintname", diff --git a/lib/chef/knife/core/formatting_options.rb b/lib/chef/knife/core/formatting_options.rb new file mode 100644 index 0000000000..cdee2c5989 --- /dev/null +++ b/lib/chef/knife/core/formatting_options.rb @@ -0,0 +1,49 @@ +# +# Author:: Nicolas DUPEUX (<nicolas.dupeux@arkea.com>) +# Copyright:: Copyright (c) Chef Software Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class Chef + class Knife + module Core + + # This module may be included into a knife subcommand class to automatically + # add configuration options used by the StatusPresenter and NodePresenter. + module FormattingOptions + # @private + # Would prefer to do this in a rational way, but can't be done b/c of + # Mixlib::CLI's design :( + def self.included(includer) + includer.class_eval do + option :medium_output, + short: "-m", + long: "--medium", + boolean: true, + default: false, + description: "Include normal attributes in the output" + + option :long_output, + short: "-l", + long: "--long", + boolean: true, + default: false, + description: "Include all attributes in the output" + end + end + end + end + end +end diff --git a/lib/chef/knife/core/node_presenter.rb b/lib/chef/knife/core/node_presenter.rb index 6690bc1075..8c948cf76c 100644 --- a/lib/chef/knife/core/node_presenter.rb +++ b/lib/chef/knife/core/node_presenter.rb @@ -23,31 +23,6 @@ class Chef class Knife module Core - # This module may be included into a knife subcommand class to automatically - # add configuration options used by the NodePresenter - module NodeFormattingOptions - # @private - # Would prefer to do this in a rational way, but can't be done b/c of - # Mixlib::CLI's design :( - def self.included(includer) - includer.class_eval do - option :medium_output, - short: "-m", - long: "--medium", - boolean: true, - default: false, - description: "Include normal attributes in the output" - - option :long_output, - short: "-l", - long: "--long", - boolean: true, - default: false, - description: "Include all attributes in the output" - end - end - end - # A customized presenter for Chef::Node objects. Supports variable-length # output formats for displaying node data class NodePresenter < GenericPresenter diff --git a/lib/chef/knife/core/status_presenter.rb b/lib/chef/knife/core/status_presenter.rb index 9a4ea76508..215e79f33b 100644 --- a/lib/chef/knife/core/status_presenter.rb +++ b/lib/chef/knife/core/status_presenter.rb @@ -23,31 +23,6 @@ class Chef class Knife module Core - # This module may be included into a knife subcommand class to automatically - # add configuration options used by the StatusPresenter - module StatusFormattingOptions - # @private - # Would prefer to do this in a rational way, but can't be done b/c of - # Mixlib::CLI's design :( - def self.included(includer) - includer.class_eval do - option :medium_output, - short: "-m", - long: "--medium", - boolean: true, - default: false, - description: "Include normal attributes in the output" - - option :long_output, - short: "-l", - long: "--long", - boolean: true, - default: false, - description: "Include all attributes in the output" - end - end - end - # A customized presenter for Chef::Node objects. Supports variable-length # output formats for displaying node data class StatusPresenter < GenericPresenter diff --git a/lib/chef/knife/node_show.rb b/lib/chef/knife/node_show.rb index 8ef06d8938..173348dc41 100644 --- a/lib/chef/knife/node_show.rb +++ b/lib/chef/knife/node_show.rb @@ -18,13 +18,14 @@ require_relative "../knife" require_relative "core/node_presenter" +require_relative "core/formatting_options" require "chef-utils/dist" unless defined?(ChefUtils::Dist) class Chef class Knife class NodeShow < Knife - include Knife::Core::NodeFormattingOptions + include Knife::Core::FormattingOptions include Knife::Core::MultiAttributeReturnOption deps do diff --git a/lib/chef/knife/search.rb b/lib/chef/knife/search.rb index 2feb8e6729..620cfb971d 100644 --- a/lib/chef/knife/search.rb +++ b/lib/chef/knife/search.rb @@ -18,6 +18,7 @@ require_relative "../knife" require_relative "core/node_presenter" +require_relative "core/formatting_options" class Chef class Knife @@ -32,7 +33,7 @@ class Chef require_relative "../search/query" end - include Knife::Core::NodeFormattingOptions + include Knife::Core::FormattingOptions banner "knife search INDEX QUERY (options)" diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb index ea5dffdf6c..b70c61773a 100644 --- a/lib/chef/knife/status.rb +++ b/lib/chef/knife/status.rb @@ -18,13 +18,13 @@ require_relative "../knife" require_relative "core/status_presenter" -require_relative "core/node_presenter" +require_relative "core/formatting_options" require "chef-utils/dist" unless defined?(ChefUtils::Dist) class Chef class Knife class Status < Knife - include Knife::Core::NodeFormattingOptions + include Knife::Core::FormattingOptions deps do require_relative "../search/query" @@ -68,11 +68,11 @@ class Chef append_to_query("chef_environment:#{config[:environment]}") if config[:environment] if config[:hide_by_mins] - hidemins = config[:hide_by_mins].to_i + hide_by_mins = config[:hide_by_mins].to_i time = Time.now.to_i # AND NOT is not valid lucene syntax, so don't use append_to_query @query << " " unless @query.empty? - @query << "NOT ohai_time:[#{(time - hidemins * 60)} TO #{time}]" + @query << "NOT ohai_time:[#{(time - hide_by_mins * 60)} TO #{time}]" end @query = @query.empty? ? "*:*" : @query @@ -84,13 +84,10 @@ class Chef all_nodes << node end - output(all_nodes.sort do |n1, n2| - if config[:sort_reverse] || config[:sort_status_reverse] - (n2["ohai_time"] || 0) <=> (n1["ohai_time"] || 0) - else - (n1["ohai_time"] || 0) <=> (n2["ohai_time"] || 0) - end - end) + all_nodes.sort_by! {|n| n["ohai_time"] || 0 } + all_nodes.reverse! if config[:sort_reverse] || config[:sort_status_reverse] + + output(all_nodes) end end diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb index bac015be42..35282bf915 100644 --- a/lib/chef/policy_builder/policyfile.rb +++ b/lib/chef/policy_builder/policyfile.rb @@ -475,7 +475,7 @@ class Chef end # @api private - # Fetches the CookbookVersion object for the given name and identifer + # Fetches the CookbookVersion object for the given name and identifier # specified in the lock_data. # TODO: This only implements Chef 11 compatibility mode, which means that # cookbooks are fetched by the "dotted_decimal_identifier": a diff --git a/lib/chef/resource/windows_certificate.rb b/lib/chef/resource/windows_certificate.rb index 930c5ae6a4..5800fe0f45 100644 --- a/lib/chef/resource/windows_certificate.rb +++ b/lib/chef/resource/windows_certificate.rb @@ -69,7 +69,7 @@ class Chef description: "The password to access the source if it is a pfx file." property :private_key_acl, Array, - description: "An array of 'domain\account' entries to be granted read-only access to the certificate's private key. Not idempotent." + description: "An array of 'domain\\account' entries to be granted read-only access to the certificate's private key. Not idempotent." property :store_name, String, description: "The certificate store to manipulate.", @@ -309,11 +309,7 @@ class Chef # @raise [OpenSSL::PKCS12::PKCS12Error] When incorrect password is provided for PFX certificate # def fetch_cert_object(ext) - contents = if binary_cert? - ::File.binread(new_resource.source) - else - ::File.read(new_resource.source) - end + contents = ::File.binread(new_resource.source) case ext when ".pfx" @@ -330,12 +326,6 @@ class Chef end end - # @return [Boolean] Whether the certificate file is binary encoded or not - # - def binary_cert? - shell_out!("file -b --mime-encoding #{new_resource.source}").stdout.strip == "binary" - end - # Imports the certificate object into cert store # # @param cert_objs [OpenSSL::X509::Certificate] Object containing certificate's attributes diff --git a/spec/data/rubygems.org/latest_specs.4.8.gz b/spec/data/rubygems.org/latest_specs.4.8.gz Binary files differnew file mode 100644 index 0000000000..ab6a175f32 --- /dev/null +++ b/spec/data/rubygems.org/latest_specs.4.8.gz diff --git a/spec/data/rubygems.org/nonexistent_gem b/spec/data/rubygems.org/nonexistent_gem Binary files differnew file mode 100644 index 0000000000..0ba94359df --- /dev/null +++ b/spec/data/rubygems.org/nonexistent_gem diff --git a/spec/data/rubygems.org/sexp_processor b/spec/data/rubygems.org/sexp_processor Binary files differnew file mode 100644 index 0000000000..37c6e97769 --- /dev/null +++ b/spec/data/rubygems.org/sexp_processor diff --git a/spec/data/rubygems.org/sexp_processor-4.15.1.gemspec.rz b/spec/data/rubygems.org/sexp_processor-4.15.1.gemspec.rz Binary files differnew file mode 100644 index 0000000000..38840f2682 --- /dev/null +++ b/spec/data/rubygems.org/sexp_processor-4.15.1.gemspec.rz diff --git a/spec/functional/resource/windows_certificate_spec.rb b/spec/functional/resource/windows_certificate_spec.rb index 20d444dd59..b5d0484e0c 100644 --- a/spec/functional/resource/windows_certificate_spec.rb +++ b/spec/functional/resource/windows_certificate_spec.rb @@ -19,478 +19,298 @@ require "spec_helper" require "chef/mixin/powershell_exec" require "chef/resource/windows_certificate" -module WindowsCertificateHelper +describe Chef::Resource::WindowsCertificate, :windows_only do include Chef::Mixin::PowershellExec - def create_store(store) - path = "Cert:\\LocalMachine\\" + store - command = <<~EOC - New-Item -Path #{path} + def create_store + powershell_exec <<~EOC + New-Item -Path Cert:\\LocalMachine\\#{store} EOC - powershell_exec(command) end - def cleanup(store) - path = "Cert:\\LocalMachine\\" + store - command = <<~EOC - Remove-Item -Path #{path} -Recurse + def delete_store + powershell_exec <<~EOC + Remove-Item -Path Cert:\\LocalMachine\\#{store} -Recurse EOC - powershell_exec(command) end - def no_of_certificates - path = "Cert:\\LocalMachine\\" + store - # Seems weird that we have to call dir twice right? - # The powershell pki module cache the last dir in module session state - # Issuing dir with a different arg (-Force) seems to refresh that state. - command = <<~EOC - dir #{path} -Force | Out-Null - (dir #{path} | measure).Count + def certificate_count + powershell_exec(<<~EOC).result.to_i + (Get-ChildItem -Force -Path Cert:\\LocalMachine\\#{store} | measure).Count EOC - powershell_exec(command).result.to_i end -end -describe Chef::Resource::WindowsCertificate, :windows_only do - include WindowsCertificateHelper - - let(:stdout) { StringIO.new } - let(:username) { "ChefFunctionalTest" } - let(:node) { Chef::Node.new } - let(:events) { Chef::EventDispatch::Dispatcher.new } - let(:run_context) { Chef::RunContext.new(node, {}, events) } - let(:new_resource) { Chef::Resource::WindowsCertificate.new(username, run_context) } let(:password) { "P@ssw0rd!" } let(:store) { "Chef-Functional-Test" } - let(:certificate_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "windows_certificates")) } - let(:cer_path) { File.join(certificate_path, "test.cer") } - let(:base64_path) { File.join(certificate_path, "base64_test.cer") } - let(:pem_path) { File.join(certificate_path, "test.pem") } - let(:p7b_path) { File.join(certificate_path, "test.p7b") } - let(:pfx_path) { File.join(certificate_path, "test.pfx") } - let(:out_path) { File.join(certificate_path, "testout.pem") } + let(:cer_path) { File.join(CHEF_SPEC_DATA, "windows_certificates", "test.cer") } + let(:base64_path) { File.join(CHEF_SPEC_DATA, "windows_certificates", "base64_test.cer") } + let(:pem_path) { File.join(CHEF_SPEC_DATA, "windows_certificates", "test.pem") } + let(:p7b_path) { File.join(CHEF_SPEC_DATA, "windows_certificates", "test.p7b") } + let(:pfx_path) { File.join(CHEF_SPEC_DATA, "windows_certificates", "test.pfx") } let(:tests_thumbprint) { "e45a4a7ff731e143cf20b8bfb9c7c4edd5238bb3" } - let(:other_cer_path) { File.join(certificate_path, "othertest.cer") } + let(:other_cer_path) { File.join(CHEF_SPEC_DATA, "windows_certificates", "othertest.cer") } let(:others_thumbprint) { "6eae1deefaf59daf1a97c9ceeff39c98b3da38cb" } let(:p7b_thumbprint) { "f867e25b928061318ed2c36ca517681774b06260" } let(:p7b_nested_thumbprint) { "dc395eae6be5b69951b8b6e1090cfc33df30d2cd" } + let(:resource) do + run_context = Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new) + Chef::Resource::WindowsCertificate.new("ChefFunctionalTest", run_context).tap do |r| + r.store_name = store + end + end + before do - opts = { store_name: store } - key = :store_name - to_be = ["TRUSTEDPUBLISHER", "TrustedPublisher", "CLIENTAUTHISSUER", - "REMOTE DESKTOP", "ROOT", "TRUSTEDDEVICES", "WEBHOSTING", - "CA", "AUTHROOT", "TRUSTEDPEOPLE", "MY", "SMARTCARDROOT", "TRUST", - "DISALLOWED"] - - # Byepassing the validation so that we may create a custom store + # Bypass validation of the store name so we can use a fake test store. allow_any_instance_of(Chef::Mixin::ParamsValidate) .to receive(:_pv_equal_to) - .with(opts, key, to_be) + .with({ store_name: store }, :store_name, anything) .and_return(true) - # Creating a custom store for the testing - create_store(store) + create_store + end + + after { delete_store } - allow(Chef::Log).to receive(:info) do |msg| - stdout.puts(msg) + describe "action: create" do + it "starts with no certificates" do + expect(certificate_count).to eq(0) end - end - after { cleanup(store) } + it "can add a certificate idempotently" do + resource.source = cer_path + resource.run_action(:create) - subject(:win_certificate) do - new_resource.store_name = store - new_resource - end + expect(certificate_count).to eq(1) + expect(resource).to be_updated_by_last_action - it "Initially there are no certificates" do - expect(no_of_certificates).to eq(0) - end + # Adding the cert again should have no effect + resource.run_action(:create) + expect(certificate_count).to eq(1) + expect(resource).not_to be_updated_by_last_action - describe "action :create" do - before do - win_certificate.source = cer_path - win_certificate.run_action(:create) - end + # Adding the cert again with a different format should have no effect + resource.source = pem_path + resource.run_action(:create) + expect(certificate_count).to eq(1) + expect(resource).not_to be_updated_by_last_action - context "Adding a certificate" do - it "Imports certificate into store" do - expect(no_of_certificates).to eq(1) - end + # Adding another cert should work correctly + resource.source = other_cer_path + resource.run_action(:create) - it "Converges while addition" do - expect(win_certificate).to be_updated_by_last_action - end + expect(certificate_count).to eq(2) + expect(resource).to be_updated_by_last_action end - context "Again adding the same certificate" do - before do - win_certificate.run_action(:create) - end - it "Does not imports certificate into store" do - expect(no_of_certificates).to eq(1) - end - it "Idempotent: Does not converge while addition" do - expect(no_of_certificates).to eq(1) - expect(win_certificate).not_to be_updated_by_last_action - end - end + it "can add a base64 encoded certificate idempotently" do + resource.source = base64_path + resource.run_action(:create) - context "Again adding the same certificate of other format" do - before do - win_certificate.source = pem_path - win_certificate.run_action(:create) - end - it "Does not imports certificate into store" do - expect(no_of_certificates).to eq(1) - end - it "Idempotent: Does not converge while addition" do - expect(no_of_certificates).to eq(1) - expect(win_certificate).not_to be_updated_by_last_action - end - end + expect(certificate_count).to eq(1) - context "Adding another certificate" do - before do - win_certificate.source = other_cer_path - win_certificate.run_action(:create) - end - it "Imports certificate into store" do - expect(no_of_certificates).to eq(2) - end - it "Converges while addition" do - expect(no_of_certificates).to eq(2) - expect(win_certificate).to be_updated_by_last_action - end + resource.run_action(:create) + expect(certificate_count).to eq(1) + expect(resource).not_to be_updated_by_last_action end - end - describe "Works for various formats" do - context "Adds CER" do - before do - win_certificate.source = cer_path - win_certificate.run_action(:create) - end - it "Imports certificate into store" do - expect(no_of_certificates).to eq(1) - end - it "Idempotent: Does not converge while adding again" do - win_certificate.run_action(:create) - expect(no_of_certificates).to eq(1) - expect(win_certificate).not_to be_updated_by_last_action - end - end + it "can add a PEM certificate idempotently" do + resource.source = pem_path + resource.run_action(:create) - context "Adds Base64 Encoded CER" do - before do - win_certificate.source = base64_path - win_certificate.run_action(:create) - end - it "Imports certificate into store" do - expect(no_of_certificates).to eq(1) - end - it "Idempotent: Does not converge while adding again" do - win_certificate.run_action(:create) - expect(no_of_certificates).to eq(1) - expect(win_certificate).not_to be_updated_by_last_action - end + expect(certificate_count).to eq(1) + + resource.run_action(:create) + + expect(certificate_count).to eq(1) + expect(resource).not_to be_updated_by_last_action end - context "Adds PEM" do - before do - win_certificate.source = pem_path - win_certificate.run_action(:create) - end - it "Imports certificate into store" do - expect(no_of_certificates).to eq(1) - end - it "Idempotent: Does not converge while adding again" do - win_certificate.run_action(:create) - expect(no_of_certificates).to eq(1) - expect(win_certificate).not_to be_updated_by_last_action - end + it "can add a P7B certificate idempotently" do + resource.source = p7b_path + resource.run_action(:create) + + # A P7B cert includes nested certs + expect(certificate_count).to eq(3) + + resource.run_action(:create) + + expect(resource).not_to be_updated_by_last_action + expect(certificate_count).to eq(3) end - context "Adds P7B" do - before do - win_certificate.source = p7b_path - win_certificate.run_action(:create) - end - it "Imports certificate into store" do - expect(no_of_certificates).not_to eq(0) - end - it "Idempotent: Does not converge while adding again" do - win_certificate.run_action(:create) - expect(win_certificate).not_to be_updated_by_last_action - end - it "Nested certificates are also imported" do - expect(no_of_certificates).to eq(3) - end + it "can add a PFX certificate idempotently with a valid password" do + resource.source = pfx_path + resource.pfx_password = password + resource.run_action(:create) + + expect(certificate_count).to eq(1) + + resource.run_action(:create) + expect(certificate_count).to eq(1) + expect(resource).not_to be_updated_by_last_action end - context "Adds PFX" do - context "With valid password" do - before do - win_certificate.source = pfx_path - win_certificate.pfx_password = password - win_certificate.run_action(:create) - end - it "Imports certificate into store" do - expect(no_of_certificates).to eq(1) - end - it "Idempotent: Does not converge while adding again" do - win_certificate.run_action(:create) - expect(no_of_certificates).to eq(1) - expect(win_certificate).not_to be_updated_by_last_action - end - end + it "raises an error when adding a PFX certificate with an invalid password" do + resource.source = pfx_path + resource.pfx_password = "Invalid password" - context "With Invalid password" do - before do - win_certificate.source = pfx_path - win_certificate.pfx_password = "Invalid password" - end - it "Raises an error" do - expect { win_certificate.run_action(:create) }.to raise_error(OpenSSL::PKCS12::PKCS12Error) - end - end + expect { resource.run_action(:create) }.to raise_error(OpenSSL::PKCS12::PKCS12Error) end end describe "action: verify" do - context "When a certificate is not present" do - before do - win_certificate.source = tests_thumbprint - win_certificate.run_action(:verify) - end - it "Initial check if certificate is not present" do - expect(no_of_certificates).to eq(0) - end - it "Displays correct message" do - expect(stdout.string.strip).to eq("Certificate not found") - end - it "Does not converge while verifying" do - expect(win_certificate).not_to be_updated_by_last_action - end + it "fails with no certificates in the store" do + expect(Chef::Log).to receive(:info).with("Certificate not found") + + resource.source = tests_thumbprint + resource.run_action(:verify) + + expect(resource).not_to be_updated_by_last_action end - context "When a certificate is present" do + context "with a certificate in the store" do before do - win_certificate.source = cer_path - win_certificate.run_action(:create) + resource.source = cer_path + resource.run_action(:create) end - context "For a valid thumbprint" do - before do - win_certificate.source = tests_thumbprint - win_certificate.run_action(:verify) - end - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(1) - end - it "Displays correct message" do - expect(stdout.string.strip).to eq("Certificate is valid") - end - it "Does not converge while verifying" do - expect(win_certificate).not_to be_updated_by_last_action - end + it "succeeds with a valid thumbprint" do + expect(Chef::Log).to receive(:info).with("Certificate is valid") + + resource.source = tests_thumbprint + resource.run_action(:verify) + + expect(resource).not_to be_updated_by_last_action end - context "For an invalid thumbprint" do - before do - win_certificate.source = others_thumbprint - win_certificate.run_action(:verify) - end - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(1) - end - it "Displays correct message" do - expect(stdout.string.strip).to eq("Certificate not found") - end - it "Does not converge while verifying" do - expect(win_certificate).not_to be_updated_by_last_action - end + it "fails with an invalid thumbprint" do + expect(Chef::Log).to receive(:info).with("Certificate not found") + + resource.source = others_thumbprint + resource.run_action(:verify) + + expect(resource).not_to be_updated_by_last_action end end - context "When multiple certificates are present" do + context "with a nested certificate in the store" do before do - win_certificate.source = p7b_path - win_certificate.run_action(:create) + resource.source = p7b_path + resource.run_action(:create) end - context "With main certificate's thumbprint" do - before do - win_certificate.source = p7b_thumbprint - win_certificate.run_action(:verify) - end - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(3) - end - it "Displays correct message" do - expect(stdout.string.strip).to eq("Certificate is valid") - end - it "Does not converge while verifying" do - expect(win_certificate).not_to be_updated_by_last_action - end + it "succeeds with the main certificate's thumbprint" do + expect(Chef::Log).to receive(:info).with("Certificate is valid") + + resource.source = p7b_thumbprint + resource.run_action(:verify) + + expect(resource).not_to be_updated_by_last_action end - context "With nested certificate's thumbprint" do - before do - win_certificate.source = p7b_nested_thumbprint - win_certificate.run_action(:verify) - end - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(3) - end - it "Displays correct message" do - expect(stdout.string.strip).to eq("Certificate is valid") - end - it "Does not converge while verifying" do - expect(win_certificate).not_to be_updated_by_last_action - end + it "succeeds with the nested certificate's thumbprint" do + expect(Chef::Log).to receive(:info).with("Certificate is valid") + + resource.source = p7b_nested_thumbprint + resource.run_action(:verify) + + expect(resource).not_to be_updated_by_last_action end - context "For an invalid thumbprint" do - before do - win_certificate.source = others_thumbprint - win_certificate.run_action(:verify) - end - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(3) - end - it "Displays correct message" do - expect(stdout.string.strip).to eq("Certificate not found") - end - it "Does not converge while verifying" do - expect(win_certificate).not_to be_updated_by_last_action - end + it "fails with an invalid thumbprint" do + expect(Chef::Log).to receive(:info).with("Certificate not found") + + resource.source = others_thumbprint + resource.run_action(:verify) + + expect(resource).not_to be_updated_by_last_action end end end describe "action: fetch" do - context "When a certificate is not present" do - before do - win_certificate.source = tests_thumbprint - win_certificate.run_action(:fetch) - end - it "Initial check if certificate is not present" do - expect(no_of_certificates).to eq(0) - end - it "Does not show any content" do - expect(stdout.string.strip).to be_empty - end - it "Does not converge while fetching" do - expect(win_certificate).not_to be_updated_by_last_action - end + it "does nothing with no certificates in the store" do + expect(Chef::Log).not_to receive(:info) + + resource.source = tests_thumbprint + resource.run_action(:fetch) + + expect(resource).not_to be_updated_by_last_action end - context "When a certificate is present" do + context "with a certificate in the store" do before do - win_certificate.source = cer_path - win_certificate.run_action(:create) + resource.source = cer_path + resource.run_action(:create) end - after do - if File.exist?(out_path) - File.delete(out_path) - end - end + it "succeeds with a valid thumbprint" do + resource.source = tests_thumbprint - context "For a valid thumbprint" do - before do - win_certificate.source = tests_thumbprint - win_certificate.cert_path = out_path - win_certificate.run_action(:fetch) - end - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(1) - end - it "Stores Certificate content at given path" do - expect(File.exist?(out_path)).to be_truthy - end - it "Does not converge while fetching" do - expect(win_certificate).not_to be_updated_by_last_action + Dir.mktmpdir do |dir| + path = File.join(dir, "test.pem") + expect(Chef::Log).to receive(:info).with("Certificate export in #{path}") + + resource.cert_path = path + resource.run_action(:fetch) + + expect(File.exist?(path)).to be_truthy end + + expect(resource).not_to be_updated_by_last_action end - context "For an invalid thumbprint" do - before do - win_certificate.source = others_thumbprint - win_certificate.cert_path = out_path - win_certificate.run_action(:fetch) - end - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(1) - end - it "Does not show any content" do - expect(stdout.string.strip).to be_empty - end - it "Does not store certificate content at given path" do - expect(File.exist?(out_path)).to be_falsy - end - it "Does not converge while fetching" do - expect(win_certificate).not_to be_updated_by_last_action + it "fails with an invalid thumbprint" do + expect(Chef::Log).not_to receive(:info) + + resource.source = others_thumbprint + + Dir.mktmpdir do |dir| + path = File.join(dir, "test.pem") + + resource.cert_path = path + resource.run_action(:fetch) + + expect(File.exist?(path)).to be_falsy end + + expect(resource).not_to be_updated_by_last_action end end end describe "action: delete" do - context "When a certificate is not present" do - before do - win_certificate.source = tests_thumbprint - win_certificate.run_action(:delete) - end - it "Initial check if certificate is not present" do - expect(no_of_certificates).to eq(0) - end - it "Does not delete any certificate" do - expect(stdout.string.strip).to be_empty - end + it "does nothing when attempting to delete a certificate that doesn't exist" do + expect(Chef::Log).to receive(:debug).with("Certificate not found") + + resource.source = tests_thumbprint + resource.run_action(:delete) end - context "When a certificate is present" do - before do - win_certificate.source = cer_path - win_certificate.run_action(:create) - end - before { win_certificate.source = tests_thumbprint } - it "Initial check if certificate is present" do - expect(no_of_certificates).to eq(1) - end - it "Deletes the certificate" do - win_certificate.run_action(:delete) - expect(no_of_certificates).to eq(0) - end - it "Converges while deleting" do - win_certificate.run_action(:delete) - expect(win_certificate).to be_updated_by_last_action - end - it "Idempotent: Does not converge while deleting again" do - win_certificate.run_action(:delete) - win_certificate.run_action(:delete) - expect(no_of_certificates).to eq(0) - expect(win_certificate).not_to be_updated_by_last_action - end - it "Deletes the valid certificate" do - # Add another certificate" - win_certificate.source = other_cer_path - win_certificate.run_action(:create) - expect(no_of_certificates).to eq(2) - - # Delete previously added certificate - win_certificate.source = tests_thumbprint - win_certificate.run_action(:delete) - expect(no_of_certificates).to eq(1) - - # Verify another certificate still exists - win_certificate.source = others_thumbprint - win_certificate.run_action(:verify) - expect(stdout.string.strip).to eq("Certificate is valid") - end + it "deletes an existing certificate while leaving other certificates alone" do + # Add two certs + resource.source = cer_path + resource.run_action(:create) + + resource.source = other_cer_path + resource.run_action(:create) + + # Delete the first cert added + resource.source = tests_thumbprint + resource.run_action(:delete) + + expect(certificate_count).to eq(1) + expect(resource).to be_updated_by_last_action + + resource.run_action(:delete) + expect(certificate_count).to eq(1) + expect(resource).not_to be_updated_by_last_action + + # Verify second cert still exists + expect(Chef::Log).to receive(:info).with("Certificate is valid") + resource.source = others_thumbprint + resource.run_action(:verify) end end end diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb index 6f31c231ce..5c947cf275 100644 --- a/spec/unit/provider/package/rubygems_spec.rb +++ b/spec/unit/provider/package/rubygems_spec.rb @@ -50,6 +50,8 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do before do @gem_env = Chef::Provider::Package::Rubygems::CurrentGemEnvironment.new allow(@gem_env).to receive(:logger).and_return(logger) + + WebMock.disable_net_connect! end it "determines the gem paths from the in memory rubygems" do @@ -113,28 +115,55 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do end it "finds a matching gem candidate version on rubygems 2.0.0+" do - dep = Gem::Dependency.new("rspec", ">= 0") + stub_request(:head, "https://rubygems.org/api/v1/dependencies") + + stub_request(:get, "https://rubygems.org/api/v1/dependencies?gems=sexp_processor") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "sexp_processor"))) + + stub_request(:get, "https://rubygems.org/quick/Marshal.4.8/sexp_processor-4.15.1.gemspec.rz") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "sexp_processor-4.15.1.gemspec.rz"))) + + dep = Gem::Dependency.new("sexp_processor", ">= 0") expect(@gem_env.candidate_version_from_remote(dep)).to be_kind_of(Gem::Version) end it "gives the candidate version as nil if none is found" do - dep = Gem::Dependency.new("lksdjflksdjflsdkfj", ">= 0") + stub_request(:head, "https://rubygems.org/api/v1/dependencies") + + stub_request(:get, "https://rubygems.org/api/v1/dependencies?gems=nonexistent_gem") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "nonexistent_gem"))) + + dep = Gem::Dependency.new("nonexistent_gem", ">= 0") expect(@gem_env.candidate_version_from_remote(dep)).to be_nil end it "finds a matching gem from a specific gemserver when explicit sources are given (to a server that doesn't respond to api requests)" do - dep = Gem::Dependency.new("rspec", ">= 0") - expect(@gem_env.candidate_version_from_remote(dep, "https://rubygems.org")).to be_kind_of(Gem::Version) + stub_request(:head, "https://rubygems2.org/api/v1/dependencies") + + stub_request(:get, "https://rubygems2.org/api/v1/dependencies?gems=sexp_processor") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "sexp_processor"))) + + stub_request(:get, "https://rubygems2.org/quick/Marshal.4.8/sexp_processor-4.15.1.gemspec.rz") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "sexp_processor-4.15.1.gemspec.rz"))) + + dep = Gem::Dependency.new("sexp_processor", ">= 0") + expect(@gem_env.candidate_version_from_remote(dep, "https://rubygems2.org")).to be_kind_of(Gem::Version) end end context "old rubygems caching behavior" do before do Chef::Config[:rubygems_cache_enabled] = true + + stub_request(:get, "https://rubygems.org/latest_specs.4.8.gz") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "latest_specs.4.8.gz"))) end it "finds a matching gem candidate version on rubygems 2.0.0+" do - dep = Gem::Dependency.new("rspec", ">= 0") + stub_request(:get, "https://rubygems.org/quick/Marshal.4.8/sexp_processor-4.15.1.gemspec.rz") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "sexp_processor-4.15.1.gemspec.rz"))) + + dep = Gem::Dependency.new("sexp_processor", ">= 0") expect(@gem_env.candidate_version_from_remote(dep)).to be_kind_of(Gem::Version) end @@ -144,8 +173,11 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do end it "finds a matching gem from a specific gemserver when explicit sources are given" do - dep = Gem::Dependency.new("rspec", ">= 0") - expect(@gem_env.candidate_version_from_remote(dep, "http://production.cf.rubygems.org")).to be_kind_of(Gem::Version) + stub_request(:get, "https://rubygems.org/quick/Marshal.4.8/sexp_processor-4.15.1.gemspec.rz") + .to_return(status: 200, body: File.binread(File.join(CHEF_SPEC_DATA, "rubygems.org", "sexp_processor-4.15.1.gemspec.rz"))) + + dep = Gem::Dependency.new("sexp_processor", ">= 0") + expect(@gem_env.candidate_version_from_remote(dep, "http://rubygems2.org")).to be_kind_of(Gem::Version) end end diff --git a/tasks/spellcheck.rb b/tasks/spellcheck.rb index 77b450e5d3..0eb8924a81 100644 --- a/tasks/spellcheck.rb +++ b/tasks/spellcheck.rb @@ -17,12 +17,7 @@ namespace :spellcheck do task run: :prereqs do - sh 'cspell "**/*"' - end - - desc "List the unique unrecognized words in the project." - task unknown_words: :prereqs do - sh 'cspell "**/*" --wordsOnly --no-summary | sort | uniq' + sh 'cspell lint --no-progress "**/*"' end task prereqs: %i{cspell_check config_check fetch_common} |