From d50fef82e8a1865fda8fdfa5f7afa0aaa6465163 Mon Sep 17 00:00:00 2001 From: Morgan Haskel Date: Thu, 4 Jun 2015 09:41:27 -0700 Subject: [PATCH] Make apt::key compatible with 1.8.x --- README.md | 12 +- manifests/key.pp | 155 ++++++++-------- spec/defines/key_compat_spec.rb | 316 ++++++++++++++++++++++++++++++++ 3 files changed, 400 insertions(+), 83 deletions(-) create mode 100644 spec/defines/key_compat_spec.rb diff --git a/README.md b/README.md index ec27807..0e2dfd6 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,16 @@ The `apt::key` define makes use of the `apt_key` type, but includes extra functi * `server`: Specifies a keyserver to provide the GPG key. Valid options: a string containing a domain name or a full URL (http://, https://, or hkp://). Default: 'keyserver.ubuntu.com'. +* `key`: Specifies a GPG key to authenticate Apt package signatures. Valid options: a string containing a key ID (8 or 16 hexadecimal characters, optionally prefixed with "0x") or a full key fingerprint (40 hexadecimal characters). Default: undef. **Note** This parameter is deprecated and will be removed in a future release. + +* `key_content`: Supplies the entire GPG key. Useful in case the key can't be fetched from a remote location and using a file resource is inconvenient. Valid options: a string. Default: undef. **Note** This parameter is deprecated and will be removed in a future release. + +* `key_source`: Specifies the location of an existing GPG key file to copy. Valid options: a string containing a URL (ftp://, http://, or https://) or an absolute path. Default: undef. **Note** This parameter is deprecated and will be removed in a future release. + +* `key_server`: Specifies a keyserver to provide the GPG key. Valid options: a string containing a domain name or a full URL (http://, https://, or hkp://). Default: 'keyserver.ubuntu.com' .**Note** This parameter is deprecated and will be removed in a future release. + +* `key_options`: Passes additional options to `apt-key adv --keyserver-options`. Valid options: a string. Default: undef. **Note** This parameter is deprecated and will be removed in a future release. + #### Define: `apt::pin` Manages Apt pins. @@ -447,4 +457,4 @@ Puppet Labs modules on the Puppet Forge are open projects, and community contrib For more information, see our [module contribution guide.](https://docs.puppetlabs.com/forge/contributing.html) -To see who's already involved, see the [list of contributors.](https://github.com/puppetlabs/puppetlabs-apt/graphs/contributors) \ No newline at end of file +To see who's already involved, see the [list of contributors.](https://github.com/puppetlabs/puppetlabs-apt/graphs/contributors) diff --git a/manifests/key.pp b/manifests/key.pp index 6761e69..8fbb47a 100644 --- a/manifests/key.pp +++ b/manifests/key.pp @@ -1,115 +1,106 @@ # == Define: apt::key -# -# The apt::key defined type allows for keys to be added to apt's keyring -# which is used for package validation. This defined type uses the apt_key -# native type to manage keys. This is a simple wrapper around apt_key with -# a few safeguards in place. -# -# === Parameters -# -# [*id*] -# _default_: +$title+, the title/name of the resource -# -# Is a GPG key ID or full key fingerprint. This value is validated with -# a regex enforcing it to only contain valid hexadecimal characters, be -# precisely 8 or 16 hexadecimal characters long and optionally prefixed -# with 0x for key IDs, or 40 hexadecimal characters long for key -# fingerprints. -# -# [*ensure*] -# _default_: +present+ -# -# The state we want this key in, may be either one of: -# * +present+ -# * +absent+ -# -# [*content*] -# _default_: +undef+ -# -# This parameter can be used to pass in a GPG key as a -# string in case it cannot be fetched from a remote location -# and using a file resource is for other reasons inconvenient. -# -# [*source*] -# _default_: +undef+ -# -# This parameter can be used to pass in the location of a GPG -# key. This URI can take the form of a: -# * +URL+: ftp, http or https -# * +path+: absolute path to a file on the target system. -# -# [*server*] -# _default_: +undef+ -# -# The keyserver from where to fetch our GPG key. It can either be a domain -# name or url. It defaults to +keyserver.ubuntu.com+. -# -# [*options*] -# _default_: +undef+ -# -# Additional options to pass on to `apt-key adv --keyserver-options`. define apt::key ( - $id = $title, - $ensure = present, - $content = undef, - $source = undef, - $server = $::apt::keyserver, - $options = undef, + $id = $title, + $ensure = present, + $content = undef, + $source = undef, + $server = $::apt::keyserver, + $options = undef, + $key = undef, + $key_content = undef, + $key_source = undef, + $key_server = undef, + $key_options = undef, ) { - validate_re($id, ['\A(0x)?[0-9a-fA-F]{8}\Z', '\A(0x)?[0-9a-fA-F]{16}\Z', '\A(0x)?[0-9a-fA-F]{40}\Z']) + if $key != undef { + warning('$key is deprecated and will be removed in the next major release. Please use $id instead.') + $_id = $key + } else { + $_id = $id + } + + if $key_content != undef { + warning('$key_content is deprecated and will be removed in the next major release. Please use $content instead.') + $_content = $key_content + } else { + $_content = $content + } + + if $key_source != undef { + warning('$key_source is deprecated and will be removed in the next major release. Please use $source instead.') + $_source = $key_source + } else { + $_source = $source + } + + if $key_server != undef { + warning('$key_server is deprecated and will be removed in the next major release. Please use $server instead.') + $_server = $key_server + } else { + $_server = $server + } + + if $key_options != undef { + warning('$key_options is deprecated and will be removed in the next major release. Please use $options instead.') + $_options = $key_options + } else { + $_options = $options + } + + validate_re($_id, ['\A(0x)?[0-9a-fA-F]{8}\Z', '\A(0x)?[0-9a-fA-F]{16}\Z', '\A(0x)?[0-9a-fA-F]{40}\Z']) validate_re($ensure, ['\Aabsent|present\Z',]) - if $content { - validate_string($content) + if $_content { + validate_string($_content) } - if $source { - validate_re($source, ['\Ahttps?:\/\/', '\Aftp:\/\/', '\A\/\w+']) + if $_source { + validate_re($_source, ['\Ahttps?:\/\/', '\Aftp:\/\/', '\A\/\w+']) } - if $server { - validate_re($server,['\A((hkp|http|https):\/\/)?([a-z\d])([a-z\d-]{0,61}\.)+[a-z\d]+(:\d{2,5})?$']) + if $_server { + validate_re($_server,['\A((hkp|http|https):\/\/)?([a-z\d])([a-z\d-]{0,61}\.)+[a-z\d]+(:\d{2,5})?$']) } - if $options { - validate_string($options) + if $_options { + validate_string($_options) } case $ensure { present: { - if defined(Anchor["apt_key ${id} absent"]){ - fail("key with id ${id} already ensured as absent") + if defined(Anchor["apt_key ${_id} absent"]){ + fail("key with id ${_id} already ensured as absent") } - if !defined(Anchor["apt_key ${id} present"]) { + if !defined(Anchor["apt_key ${_id} present"]) { apt_key { $title: ensure => $ensure, - id => $id, - source => $source, - content => $content, - server => $server, - options => $options, + id => $_id, + source => $_source, + content => $_content, + server => $_server, + options => $_options, } -> - anchor { "apt_key ${id} present": } + anchor { "apt_key ${_id} present": } } } absent: { - if defined(Anchor["apt_key ${id} present"]){ - fail("key with id ${id} already ensured as present") + if defined(Anchor["apt_key ${_id} present"]){ + fail("key with id ${_id} already ensured as present") } - if !defined(Anchor["apt_key ${id} absent"]){ + if !defined(Anchor["apt_key ${_id} absent"]){ apt_key { $title: ensure => $ensure, - id => $id, - source => $source, - content => $content, - server => $server, - options => $options, + id => $_id, + source => $_source, + content => $_content, + server => $_server, + options => $_options, } -> - anchor { "apt_key ${id} absent": } + anchor { "apt_key ${_id} absent": } } } diff --git a/spec/defines/key_compat_spec.rb b/spec/defines/key_compat_spec.rb new file mode 100644 index 0000000..872bcad --- /dev/null +++ b/spec/defines/key_compat_spec.rb @@ -0,0 +1,316 @@ +require 'spec_helper' + +describe 'apt::key', :type => :define do + let(:facts) { { :lsbdistid => 'Debian' } } + GPG_KEY_ID = '47B320EB4C7C375AA9DAE1A01054B7A24BD6EC30' + + let :title do + GPG_KEY_ID + end + + describe 'normal operation' do + describe 'default options' do + it 'contains the apt_key' do + should contain_apt_key(title).with({ + :id => title, + :ensure => 'present', + :source => nil, + :server => nil, + :content => nil, + :keyserver_options => nil, + }) + end + it 'contains the apt_key present anchor' do + should contain_anchor("apt_key #{title} present") + end + end + + describe 'title and key =>' do + let :title do + 'puppetlabs' + end + + let :params do { + :key => GPG_KEY_ID, + } end + + it 'contains the apt_key' do + should contain_apt_key(title).with({ + :id => GPG_KEY_ID, + :ensure => 'present', + :source => nil, + :server => nil, + :content => nil, + :keyserver_options => nil, + }) + end + it 'contains the apt_key present anchor' do + should contain_anchor("apt_key #{GPG_KEY_ID} present") + end + end + + describe 'ensure => absent' do + let :params do { + :ensure => 'absent', + } end + + it 'contains the apt_key' do + should contain_apt_key(title).with({ + :id => title, + :ensure => 'absent', + :source => nil, + :server => nil, + :content => nil, + :keyserver_options => nil, + }) + end + it 'contains the apt_key absent anchor' do + should contain_anchor("apt_key #{title} absent") + end + end + + describe 'set a bunch of things!' do + let :params do { + :key_content => 'GPG key content', + :key_source => 'http://apt.puppetlabs.com/pubkey.gpg', + :key_server => 'pgp.mit.edu', + :key_options => 'debug', + } end + + it 'contains the apt_key' do + should contain_apt_key(title).with({ + :id => title, + :ensure => 'present', + :source => 'http://apt.puppetlabs.com/pubkey.gpg', + :server => 'pgp.mit.edu', + :content => params[:key_content], + :options => 'debug', + }) + end + it 'contains the apt_key present anchor' do + should contain_anchor("apt_key #{title} present") + end + end + + context "domain with dash" do + let(:params) do{ + :key_server => 'p-gp.m-it.edu', + } end + it 'contains the apt_key' do + should contain_apt_key(title).with({ + :id => title, + :server => 'p-gp.m-it.edu', + }) + end + end + + context "url" do + let :params do + { + :key_server => 'hkp://pgp.mit.edu', + } + end + it 'contains the apt_key' do + should contain_apt_key(title).with({ + :id => title, + :server => 'hkp://pgp.mit.edu', + }) + end + end + context "url with port number" do + let :params do + { + :key_server => 'hkp://pgp.mit.edu:80', + } + end + it 'contains the apt_key' do + should contain_apt_key(title).with({ + :id => title, + :server => 'hkp://pgp.mit.edu:80', + }) + end + end + end + + describe 'validation' do + context "domain begin with dash" do + let(:params) do{ + :key_server => '-pgp.mit.edu', + } end + it 'fails' do + expect { subject.call } .to raise_error(/does not match/) + end + end + + context "domain begin with dot" do + let(:params) do{ + :key_server => '.pgp.mit.edu', + } end + it 'fails' do + expect { subject.call } .to raise_error(/does not match/) + end + end + + context "domain end with dot" do + let(:params) do{ + :key_server => "pgp.mit.edu.", + } end + it 'fails' do + expect { subject.call } .to raise_error(/does not match/) + end + end + context "exceed character url" do + let :params do + { + :key_server => 'hkp://pgpiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.mit.edu' + } + end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + context "incorrect port number url" do + let :params do + { + :key_server => 'hkp://pgp.mit.edu:8008080' + } + end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + context "incorrect protocol for url" do + let :params do + { + :key_server => 'abc://pgp.mit.edu:80' + } + end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + context "missing port number url" do + let :params do + { + :key_server => 'hkp://pgp.mit.edu:' + } + end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + context "url ending with a dot" do + let :params do + { + :key_server => 'hkp://pgp.mit.edu.' + } + end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + context "url begin with a dash" do + let(:params) do{ + :key_server => "hkp://-pgp.mit.edu", + } end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + context 'invalid key' do + let :title do + 'Out of rum. Why? Why are we out of rum?' + end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + + context 'invalid source' do + let :params do { + :key_source => 'afp://puppetlabs.com/key.gpg', + } end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + + context 'invalid content' do + let :params do { + :key_content => [], + } end + it 'fails' do + expect { subject.call }.to raise_error(/is not a string/) + end + end + + context 'invalid server' do + let :params do { + :key_server => 'two bottles of rum', + } end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + + context 'invalid keyserver_options' do + let :params do { + :key_options => {}, + } end + it 'fails' do + expect { subject.call }.to raise_error(/is not a string/) + end + end + + context 'invalid ensure' do + let :params do + { + :ensure => 'foo', + } + end + it 'fails' do + expect { subject.call }.to raise_error(/does not match/) + end + end + + describe 'duplication' do + context 'two apt::key resources for same key, different titles' do + let :pre_condition do + "apt::key { 'duplicate': key => '#{title}', }" + end + + it 'contains two apt::key resources' do + should contain_apt__key('duplicate').with({ + :key => title, + :ensure => 'present', + }) + should contain_apt__key(title).with({ + :id => title, + :ensure => 'present', + }) + end + + it 'contains only a single apt_key' do + should contain_apt_key('duplicate').with({ + :id => title, + :ensure => 'present', + :source => nil, + :server => nil, + :content => nil, + :keyserver_options => nil, + }) + should_not contain_apt_key(title) + end + end + + context 'two apt::key resources, different ensure' do + let :pre_condition do + "apt::key { 'duplicate': key => '#{title}', ensure => 'absent', }" + end + it 'informs the user of the impossibility' do + expect { subject.call }.to raise_error(/already ensured as absent/) + end + end + end + end +end -- 2.32.3