feat: initial commit
This commit is contained in:
commit
38f495e3f4
457 changed files with 40577 additions and 0 deletions
9
environments/production/thirdparty/apt/lib/facter/apt_reboot_required.rb
vendored
Normal file
9
environments/production/thirdparty/apt/lib/facter/apt_reboot_required.rb
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# apt_reboot_required.rb
|
||||
Facter.add(:apt_reboot_required) do
|
||||
confine 'os.family': 'Debian'
|
||||
setcode do
|
||||
File.file?('/var/run/reboot-required')
|
||||
end
|
||||
end
|
13
environments/production/thirdparty/apt/lib/facter/apt_sources.rb
vendored
Normal file
13
environments/production/thirdparty/apt/lib/facter/apt_sources.rb
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# This fact lists the .list filenames that are used by apt.
|
||||
Facter.add(:apt_sources) do
|
||||
confine 'os.family': 'Debian'
|
||||
setcode do
|
||||
sources = ['sources.list']
|
||||
Dir.glob('/etc/apt/sources.list.d/*.{list,sources}').each do |file|
|
||||
sources.push(File.basename(file))
|
||||
end
|
||||
sources
|
||||
end
|
||||
end
|
18
environments/production/thirdparty/apt/lib/facter/apt_update_last_success.rb
vendored
Normal file
18
environments/production/thirdparty/apt/lib/facter/apt_update_last_success.rb
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'facter'
|
||||
|
||||
# This is derived from the file /var/lib/apt/periodic/update-success-stamp
|
||||
# This is generated upon a successful apt-get update run natively in ubuntu.
|
||||
# the Puppetlabs-apt module deploys this same functionality for other debian-ish OSes
|
||||
Facter.add('apt_update_last_success') do
|
||||
confine 'os.family': 'Debian'
|
||||
setcode do
|
||||
if File.exist?('/var/lib/apt/periodic/update-success-stamp')
|
||||
# get epoch time
|
||||
File.mtime('/var/lib/apt/periodic/update-success-stamp').to_i
|
||||
else
|
||||
-1
|
||||
end
|
||||
end
|
||||
end
|
103
environments/production/thirdparty/apt/lib/facter/apt_updates.rb
vendored
Normal file
103
environments/production/thirdparty/apt/lib/facter/apt_updates.rb
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
apt_package_updates = nil
|
||||
apt_dist_updates = nil
|
||||
|
||||
# Executes the upgrading of packages
|
||||
# @param
|
||||
# upgrade_option Type of upgrade passed into apt-get command arguments i.e. 'upgrade' or 'dist-upgrade'
|
||||
def get_updates(upgrade_option)
|
||||
apt_updates = nil
|
||||
if File.executable?('/usr/bin/apt-get')
|
||||
apt_get_result = Facter::Core::Execution.execute("/usr/bin/apt-get -s -o Debug::NoLocking=true #{upgrade_option} 2>&1")
|
||||
unless apt_get_result.nil?
|
||||
apt_updates = [[], []]
|
||||
apt_get_result.each_line do |line|
|
||||
next unless %r{^Inst\s}.match?(line)
|
||||
|
||||
package = line.gsub(%r{^Inst\s([^\s]+)\s.*}, '\1').strip
|
||||
apt_updates[0].push(package)
|
||||
security_matches = [
|
||||
%r{ Debian-Security:},
|
||||
%r{ Ubuntu[^\s]+-security[, ]},
|
||||
%r{ gNewSense[^\s]+-security[, ]},
|
||||
]
|
||||
re = Regexp.union(security_matches)
|
||||
apt_updates[1].push(package) if line.match(re)
|
||||
end
|
||||
end
|
||||
end
|
||||
apt_updates
|
||||
end
|
||||
|
||||
Facter.add('apt_has_updates') do
|
||||
confine 'os.family': 'Debian'
|
||||
setcode do
|
||||
apt_package_updates = get_updates('upgrade')
|
||||
apt_package_updates != [[], []] if !apt_package_updates.nil? && apt_package_updates.length == 2
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_has_dist_updates') do
|
||||
confine 'os.family': 'Debian'
|
||||
setcode do
|
||||
apt_dist_updates = get_updates('dist-upgrade')
|
||||
apt_dist_updates != [[], []] if !apt_dist_updates.nil? && apt_dist_updates.length == 2
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_package_updates') do
|
||||
confine apt_has_updates: true
|
||||
setcode do
|
||||
apt_package_updates[0]
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_package_dist_updates') do
|
||||
confine apt_has_dist_updates: true
|
||||
setcode do
|
||||
apt_dist_updates[0]
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_package_security_updates') do
|
||||
confine apt_has_updates: true
|
||||
setcode do
|
||||
apt_package_updates[1]
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_package_security_dist_updates') do
|
||||
confine apt_has_dist_updates: true
|
||||
setcode do
|
||||
apt_dist_updates[1]
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_updates') do
|
||||
confine apt_has_updates: true
|
||||
setcode do
|
||||
Integer(apt_package_updates[0].length)
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_dist_updates') do
|
||||
confine apt_has_dist_updates: true
|
||||
setcode do
|
||||
Integer(apt_dist_updates[0].length)
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_security_updates') do
|
||||
confine apt_has_updates: true
|
||||
setcode do
|
||||
Integer(apt_package_updates[1].length)
|
||||
end
|
||||
end
|
||||
|
||||
Facter.add('apt_security_dist_updates') do
|
||||
confine apt_has_dist_updates: true
|
||||
setcode do
|
||||
Integer(apt_dist_updates[1].length)
|
||||
end
|
||||
end
|
240
environments/production/thirdparty/apt/lib/puppet/provider/apt_key/apt_key.rb
vendored
Normal file
240
environments/production/thirdparty/apt/lib/puppet/provider/apt_key/apt_key.rb
vendored
Normal file
|
@ -0,0 +1,240 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'open-uri'
|
||||
begin
|
||||
require 'net/ftp'
|
||||
rescue LoadError
|
||||
# Ruby 3.0 changed net-ftp to a default gem
|
||||
end
|
||||
require 'tempfile'
|
||||
|
||||
Puppet::Type.type(:apt_key).provide(:apt_key) do
|
||||
desc 'apt-key provider for apt_key resource'
|
||||
|
||||
confine 'os.family': :debian
|
||||
defaultfor 'os.family': :debian
|
||||
commands apt_key: 'apt-key'
|
||||
commands gpg: '/usr/bin/gpg'
|
||||
|
||||
def self.instances
|
||||
key_array = []
|
||||
|
||||
cli_args = ['adv', '--no-tty', '--list-keys', '--with-colons', '--fingerprint', '--fixed-list-mode']
|
||||
|
||||
key_output = apt_key(cli_args).encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
||||
|
||||
pub_line = nil
|
||||
fpr_lines = []
|
||||
sub_lines = []
|
||||
|
||||
lines = key_output.split("\n")
|
||||
|
||||
lines.each_index do |i|
|
||||
if lines[i].start_with?('pub')
|
||||
pub_line = lines[i]
|
||||
# starting a new public key, so reset fpr_lines and sub_lines
|
||||
fpr_lines = []
|
||||
sub_lines = []
|
||||
elsif lines[i].start_with?('fpr')
|
||||
fpr_lines << lines[i]
|
||||
elsif lines[i].start_with?('sub')
|
||||
sub_lines << lines[i]
|
||||
end
|
||||
|
||||
next unless (pub_line && !fpr_lines.empty?) && (!lines[i + 1] || lines[i + 1].start_with?('pub'))
|
||||
|
||||
line_hash = key_line_hash(pub_line, fpr_lines)
|
||||
|
||||
expired = line_hash[:key_expired] || subkeys_all_expired(sub_lines)
|
||||
|
||||
key_array << new(
|
||||
name: line_hash[:key_fingerprint],
|
||||
id: line_hash[:key_long],
|
||||
fingerprint: line_hash[:key_fingerprint],
|
||||
short: line_hash[:key_short],
|
||||
long: line_hash[:key_long],
|
||||
ensure: :present,
|
||||
expired: expired,
|
||||
expiry: line_hash[:key_expiry].nil? ? nil : line_hash[:key_expiry].strftime('%Y-%m-%d'),
|
||||
size: line_hash[:key_size],
|
||||
type: line_hash[:key_type],
|
||||
created: line_hash[:key_created].strftime('%Y-%m-%d'),
|
||||
)
|
||||
end
|
||||
key_array
|
||||
end
|
||||
|
||||
def self.prefetch(resources)
|
||||
apt_keys = instances
|
||||
resources.each_key do |name|
|
||||
case name.length
|
||||
when 40
|
||||
provider = apt_keys.find { |key| key.fingerprint == name }
|
||||
resources[name].provider = provider if provider
|
||||
when 16
|
||||
provider = apt_keys.find { |key| key.long == name }
|
||||
resources[name].provider = provider if provider
|
||||
when 8
|
||||
provider = apt_keys.find { |key| key.short == name }
|
||||
resources[name].provider = provider if provider
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.subkeys_all_expired(sub_lines)
|
||||
return false if sub_lines.empty?
|
||||
|
||||
sub_lines.each do |line|
|
||||
return false if line.split(':')[1] == '-'
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def self.key_line_hash(pub_line, fpr_lines)
|
||||
pub_split = pub_line.split(':')
|
||||
fpr_split = fpr_lines.first.split(':')
|
||||
|
||||
fingerprint = fpr_split.last
|
||||
return_hash = {
|
||||
key_fingerprint: fingerprint,
|
||||
key_long: fingerprint[-16..], # last 16 characters of fingerprint
|
||||
key_short: fingerprint[-8..], # last 8 characters of fingerprint
|
||||
key_size: pub_split[2],
|
||||
key_type: nil,
|
||||
key_created: Time.at(pub_split[5].to_i),
|
||||
key_expired: pub_split[1] == 'e',
|
||||
key_expiry: pub_split[6].empty? ? nil : Time.at(pub_split[6].to_i)
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
return_hash
|
||||
end
|
||||
|
||||
def source_to_file(value)
|
||||
parsed_value = URI.parse(value)
|
||||
if parsed_value.scheme.nil?
|
||||
raise(_('The file %{_value} does not exist') % { _value: value }) unless File.exist?(value)
|
||||
|
||||
# Because the tempfile method has to return a live object to prevent GC
|
||||
# of the underlying file from occuring too early, we also have to return
|
||||
# a file object here. The caller can still call the #path method on the
|
||||
# closed file handle to get the path.
|
||||
f = File.open(value, 'r')
|
||||
f.close
|
||||
f
|
||||
else
|
||||
exceptions = [OpenURI::HTTPError]
|
||||
exceptions << Net::FTPPermError if defined?(Net::FTPPermError)
|
||||
|
||||
begin
|
||||
# Only send basic auth if URL contains userinfo
|
||||
# Some webservers (e.g. Amazon S3) return code 400 if empty basic auth is sent
|
||||
if parsed_value.userinfo.nil?
|
||||
key = if parsed_value.scheme == 'https' && resource[:weak_ssl] == true
|
||||
URI.open(parsed_value, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read
|
||||
else
|
||||
parsed_value.read
|
||||
end
|
||||
else
|
||||
user_pass = parsed_value.userinfo.split(':')
|
||||
parsed_value.userinfo = ''
|
||||
key = URI.open(parsed_value, http_basic_authentication: user_pass).read
|
||||
end
|
||||
rescue *exceptions => e
|
||||
raise(_('%{_e} for %{_resource}') % { _e: e.message, _resource: resource[:source] })
|
||||
rescue SocketError
|
||||
raise(_('could not resolve %{_resource}') % { _resource: resource[:source] })
|
||||
else
|
||||
tempfile(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# The tempfile method needs to return the tempfile object to the caller, so
|
||||
# that it doesn't get deleted by the GC immediately after it returns. We
|
||||
# want the caller to control when it goes out of scope.
|
||||
def tempfile(content)
|
||||
file = Tempfile.new('apt_key')
|
||||
file.write content
|
||||
file.close
|
||||
# confirm that the fingerprint from the file, matches the long key that is in the manifest
|
||||
if name.size == 40
|
||||
if File.executable? command(:gpg)
|
||||
extracted_key = execute(["#{command(:gpg)} --no-tty --with-fingerprint --with-colons #{file.path} | awk -F: '/^fpr:/ { print $10 }'"], failonfail: false)
|
||||
extracted_key = extracted_key.chomp
|
||||
|
||||
found_match = false
|
||||
extracted_key.each_line do |line|
|
||||
found_match = true if line.chomp == name
|
||||
end
|
||||
unless found_match
|
||||
raise(_('The id in your manifest %{_resource} and the fingerprint from content/source don\'t match. Check for an error in the id and content/source is legitimate.') % { _resource: resource[:name] }) # rubocop:disable Layout/LineLength
|
||||
end
|
||||
else
|
||||
warning('/usr/bin/gpg cannot be found for verification of the id.')
|
||||
end
|
||||
end
|
||||
file
|
||||
end
|
||||
|
||||
def exists?
|
||||
# report expired keys as non-existing when refresh => true
|
||||
@property_hash[:ensure] == :present && !(resource[:refresh] && @property_hash[:expired])
|
||||
end
|
||||
|
||||
def create
|
||||
command = []
|
||||
if resource[:source].nil? && resource[:content].nil?
|
||||
# Breaking up the command like this is needed because it blows up
|
||||
# if --recv-keys isn't the last argument.
|
||||
command.push('adv', '--no-tty', '--keyserver', resource[:server])
|
||||
command.push('--keyserver-options', resource[:options]) unless resource[:options].nil?
|
||||
command.push('--recv-keys', resource[:id])
|
||||
elsif resource[:content]
|
||||
key_file = tempfile(resource[:content])
|
||||
command.push('add', key_file.path)
|
||||
elsif resource[:source]
|
||||
key_file = source_to_file(resource[:source])
|
||||
command.push('add', key_file.path)
|
||||
# In case we really screwed up, better safe than sorry.
|
||||
else
|
||||
raise(_('an unexpected condition occurred while trying to add the key: %{_resource}') % { _resource: resource[:id] })
|
||||
end
|
||||
apt_key(command)
|
||||
@property_hash[:ensure] = :present
|
||||
end
|
||||
|
||||
def destroy
|
||||
loop do
|
||||
apt_key('del', resource.provider.short)
|
||||
r = execute(["#{command(:apt_key)} list | grep '/#{resource.provider.short}\s'"], failonfail: false)
|
||||
break unless r.exitstatus.zero?
|
||||
end
|
||||
@property_hash.clear
|
||||
end
|
||||
|
||||
def read_only(_value)
|
||||
raise(_('This is a read-only property.'))
|
||||
end
|
||||
|
||||
mk_resource_methods
|
||||
|
||||
# Alias the setters of read-only properties
|
||||
# to the read_only function.
|
||||
alias_method :created=, :read_only
|
||||
alias_method :expired=, :read_only
|
||||
alias_method :expiry=, :read_only
|
||||
alias_method :size=, :read_only
|
||||
alias_method :type=, :read_only
|
||||
end
|
146
environments/production/thirdparty/apt/lib/puppet/type/apt_key.rb
vendored
Normal file
146
environments/production/thirdparty/apt/lib/puppet/type/apt_key.rb
vendored
Normal file
|
@ -0,0 +1,146 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'pathname'
|
||||
require 'puppet/parameter/boolean'
|
||||
|
||||
Puppet::Type.newtype(:apt_key) do
|
||||
@doc = <<-MANIFEST
|
||||
@summary This type provides Puppet with the capabilities to manage GPG keys needed
|
||||
by apt to perform package validation. Apt has it's own GPG keyring that can
|
||||
be manipulated through the `apt-key` command.
|
||||
|
||||
@example Basic usage
|
||||
apt_key { '6F6B15509CF8E59E6E469F327F438280EF8D349F':
|
||||
source => 'http://apt.puppetlabs.com/pubkey.gpg'
|
||||
}
|
||||
|
||||
**Autorequires**
|
||||
|
||||
If Puppet is given the location of a key file which looks like an absolute
|
||||
path this type will autorequire that file.
|
||||
|
||||
@api private
|
||||
MANIFEST
|
||||
|
||||
ensurable
|
||||
|
||||
validate do
|
||||
raise(_('ensure => absent and refresh => true are mutually exclusive')) if self[:refresh] == true && self[:ensure] == :absent
|
||||
raise(_('The properties content and source are mutually exclusive.')) if self[:content] && self[:source]
|
||||
|
||||
warning(_('The id should be a full fingerprint (40 characters), see README.')) if self[:id].length < 40
|
||||
end
|
||||
|
||||
newparam(:id, namevar: true) do
|
||||
desc 'The ID of the key you want to manage.'
|
||||
# GPG key ID's should be either 32-bit (short) or 64-bit (long) key ID's
|
||||
# and may start with the optional 0x, or they can be 40-digit key fingerprints
|
||||
newvalues(%r{\A(0x)?[0-9a-fA-F]{8}\Z}, %r{\A(0x)?[0-9a-fA-F]{16}\Z}, %r{\A(0x)?[0-9a-fA-F]{40}\Z})
|
||||
munge do |value|
|
||||
id = if value.start_with?('0x')
|
||||
value.partition('0x').last.upcase
|
||||
else
|
||||
value.upcase
|
||||
end
|
||||
id
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:content) do
|
||||
desc 'The content of, or string representing, a GPG key.'
|
||||
end
|
||||
|
||||
newparam(:source) do
|
||||
desc 'Location of a GPG key file, /path/to/file, ftp://, http:// or https://'
|
||||
newvalues(%r{\Ahttps?://}, %r{\Aftp://}, %r{\A/\w+})
|
||||
end
|
||||
|
||||
autorequire(:file) do
|
||||
self[:source] if self[:source] && Pathname.new(self[:source]).absolute?
|
||||
end
|
||||
|
||||
newparam(:server) do
|
||||
desc 'The key server to fetch the key from based on the ID. It can either be a domain name or url.'
|
||||
defaultto :'keyserver.ubuntu.com'
|
||||
|
||||
newvalues(%r{\A((hkp|hkps|http|https)://)?([a-z\d])([a-z\d-]{0,61}\.)+[a-z\d]+(:\d{2,5})?(/[a-zA-Z\d\-_.]+)*/?$})
|
||||
end
|
||||
|
||||
newparam(:options) do
|
||||
desc 'Additional options to pass to apt-key\'s --keyserver-options.'
|
||||
end
|
||||
|
||||
newparam(:refresh, boolean: true, parent: Puppet::Parameter::Boolean) do
|
||||
desc 'When true, recreate an existing expired key'
|
||||
defaultto false
|
||||
end
|
||||
|
||||
newparam(:weak_ssl, boolean: true, parent: Puppet::Parameter::Boolean) do
|
||||
desc 'When true and source uses https, accepts download of keys without SSL verification'
|
||||
defaultto false
|
||||
end
|
||||
|
||||
newproperty(:fingerprint) do
|
||||
desc <<-MANIFEST
|
||||
The 40-digit hexadecimal fingerprint of the specified GPG key.
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
|
||||
newproperty(:long) do
|
||||
desc <<-MANIFEST
|
||||
The 16-digit hexadecimal id of the specified GPG key.
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
|
||||
newproperty(:short) do
|
||||
desc <<-MANIFEST
|
||||
The 8-digit hexadecimal id of the specified GPG key.
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
|
||||
newproperty(:expired) do
|
||||
desc <<-MANIFEST
|
||||
Indicates if the key has expired.
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
|
||||
newproperty(:expiry) do
|
||||
desc <<-MANIFEST
|
||||
The date the key will expire, or nil if it has no expiry date.
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
|
||||
newproperty(:size) do
|
||||
desc <<-MANIFEST
|
||||
The key size, usually a multiple of 1024.
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
|
||||
newproperty(:type) do
|
||||
desc <<-MANIFEST
|
||||
The key type, one of: rsa, dsa, ecc, ecdsa
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
|
||||
newproperty(:created) do
|
||||
desc <<-MANIFEST
|
||||
Date the key was created.
|
||||
|
||||
This property is read-only.
|
||||
MANIFEST
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue