summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2017-09-25 21:33:52 -0700
committerTim Smith <tsmith@chef.io>2017-09-28 11:04:54 -0700
commit4df19b0ac8a403c127986e4f6f5e739b8930eb7c (patch)
tree02ece044229aefd4f76ec3dd4901acb7f9b0d3f3
parented3750c1d9f8a677b891c59203e828cbfccc345e (diff)
downloadchef-4df19b0ac8a403c127986e4f6f5e739b8930eb7c.tar.gz
Use apt-like gpg key management to avoid notifications
Download the key to the cache Grab the key's fingerprint Check to see if that fingerprint is in the RPM database Add it if it's not Signed-off-by: Tim Smith <tsmith@chef.io>
-rw-r--r--lib/chef/provider/zypper_repository.rb85
-rw-r--r--spec/unit/provider/zypper_repository_spec.rb62
2 files changed, 142 insertions, 5 deletions
diff --git a/lib/chef/provider/zypper_repository.rb b/lib/chef/provider/zypper_repository.rb
index 14d592debe..a1a31d5bea 100644
--- a/lib/chef/provider/zypper_repository.rb
+++ b/lib/chef/provider/zypper_repository.rb
@@ -19,6 +19,7 @@
require "chef/resource"
require "chef/dsl/declare_resource"
require "chef/provider/noop"
+require "chef/mixin/shell_out"
require "shellwords"
class Chef
@@ -31,10 +32,9 @@ class Chef
action :create do
if new_resource.gpgautoimportkeys
- declare_resource(:execute, "import gpg key from #{new_resource.gpgkey}") do
- command "/bin/rpm --import #{new_resource.gpgkey}"
- action :nothing
- end
+ install_gpg_key(new_resource.gpgkey)
+ else
+ Chef::Log.debug("'gpgautoimportkeys' property is set to false. Skipping key import.")
end
declare_resource(:template, "/etc/zypp/repos.d/#{escaped_repo_name}.repo") do
@@ -47,7 +47,6 @@ class Chef
sensitive new_resource.sensitive
variables(config: new_resource)
mode new_resource.mode
- notifies :run, "execute[import gpg key from #{new_resource.gpgkey}]", :before if new_resource.gpgautoimportkeys
notifies :refresh, new_resource, :immediately if new_resource.refresh_cache
end
end
@@ -74,11 +73,87 @@ class Chef
end
# determine if a template file is available in the current run
+ # @param [String] path the path to the template file
+ #
# @return [Boolean] template file exists or doesn't
def template_available?(path)
!path.nil? && run_context.has_template_in_cookbook?(new_resource.cookbook_name, path)
end
+ # determine if a cookbook file is available in the run
+ # @param [String] path the path to the template file
+ #
+ # @return [Boolean] cookbook file exists or doesn't
+ def has_cookbook_file?(fn)
+ run_context.has_cookbook_file_in_cookbook?(cookbook_name, fn)
+ end
+
+ # Given the provided key URI determine what kind of chef resource we need
+ # to fetch the key
+ # @param [String] uri the uri of the gpg key (local path or http URL)
+ #
+ # @raise [Chef::Exceptions::FileNotFound] Key isn't remote or found in the current run
+ #
+ # @return [Symbol] :remote_file or :cookbook_file
+ def key_type(uri)
+ if uri.start_with?("http")
+ Chef::Log.debug("Will use :remote_file resource to cache the gpg key locally")
+ :remote_file
+ elsif has_cookbook_file?(key)
+ Chef::Log.debug("Will use :cookbook_file resource to cache the gpg key locally")
+ :cookbook_file
+ else
+ raise Chef::Exceptions::FileNotFound, "Cannot determine location of gpgkey. Must start with 'http' or be a file managed by Chef."
+ end
+ end
+
+ # is the provided key already installed
+ # @param [String] key_path the path to the key on the local filesystem
+ #
+ # @return [boolean] is the key already known by rpm
+ def key_installed?(key_path)
+ so = shell_out("rpm -qa gpg-pubkey*").run_command
+ # expected output & match: http://rubular.com/r/RdF7EcXEtb
+ status = /gpg-pubkey-#{key_fingerprint(key_path)}/.match(so.stdout)
+ Chef::Log.debug("GPG key at #{key_path} is known by rpm? #{status ? "true" : "false"}")
+ status
+ end
+
+ # extract the gpg key fingerprint from a local file
+ # @param [String] key_path the path to the key on the local filesystem
+ #
+ # @return [String] the fingerprint of the key
+ def key_fingerprint(key_path)
+ so = shell_out("gpg --with-fingerprint #{key_path}").run_command
+ # expected output and match: http://rubular.com/r/BpfMjxySQM
+ fingerprint = /pub\s*\S*\/(\S*)/.match(so.stdout)[1].downcase
+ Chef::Log.debug("GPG fingerprint of key at #{key_path} is #{fingerprint}")
+ fingerprint
+ end
+
+ # install the provided gpg key
+ # @param [String] uri the uri of the local or remote gpg key
+ def install_gpg_key(uri)
+ unless uri
+ Chef::Log.debug("'gpgkey' property not provided or set to nil. Skipping key import.")
+ return
+ end
+
+ cached_keyfile = ::File.join(Chef::Config[:file_cache_path], uri.split("/")[-1])
+
+ declare_resource(key_type(new_resource.gpgkey), cached_keyfile) do
+ source uri
+ mode "0644"
+ sensitive new_resource.sensitive
+ action :create
+ end
+
+ declare_resource(:execute, "import gpg key from #{new_resource.gpgkey}") do
+ command "/bin/rpm --import #{new_resource.gpgkey}"
+ not_if { key_installed?(cached_keyfile) }
+ action :run
+ end
+ end
end
end
end
diff --git a/spec/unit/provider/zypper_repository_spec.rb b/spec/unit/provider/zypper_repository_spec.rb
new file mode 100644
index 0000000000..d909639d5a
--- /dev/null
+++ b/spec/unit/provider/zypper_repository_spec.rb
@@ -0,0 +1,62 @@
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: 2017, 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.
+#
+
+require "spec_helper"
+
+# Output of the command:
+# => rpm -qa gpg-pubkey*
+RPM_KEYS = <<-EOF
+gpg-pubkey-307e3d54-4be01a65
+gpg-pubkey-3dbdc284-53674dd4
+EOF
+
+# Output of the command:
+# => gpg --with-fingerprint [FILE]
+GPG_FINGER = <<-EOF
+pub 2048R/7BD9BF62 2011-08-19 [expires: 2024-06-14]
+ Key fingerprint = 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62
+uid nginx signing key <signing-key@nginx.com>
+EOF
+
+describe Chef::Provider::ZypperRepository do
+ let(:new_resource) { Chef::Resource::ZypperRepository.new("nginx") }
+
+ let(:shellout_env) { { env: { "LANG" => "en_US", "LANGUAGE" => "en_US" } } }
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::ZypperRepository.new(new_resource, run_context)
+ end
+
+ let(:rpm_key_finger) do
+ r = double("Mixlib::ShellOut", stdout: RPM_KEYS, exitstatus: 0, live_stream: true)
+ allow(r).to receive(:run_command)
+ r
+ end
+
+ let(:gpg_finger) do
+ r = double("Mixlib::ShellOut", stdout: GPG_FINGER, exitstatus: 0, live_stream: true)
+ allow(r).to receive(:run_command)
+ r
+ end
+
+ it "responds to load_current_resource" do
+ expect(provider).to respond_to(:load_current_resource)
+ end
+end