Puppet::Type.type(:apt_key).provide(:apt_key) do
- KEY_LINE = {
- :date => '[0-9]{4}-[0-9]{2}-[0-9]{2}',
- :key_type => '(R|D)',
- :key_size => '\d{4}',
- :key_id => '[0-9a-fA-F]+',
- :expires => 'expire(d|s)',
- }
-
confine :osfamily => :debian
defaultfor :osfamily => :debian
commands :apt_key => 'apt-key'
def self.instances
+ cli_args = ['adv','--list-keys', '--with-colons', '--fingerprint']
+
if RUBY_VERSION > '1.8.7'
- key_output = apt_key('list').encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
+ key_output = apt_key(cli_args).encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
else
- key_output = apt_key('list')
+ key_output = apt_key(cli_args)
end
+
+ pub_line, fpr_line = nil
+
key_array = key_output.split("\n").collect do |line|
- line_hash = key_line_hash(line)
- next unless line_hash
+ if line.start_with?('pub')
+ pub_line = line
+ elsif line.start_with?('fpr')
+ fpr_line = line
+ end
+
+ next unless (pub_line and fpr_line)
+
+ line_hash = key_line_hash(pub_line, fpr_line)
+
+ # reset everything
+ pub_line, fpr_line = nil
+
expired = false
if line_hash[:key_expiry]
end
new(
- :name => line_hash[:key_id],
- :id => line_hash[:key_id],
- :ensure => :present,
- :expired => expired,
- :expiry => line_hash[:key_expiry],
- :size => line_hash[:key_size],
- :type => line_hash[:key_type] == 'R' ? :rsa : :dsa,
- :created => line_hash[:key_created]
+ :name => line_hash[:key_fingerprint],
+ :id => line_hash[:key_fingerprint],
+ :fingerprint => line_hash[:key_fingerprint],
+ :short => line_hash[:key_short],
+ :long => line_hash[:key_long],
+ :ensure => :present,
+ :expired => expired,
+ :expiry => line_hash[:key_expiry],
+ :size => line_hash[:key_size],
+ :type => line_hash[:key_type],
+ :created => line_hash[:key_created]
)
end
key_array.compact!
def self.prefetch(resources)
apt_keys = instances
resources.keys.each do |name|
- if name.length == 16
- shortname=name[8..-1]
- else
- shortname=name
- end
- if provider = apt_keys.find{ |key| key.name == shortname }
- resources[name].provider = provider
+ if name.length == 40
+ if provider = apt_keys.find{ |key| key.fingerprint == name }
+ resources[name].provider = provider
+ end
+ elsif name.length == 16
+ if provider = apt_keys.find{ |key| key.long == name }
+ resources[name].provider = provider
+ end
+ elsif name.length == 8
+ if provider = apt_keys.find{ |key| key.short == name }
+ resources[name].provider = provider
+ end
end
end
end
- def self.key_line_hash(line)
- line_array = line.match(key_line_regexp).to_a
- return nil if line_array.length < 5
+ def self.key_line_hash(pub_line, fpr_line)
+ pub_split = pub_line.split(':')
+ fpr_split = fpr_line.split(':')
+ fingerprint = fpr_split.last
return_hash = {
- :key_id => line_array[3],
- :key_size => line_array[1],
- :key_type => line_array[2],
- :key_created => line_array[4],
- :key_expiry => nil,
+ :key_fingerprint => fingerprint,
+ :key_long => fingerprint[-16..-1], # last 16 characters of fingerprint
+ :key_short => fingerprint[-8..-1], # last 8 characters of fingerprint
+ :key_size => pub_split[2],
+ :key_type => nil,
+ :key_created => pub_split[5],
+ :key_expiry => pub_split[6].empty? ? nil : pub_split[6],
}
- return_hash[:key_expiry] = line_array[7] if line_array.length == 8
- return return_hash
- end
+ # set key type based on types defined in /usr/share/doc/gnupg/DETAILS.gz
+ case pub_split[3]
+ when "1"
+ return_hash[:key_type] = :rsa
+ when "17"
+ return_hash[:key_type] = :dsa
+ when "18"
+ return_hash[:key_type] = :ecc
+ when "19"
+ return_hash[:key_type] = :ecdsa
+ end
- def self.key_line_regexp
- # This regexp is trying to match the following output
- # pub 4096R/4BD6EC30 2010-07-10 [expires: 2016-07-08]
- # pub 1024D/CD2EFD2A 2009-12-15
- regexp = /\A
- pub # match only the public key, not signatures
- \s+ # bunch of spaces after that
- (#{KEY_LINE[:key_size]}) # size of the key, usually a multiple of 1024
- #{KEY_LINE[:key_type]} # type of the key, usually R or D
- \/ # separator between key_type and key_id
- (#{KEY_LINE[:key_id]}) # hex id of the key
- \s+ # bunch of spaces after that
- (#{KEY_LINE[:date]}) # date the key was added to the keyring
- # following an optional block which indicates if the key has an expiration
- # date and if it has expired yet
- (
- \s+ # again with thes paces
- \[ # we open with a square bracket
- #{KEY_LINE[:expires]} # expires or expired
- \: # a colon
- \s+ # more spaces
- (#{KEY_LINE[:date]}) # date indicating key expiry
- \] # we close with a square bracket
- )? # end of the optional block
- \Z/x
- regexp
+ return return_hash
end
def source_to_file(value)
require 'spec_helper_acceptance'
-PUPPETLABS_GPG_KEY_ID = '4BD6EC30'
-PUPPETLABS_GPG_LONG_KEY_ID = '1054B7A24BD6EC30'
-PUPPETLABS_APT_URL = 'apt.puppetlabs.com'
-PUPPETLABS_GPG_KEY_FILE = 'pubkey.gpg'
-CENTOS_GPG_KEY_ID = 'C105B9DE'
-CENTOS_REPO_URL = 'ftp.cvut.cz/centos'
-CENTOS_GPG_KEY_FILE = 'RPM-GPG-KEY-CentOS-6'
+PUPPETLABS_GPG_KEY_SHORT_ID = '4BD6EC30'
+PUPPETLABS_GPG_KEY_LONG_ID = '1054B7A24BD6EC30'
+PUPPETLABS_GPG_KEY_FINGERPRINT = '47B320EB4C7C375AA9DAE1A01054B7A24BD6EC30'
+PUPPETLABS_APT_URL = 'apt.puppetlabs.com'
+PUPPETLABS_GPG_KEY_FILE = 'pubkey.gpg'
+CENTOS_GPG_KEY_SHORT_ID = 'C105B9DE'
+CENTOS_GPG_KEY_LONG_ID = '0946FCA2C105B9DE'
+CENTOS_GPG_KEY_FINGERPRINT = 'C1DAC52D1664E8A4386DBA430946FCA2C105B9DE'
+CENTOS_REPO_URL = 'ftp.cvut.cz/centos'
+CENTOS_GPG_KEY_FILE = 'RPM-GPG-KEY-CentOS-6'
+
+KEY_CHECK_COMMAND = "apt-key adv --list-keys --with-colons --fingerprint | grep "
+PUPPETLABS_KEY_CHECK_COMMAND = "#{KEY_CHECK_COMMAND} #{PUPPETLABS_GPG_KEY_FINGERPRINT}"
+CENTOS_KEY_CHECK_COMMAND = "#{KEY_CHECK_COMMAND} #{CENTOS_GPG_KEY_FINGERPRINT}"
describe 'apt_key' do
before(:each) do
# Delete twice to make sure everything is cleaned
# up after the short key collision
- shell("apt-key del #{PUPPETLABS_GPG_KEY_ID}",
+ shell("apt-key del #{PUPPETLABS_GPG_KEY_SHORT_ID}",
:acceptable_exit_codes => [0,1,2])
- shell("apt-key del #{PUPPETLABS_GPG_KEY_ID}",
+ shell("apt-key del #{PUPPETLABS_GPG_KEY_SHORT_ID}",
:acceptable_exit_codes => [0,1,2])
end
key_versions = {
'32bit key id' => '4BD6EC30',
'64bit key id' => '1054B7A24BD6EC30',
+ '160bit key fingerprint' => '47B320EB4C7C375AA9DAE1A01054B7A24BD6EC30',
'32bit lowercase key id' => '4bd6ec30',
'64bit lowercase key id' => '1054b7a24bd6ec30',
+ '160bit lowercase key fingerprint' => '47b320eb4c7c375aa9dae1a01054b7a24bd6ec30',
'0x formatted 32bit key id' => '0x4BD6EC30',
'0x formatted 64bit key id' => '0x1054B7A24BD6EC30',
+ '0x formatted 160bit key fingerprint' => '0x47B320EB4C7C375AA9DAE1A01054B7A24BD6EC30',
'0x formatted 32bit lowercase key id' => '0x4bd6ec30',
'0x formatted 64bit lowercase key id' => '0x1054b7a24bd6ec30',
+ '0x formatted 160bit lowercase key fingerprint' => '0x47b320eb4c7c375aa9dae1a01054b7a24bd6ec30',
}
key_versions.each do |key, value|
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
end
end
it 'is removed' do
pp = <<-EOS
apt_key { 'centos':
- id => '#{CENTOS_GPG_KEY_ID}',
+ id => '#{CENTOS_GPG_KEY_LONG_ID}',
ensure => 'absent',
}
EOS
# Install the key first
shell("apt-key adv --keyserver keyserver.ubuntu.com \
- --recv-keys #{CENTOS_GPG_KEY_ID}")
- shell("apt-key list | grep #{CENTOS_GPG_KEY_ID}")
+ --recv-keys #{CENTOS_GPG_KEY_FINGERPRINT}")
+ shell(CENTOS_KEY_CHECK_COMMAND)
# Time to remove it using Puppet
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{CENTOS_GPG_KEY_ID}",
+ shell(CENTOS_KEY_CHECK_COMMAND,
:acceptable_exit_codes => [1])
shell("apt-key adv --keyserver keyserver.ubuntu.com \
- --recv-keys #{CENTOS_GPG_KEY_ID}")
+ --recv-keys #{CENTOS_GPG_KEY_FINGERPRINT}")
end
end
it 'is removed' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'absent',
}
EOS
# Install the key first
shell("apt-key adv --keyserver keyserver.ubuntu.com \
- --recv-keys #{PUPPETLABS_GPG_LONG_KEY_ID}")
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ --recv-keys #{PUPPETLABS_GPG_KEY_LONG_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
# Time to remove it using Puppet
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}",
+ shell(PUPPETLABS_KEY_CHECK_COMMAND,
:acceptable_exit_codes => [1])
end
end
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_FINGERPRINT}',
ensure => 'present',
content => "-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
end
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
content => 'For posterity: such content, much bogus, wow',
}
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
server => 'pgp.mit.edu',
}
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
end
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_FINGERPRINT}',
ensure => 'present',
server => 'hkp://pgp.mit.edu:80',
}
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
end
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
server => 'nonexistant.key.server',
}
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
server => '.pgp.key.server',
}
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => 'http://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
}
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
it 'fails with a 404' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => 'http://#{PUPPETLABS_APT_URL}/herpderp.gpg',
}
it 'fails with a socket error' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => 'http://apt.puppetlabss.com/herpderp.gpg',
}
context 'ftp://' do
before(:each) do
- shell("apt-key del #{CENTOS_GPG_KEY_ID}",
+ shell("apt-key del #{CENTOS_GPG_KEY_LONG_ID}",
:acceptable_exit_codes => [0,1,2])
end
it 'works' do
pp = <<-EOS
apt_key { 'CentOS 6':
- id => '#{CENTOS_GPG_KEY_ID}',
+ id => '#{CENTOS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => 'ftp://#{CENTOS_REPO_URL}/#{CENTOS_GPG_KEY_FILE}',
}
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{CENTOS_GPG_KEY_ID}")
+ shell(CENTOS_KEY_CHECK_COMMAND)
end
it 'fails with a 550' do
pp = <<-EOS
apt_key { 'CentOS 6':
- id => '#{CENTOS_GPG_KEY_ID}',
+ id => '#{CENTOS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => 'ftp://#{CENTOS_REPO_URL}/herpderp.gpg',
}
it 'fails with a socket error' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => 'ftp://apt.puppetlabss.com/herpderp.gpg',
}
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => 'https://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
}
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
it 'fails with a 404' do
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
end
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => '/tmp/totally_bogus.file',
}
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
source => '/tmp/fake-key.gpg',
}
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
keyserver_options => 'debug',
}
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
- shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ shell(PUPPETLABS_KEY_CHECK_COMMAND)
end
it 'fails on invalid options' do
pp = <<-EOS
apt_key { 'puppetlabs':
- id => '#{PUPPETLABS_GPG_KEY_ID}',
+ id => '#{PUPPETLABS_GPG_KEY_LONG_ID}',
ensure => 'present',
keyserver_options => 'this is totally bonkers',
}
EOS
- shell("apt-key del #{PUPPETLABS_GPG_KEY_ID}", :acceptable_exit_codes => [0,1,2])
+ shell("apt-key del #{PUPPETLABS_GPG_KEY_FINGERPRINT}", :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/--keyserver-options this is totally/)
end