packaging 0.88.77
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +17 -0
- data/README-Solaris.md +117 -0
- data/README.md +977 -0
- data/lib/packaging.rb +32 -0
- data/lib/packaging/archive.rb +126 -0
- data/lib/packaging/artifactory.rb +651 -0
- data/lib/packaging/artifactory/extensions.rb +94 -0
- data/lib/packaging/config.rb +492 -0
- data/lib/packaging/config/params.rb +387 -0
- data/lib/packaging/config/validations.rb +13 -0
- data/lib/packaging/deb.rb +28 -0
- data/lib/packaging/deb/repo.rb +264 -0
- data/lib/packaging/gem.rb +70 -0
- data/lib/packaging/metrics.rb +15 -0
- data/lib/packaging/nuget.rb +39 -0
- data/lib/packaging/paths.rb +376 -0
- data/lib/packaging/platforms.rb +507 -0
- data/lib/packaging/repo.rb +155 -0
- data/lib/packaging/retrieve.rb +75 -0
- data/lib/packaging/rpm.rb +5 -0
- data/lib/packaging/rpm/repo.rb +254 -0
- data/lib/packaging/sign.rb +8 -0
- data/lib/packaging/sign/deb.rb +9 -0
- data/lib/packaging/sign/dmg.rb +41 -0
- data/lib/packaging/sign/ips.rb +57 -0
- data/lib/packaging/sign/msi.rb +124 -0
- data/lib/packaging/sign/rpm.rb +115 -0
- data/lib/packaging/tar.rb +163 -0
- data/lib/packaging/util.rb +146 -0
- data/lib/packaging/util/date.rb +20 -0
- data/lib/packaging/util/execution.rb +85 -0
- data/lib/packaging/util/file.rb +125 -0
- data/lib/packaging/util/git.rb +174 -0
- data/lib/packaging/util/git_tags.rb +73 -0
- data/lib/packaging/util/gpg.rb +66 -0
- data/lib/packaging/util/jenkins.rb +95 -0
- data/lib/packaging/util/misc.rb +69 -0
- data/lib/packaging/util/net.rb +410 -0
- data/lib/packaging/util/os.rb +17 -0
- data/lib/packaging/util/platform.rb +40 -0
- data/lib/packaging/util/rake_utils.rb +112 -0
- data/lib/packaging/util/serialization.rb +19 -0
- data/lib/packaging/util/ship.rb +300 -0
- data/lib/packaging/util/tool.rb +41 -0
- data/lib/packaging/util/version.rb +334 -0
- data/spec/fixtures/config/ext/build_defaults.yaml +2 -0
- data/spec/fixtures/config/ext/project_data.yaml +2 -0
- data/spec/fixtures/configs/components/test_file.json +1 -0
- data/spec/fixtures/configs/components/test_file_2.json +0 -0
- data/spec/fixtures/configs/components/test_file_not_tagged.json +1 -0
- data/spec/fixtures/configs/components/test_file_wrong_ext.txt +0 -0
- data/spec/fixtures/configs/components/test_file_wrong_ext.wrong +0 -0
- data/spec/fixtures/util/pre_tasks.yaml +4 -0
- data/spec/lib/packaging/artifactory_spec.rb +221 -0
- data/spec/lib/packaging/config_spec.rb +576 -0
- data/spec/lib/packaging/deb/repo_spec.rb +157 -0
- data/spec/lib/packaging/deb_spec.rb +52 -0
- data/spec/lib/packaging/gem_spec.rb +86 -0
- data/spec/lib/packaging/paths_spec.rb +418 -0
- data/spec/lib/packaging/platforms_spec.rb +178 -0
- data/spec/lib/packaging/repo_spec.rb +135 -0
- data/spec/lib/packaging/retrieve_spec.rb +100 -0
- data/spec/lib/packaging/rpm/repo_spec.rb +133 -0
- data/spec/lib/packaging/sign_spec.rb +133 -0
- data/spec/lib/packaging/tar_spec.rb +116 -0
- data/spec/lib/packaging/util/execution_spec.rb +56 -0
- data/spec/lib/packaging/util/file_spec.rb +139 -0
- data/spec/lib/packaging/util/git_spec.rb +160 -0
- data/spec/lib/packaging/util/git_tag_spec.rb +36 -0
- data/spec/lib/packaging/util/gpg_spec.rb +64 -0
- data/spec/lib/packaging/util/jenkins_spec.rb +112 -0
- data/spec/lib/packaging/util/misc_spec.rb +31 -0
- data/spec/lib/packaging/util/net_spec.rb +259 -0
- data/spec/lib/packaging/util/os_spec.rb +31 -0
- data/spec/lib/packaging/util/rake_utils_spec.rb +70 -0
- data/spec/lib/packaging/util/ship_spec.rb +199 -0
- data/spec/lib/packaging/util/version_spec.rb +123 -0
- data/spec/lib/packaging_spec.rb +19 -0
- data/spec/spec_helper.rb +22 -0
- data/static_artifacts/PackageInfo.plist +3 -0
- data/tasks/00_utils.rake +214 -0
- data/tasks/30_metrics.rake +33 -0
- data/tasks/apple.rake +268 -0
- data/tasks/archive.rake +69 -0
- data/tasks/build.rake +12 -0
- data/tasks/clean.rake +5 -0
- data/tasks/config.rake +35 -0
- data/tasks/deb.rake +129 -0
- data/tasks/deb_repos.rake +28 -0
- data/tasks/deprecated.rake +130 -0
- data/tasks/doc.rake +20 -0
- data/tasks/education.rake +57 -0
- data/tasks/fetch.rake +60 -0
- data/tasks/gem.rake +159 -0
- data/tasks/jenkins.rake +538 -0
- data/tasks/jenkins_dynamic.rake +202 -0
- data/tasks/load_extras.rake +21 -0
- data/tasks/mock.rake +348 -0
- data/tasks/nightly_repos.rake +286 -0
- data/tasks/pe_deb.rake +12 -0
- data/tasks/pe_rpm.rake +13 -0
- data/tasks/pe_ship.rake +226 -0
- data/tasks/pe_sign.rake +13 -0
- data/tasks/pe_tar.rake +5 -0
- data/tasks/retrieve.rake +52 -0
- data/tasks/rpm.rake +66 -0
- data/tasks/rpm_repos.rake +29 -0
- data/tasks/ship.rake +692 -0
- data/tasks/sign.rake +154 -0
- data/tasks/tag.rake +8 -0
- data/tasks/tar.rake +28 -0
- data/tasks/update.rake +16 -0
- data/tasks/vanagon.rake +35 -0
- data/tasks/vendor_gems.rake +117 -0
- data/tasks/version.rake +33 -0
- data/tasks/z_data_dump.rake +65 -0
- data/templates/README +1 -0
- data/templates/downstream.xml.erb +47 -0
- data/templates/msi.xml.erb +197 -0
- data/templates/packaging.xml.erb +346 -0
- data/templates/repo.xml.erb +117 -0
- metadata +287 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
module Pkg::Sign::Deb
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def sign_changes(file)
|
5
|
+
# Lazy lazy lazy lazy lazy
|
6
|
+
sign_program = "-p'gpg --use-agent --no-tty'" if ENV['RPM_GPG_AGENT']
|
7
|
+
Pkg::Util::Execution.capture3("debsign #{sign_program} --re-sign -k#{Pkg::Config.gpg_key} #{file}")
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Pkg::Sign::Dmg
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def sign(target_dir = 'pkg')
|
5
|
+
use_identity = "-i #{Pkg::Config.osx_signing_ssh_key}" unless Pkg::Config.osx_signing_ssh_key.nil?
|
6
|
+
|
7
|
+
if Pkg::Config.osx_signing_server =~ /@/
|
8
|
+
host_string = "#{Pkg::Config.osx_signing_server}"
|
9
|
+
else
|
10
|
+
host_string = "#{ENV['USER']}@#{Pkg::Config.osx_signing_server}"
|
11
|
+
end
|
12
|
+
ssh_host_string = "#{use_identity} #{host_string}"
|
13
|
+
rsync_host_string = "-e 'ssh #{use_identity}' #{host_string}"
|
14
|
+
|
15
|
+
work_dir = "/tmp/#{Pkg::Util.rand_string}"
|
16
|
+
mount = File.join(work_dir, "mount")
|
17
|
+
signed = File.join(work_dir, "signed")
|
18
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "mkdir -p #{mount} #{signed}")
|
19
|
+
dmgs = Dir.glob("#{target_dir}/apple/**/*.dmg")
|
20
|
+
Pkg::Util::Net.rsync_to(dmgs.join(" "), rsync_host_string, work_dir)
|
21
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, %Q[for dmg in #{dmgs.map { |d| File.basename(d, ".dmg") }.join(" ")}; do
|
22
|
+
/usr/bin/hdiutil attach #{work_dir}/$dmg.dmg -mountpoint #{mount} -nobrowse -quiet ;
|
23
|
+
/usr/bin/security -q unlock-keychain -p "#{Pkg::Config.osx_signing_keychain_pw}" "#{Pkg::Config.osx_signing_keychain}" ;
|
24
|
+
for pkg in $(ls #{mount}/*.pkg | xargs -n 1 basename); do
|
25
|
+
if /usr/sbin/pkgutil --check-signature #{mount}/$pkg ; then
|
26
|
+
echo "$pkg is already signed, skipping . . ." ;
|
27
|
+
cp #{mount}/$pkg #{signed}/$pkg ;
|
28
|
+
else
|
29
|
+
/usr/bin/productsign --keychain "#{Pkg::Config.osx_signing_keychain}" --sign "#{Pkg::Config.osx_signing_cert}" #{mount}/$pkg #{signed}/$pkg ;
|
30
|
+
fi
|
31
|
+
done
|
32
|
+
/usr/bin/hdiutil detach #{mount} -quiet ;
|
33
|
+
/bin/rm #{work_dir}/$dmg.dmg ;
|
34
|
+
/usr/bin/hdiutil create -volname $dmg -srcfolder #{signed}/ #{work_dir}/$dmg.dmg ;
|
35
|
+
/bin/rm #{signed}/* ; done])
|
36
|
+
dmgs.each do | dmg |
|
37
|
+
Pkg::Util::Net.rsync_from("#{work_dir}/#{File.basename(dmg)}", rsync_host_string, File.dirname(dmg))
|
38
|
+
end
|
39
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "if [ -d '#{work_dir}' ]; then rm -rf '#{work_dir}'; fi")
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Pkg::Sign::Ips
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def sign(target_dir = 'pkg')
|
5
|
+
use_identity = "-i #{Pkg::Config.ips_signing_ssh_key}" unless Pkg::Config.ips_signing_ssh_key.nil?
|
6
|
+
|
7
|
+
ssh_host_string = "#{use_identity} #{ENV['USER']}@#{Pkg::Config.ips_signing_server}"
|
8
|
+
rsync_host_string = "-e 'ssh #{use_identity}' #{ENV['USER']}@#{Pkg::Config.ips_signing_server}"
|
9
|
+
|
10
|
+
p5ps = Dir.glob("#{target_dir}/solaris/11/**/*.p5p")
|
11
|
+
|
12
|
+
p5ps.each do |p5p|
|
13
|
+
work_dir = "/tmp/#{Pkg::Util.rand_string}"
|
14
|
+
unsigned_dir = "#{work_dir}/unsigned"
|
15
|
+
repo_dir = "#{work_dir}/repo"
|
16
|
+
signed_dir = "#{work_dir}/pkgs"
|
17
|
+
|
18
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "mkdir -p #{repo_dir} #{unsigned_dir} #{signed_dir}")
|
19
|
+
Pkg::Util::Net.rsync_to(p5p, rsync_host_string, unsigned_dir)
|
20
|
+
|
21
|
+
# Before we can get started with signing packages we need to create a repo
|
22
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrepo create #{repo_dir}")
|
23
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrepo set -s #{repo_dir} publisher/prefix=puppetlabs.com")
|
24
|
+
# And import all the packages into the repo.
|
25
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrecv -s #{unsigned_dir}/#{File.basename(p5p)} -d #{repo_dir} '*'")
|
26
|
+
# We are going to hard code the values for signing cert locations for now.
|
27
|
+
# This autmation will require an update to actually become reusable, but
|
28
|
+
# for now these values will stay this way so solaris signing will stop
|
29
|
+
# failing. Please update soon. 06/23/16
|
30
|
+
#
|
31
|
+
# - Sean P. McDonald
|
32
|
+
#
|
33
|
+
# We sign the entire repo
|
34
|
+
sign_cmd = "sudo -E /usr/bin/pkgsign -c /root/signing/signing_cert_2020.pem \
|
35
|
+
-i /root/signing/Thawte_SHA256_Code_Signing_CA.pem \
|
36
|
+
-i /root/signing/Thawte_Primary_Root_CA.pem \
|
37
|
+
-k /root/signing/signing_key_2020.pem \
|
38
|
+
-s 'file://#{work_dir}/repo' '*'"
|
39
|
+
puts "About to sign #{p5p} with #{sign_cmd} in #{work_dir}"
|
40
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, sign_cmd.squeeze(' '))
|
41
|
+
# pkgrecv with -a will pull packages out of the repo, so we need to do that too to actually get the packages we signed
|
42
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrecv -d #{signed_dir}/#{File.basename(p5p)} -a -s #{repo_dir} '*'")
|
43
|
+
begin
|
44
|
+
# lets make sure we actually signed something?
|
45
|
+
# **NOTE** if we're repeatedly trying to sign the same version this
|
46
|
+
# might explode because I don't know how to reset the IPS cache.
|
47
|
+
# Everything is amazing.
|
48
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkg contents -m -g #{signed_dir}/#{File.basename(p5p)} '*' | grep '^signature '")
|
49
|
+
rescue RuntimeError
|
50
|
+
raise "Looks like #{File.basename(p5p)} was not signed correctly, quitting!"
|
51
|
+
end
|
52
|
+
# and pull the packages back.
|
53
|
+
Pkg::Util::Net.rsync_from("#{signed_dir}/#{File.basename(p5p)}", rsync_host_string, File.dirname(p5p))
|
54
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "if [ -e '#{work_dir}' ] ; then sudo rm -r '#{work_dir}' ; fi")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Pkg::Sign::Msi
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def sign(target_dir = 'pkg')
|
5
|
+
use_identity = "-i #{Pkg::Config.msi_signing_ssh_key}" if Pkg::Config.msi_signing_ssh_key
|
6
|
+
|
7
|
+
ssh_host_string = "#{use_identity} Administrator@#{Pkg::Config.msi_signing_server}"
|
8
|
+
rsync_host_string = "-e 'ssh #{use_identity}' Administrator@#{Pkg::Config.msi_signing_server}"
|
9
|
+
|
10
|
+
work_dir = "Windows/Temp/#{Pkg::Util.rand_string}"
|
11
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "mkdir -p C:/#{work_dir}")
|
12
|
+
msis = Dir.glob("#{target_dir}/windows*/**/*.msi")
|
13
|
+
Pkg::Util::Net.rsync_to(msis.join(" "), rsync_host_string, "/cygdrive/c/#{work_dir}",
|
14
|
+
extra_flags: ["--ignore-existing --relative"])
|
15
|
+
|
16
|
+
# Please Note:
|
17
|
+
# We are currently adding two signatures to the msi.
|
18
|
+
#
|
19
|
+
# Microsoft compatable Signatures are composed of three different
|
20
|
+
# elements.
|
21
|
+
# 1) The Certificate used to sign the package. This is the element that
|
22
|
+
# is attached to organization. The certificate has an associated
|
23
|
+
# algorithm. We recently (February 2016) had to switch from a sha1 to
|
24
|
+
# a sha256 certificate. Sha1 was deprecated by many Microsoft
|
25
|
+
# elements on 2016-01-01, which forced us to switch to a sha256 cert.
|
26
|
+
# This sha256 certificate is recognized by all currently supported
|
27
|
+
# windows platforms (Windows 8/Vista forward).
|
28
|
+
# 2) The signature used to attach the certificate to the package. This
|
29
|
+
# can be a done with a variety of digest algorithms. Older platforms
|
30
|
+
# (i.e., Windows 8 and Windows Vista) don't recognize later
|
31
|
+
# algorithms like sha256.
|
32
|
+
# 3) The timestamp used to validate when the package was signed. This
|
33
|
+
# comes from an external source and can be delivered with a variety
|
34
|
+
# of digest algorithms. Older platforms do not recognize newer
|
35
|
+
# algorithms like sha256.
|
36
|
+
#
|
37
|
+
# We could have only one signature with the Sha256 Cert, Sha1 Signature,
|
38
|
+
# and Sha1 Timestamp, but that would be too easy. The sha256 signature
|
39
|
+
# and timestamp add more security to our packages. We can't have only
|
40
|
+
# sha256 elements in our package signature, though, because Windows 8
|
41
|
+
# and Windows Vista just don't recognize them at all.
|
42
|
+
#
|
43
|
+
# In order to add two signatures to an MSI, we also need to change the
|
44
|
+
# tool we use to sign packages with. Previously, we were using SignTool
|
45
|
+
# which is the Microsoft blessed program used to sign packages. However,
|
46
|
+
# this tool isn't able to add two signatures to an MSI specifically. It
|
47
|
+
# can dual-sign an exe, just not an MSI. In order to get the dual-signed
|
48
|
+
# packages, we decided to switch over to using osslsigncode. The original
|
49
|
+
# project didn't have support to compile on a windows system, so we
|
50
|
+
# decided to use this fork. The binaries on the signer were pulled from
|
51
|
+
# https://sourceforge.net/u/keeely/osslsigncode/ci/master/tree/
|
52
|
+
#
|
53
|
+
# These are our signatures:
|
54
|
+
# The first signature:
|
55
|
+
# * Sha256 Certificate
|
56
|
+
# * Sha1 Signature
|
57
|
+
# * Sha1 Timestamp
|
58
|
+
#
|
59
|
+
# The second signature:
|
60
|
+
# * Sha256 Certificate
|
61
|
+
# * Sha256 Signature
|
62
|
+
# * Sha256 Timestamp
|
63
|
+
#
|
64
|
+
# Once we no longer support Windows 8/Windows Vista, we can remove the
|
65
|
+
# first Sha1 signature.
|
66
|
+
sign_command = <<-CMD
|
67
|
+
for msipath in #{msis.join(" ")}; do
|
68
|
+
msi="$(basename $msipath)"
|
69
|
+
msidir="C:/#{work_dir}/$(dirname $msipath)"
|
70
|
+
if "/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe" verify -in "$msidir/$msi" ; then
|
71
|
+
echo "$msi is already signed, skipping . . ." ;
|
72
|
+
else
|
73
|
+
tries=5
|
74
|
+
sha1Servers=(http://timestamp.digicert.com/sha1/timestamp
|
75
|
+
http://timestamp.comodoca.com/authenticode)
|
76
|
+
for timeserver in "${sha1Servers[@]}"; do
|
77
|
+
for ((try=1; try<=$tries; try++)) do
|
78
|
+
ret=$(/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe sign \
|
79
|
+
-n "Puppet" -i "http://www.puppet.com" \
|
80
|
+
-h sha1 \
|
81
|
+
-pkcs12 "#{Pkg::Config.msi_signing_cert}" \
|
82
|
+
-pass "#{Pkg::Config.msi_signing_cert_pw}" \
|
83
|
+
-t "$timeserver" \
|
84
|
+
-in "$msidir/$msi" \
|
85
|
+
-out "$msidir/signed-$msi")
|
86
|
+
if [[ $ret == *"Succeeded"* ]]; then break; fi
|
87
|
+
done;
|
88
|
+
if [[ $ret == *"Succeeded"* ]]; then break; fi
|
89
|
+
done;
|
90
|
+
echo $ret
|
91
|
+
if [[ $ret != *"Succeeded"* ]]; then exit 1; fi
|
92
|
+
sha256Servers=(http://timestamp.digicert.com/sha256/timestamp
|
93
|
+
http://timestamp.comodoca.com?td=sha256)
|
94
|
+
for timeserver in "${sha256Servers[@]}"; do
|
95
|
+
for ((try=1; try<=$tries; try++)) do
|
96
|
+
ret=$(/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe sign \
|
97
|
+
-n "Puppet" -i "http://www.puppet.com" \
|
98
|
+
-nest -h sha256 \
|
99
|
+
-pkcs12 "#{Pkg::Config.msi_signing_cert}" \
|
100
|
+
-pass "#{Pkg::Config.msi_signing_cert_pw}" \
|
101
|
+
-ts "$timeserver" \
|
102
|
+
-in "$msidir/signed-$msi" \
|
103
|
+
-out "$msidir/$msi")
|
104
|
+
if [[ $ret == *"Succeeded"* ]]; then break; fi
|
105
|
+
done;
|
106
|
+
if [[ $ret == *"Succeeded"* ]]; then break; fi
|
107
|
+
done;
|
108
|
+
echo $ret
|
109
|
+
if [[ $ret != *"Succeeded"* ]]; then exit 1; fi
|
110
|
+
fi
|
111
|
+
done
|
112
|
+
CMD
|
113
|
+
|
114
|
+
Pkg::Util::Net.remote_execute(
|
115
|
+
ssh_host_string,
|
116
|
+
sign_command,
|
117
|
+
{ fail_fast: false }
|
118
|
+
)
|
119
|
+
msis.each do | msi |
|
120
|
+
Pkg::Util::Net.rsync_from("/cygdrive/c/#{work_dir}/#{msi}", rsync_host_string, File.dirname(msi))
|
121
|
+
end
|
122
|
+
Pkg::Util::Net.remote_execute(ssh_host_string, "if [ -d '/cygdrive/c/#{work_dir}' ]; then rm -rf '/cygdrive/c/#{work_dir}'; fi")
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Pkg::Sign::Rpm
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def sign(rpm, sign_flags = nil)
|
5
|
+
# To enable support for wrappers around rpm and thus support for gpg-agent
|
6
|
+
# rpm signing, we have to be able to tell the packaging repo what binary to
|
7
|
+
# use as the rpm signing tool.
|
8
|
+
rpm_command = ENV['RPM'] || Pkg::Util::Tool.find_tool('rpm')
|
9
|
+
|
10
|
+
# If we're using the gpg agent for rpm signing, we don't want to specify the
|
11
|
+
# input for the passphrase, which is what '--passphrase-fd 3' does. However,
|
12
|
+
# if we're not using the gpg agent, this is required, and is part of the
|
13
|
+
# defaults on modern rpm. The fun part of gpg-agent signing of rpms is
|
14
|
+
# specifying that the gpg check command always return true
|
15
|
+
gpg_check_command = ''
|
16
|
+
input_flag = ''
|
17
|
+
if Pkg::Util.boolean_value(ENV['RPM_GPG_AGENT'])
|
18
|
+
gpg_check_command = "--define '%__gpg_check_password_cmd /bin/true'"
|
19
|
+
else
|
20
|
+
input_flag = "--passphrase-fd 3"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Try this up to 5 times, to allow for incorrect passwords
|
24
|
+
Pkg::Util::Execution.retry_on_fail(:times => 5) do
|
25
|
+
# This definition of %__gpg_sign_cmd is the default on modern rpm. We
|
26
|
+
# accept extra flags to override certain signing behavior for older
|
27
|
+
# versions of rpm, e.g. specifying V3 signatures instead of V4.
|
28
|
+
Pkg::Util::Execution.capture3("#{rpm_command} #{gpg_check_command} --define '%_gpg_name #{Pkg::Util::Gpg.key}' --define '%__gpg_sign_cmd %{__gpg} gpg #{sign_flags} #{input_flag} --batch --no-verbose --no-armor --no-secmem-warning -u %{_gpg_name} -sbo %{__signature_filename} %{__plaintext_filename}' --addsign #{rpm}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def legacy_sign(rpm)
|
33
|
+
sign(rpm, "--force-v3-sigs --digest-algo=sha1")
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_sig?(rpm)
|
37
|
+
# This should allow the `Pkg::Util::Gpg.key` method to fail if gpg_key is
|
38
|
+
# not set, before shelling out. We also only want the short key, all
|
39
|
+
# lowercase, since that's what the `rpm -Kv` output uses.
|
40
|
+
key = Pkg::Util::Gpg.key.downcase.chars.last(8).join
|
41
|
+
signature_check_output = %x(rpm --checksig --verbose #{rpm})
|
42
|
+
# If the signing key has not been loaded on the system this is running on,
|
43
|
+
# the check will exit 1, even if the rpm is signed, so we can't use capture3,
|
44
|
+
# which bails out with non-0 exit codes. Instead, check that the output
|
45
|
+
# looks more-or-less how we expect it to.
|
46
|
+
fail "Something went wrong checking the signature of #{rpm}." unless signature_check_output.include? "Header"
|
47
|
+
return signature_check_output.include? "key ID #{key}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def sign_all(rpm_directory)
|
51
|
+
# Create a hash mapping full paths to basenames.
|
52
|
+
# This will allow us to keep track of the different paths that may be
|
53
|
+
# associated with a single basename, e.g. noarch packages.
|
54
|
+
all_rpms = {}
|
55
|
+
rpms_to_sign = Dir["#{rpm_directory}/**/*.rpm"]
|
56
|
+
rpms_to_sign.each do |rpm_path|
|
57
|
+
all_rpms[rpm_path] = File.basename(rpm_path)
|
58
|
+
end
|
59
|
+
# Delete a package, both from the signing server and from the rpm array, if
|
60
|
+
# there are other packages with the same basename so that we only sign the
|
61
|
+
# package once.
|
62
|
+
all_rpms.each do |rpm_path, rpm_filename|
|
63
|
+
if rpms_to_sign.map { |rpm| File.basename(rpm) }.count(rpm_filename) > 1
|
64
|
+
FileUtils.rm(rpm_path)
|
65
|
+
rpms_to_sign.delete(rpm_path)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
v3_rpms = []
|
70
|
+
v4_rpms = []
|
71
|
+
rpms_to_sign.each do |rpm|
|
72
|
+
platform_tag = Pkg::Paths.tag_from_artifact_path(rpm)
|
73
|
+
platform, version, _ = Pkg::Platforms.parse_platform_tag(platform_tag)
|
74
|
+
|
75
|
+
# We don't sign AIX rpms
|
76
|
+
next if platform_tag.include?('aix')
|
77
|
+
|
78
|
+
if has_sig? rpm
|
79
|
+
puts "#{rpm} is already signed, skipping . . ."
|
80
|
+
next
|
81
|
+
end
|
82
|
+
|
83
|
+
case Pkg::Platforms.signature_format_for_platform_version(platform, version)
|
84
|
+
when 'v3'
|
85
|
+
v3_rpms << rpm
|
86
|
+
when 'v4'
|
87
|
+
v4_rpms << rpm
|
88
|
+
else
|
89
|
+
fail "Cannot find signature type for package '#{rpm}'"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
unless v3_rpms.empty?
|
94
|
+
puts "Signing legacy (v3) rpms..."
|
95
|
+
legacy_sign(v3_rpms.join(' '))
|
96
|
+
end
|
97
|
+
|
98
|
+
unless v4_rpms.empty?
|
99
|
+
puts "Signing modern (v4) rpms..."
|
100
|
+
sign(v4_rpms.join(' '))
|
101
|
+
end
|
102
|
+
|
103
|
+
# Using the map of paths to basenames, we re-hardlink the rpms we deleted.
|
104
|
+
all_rpms.each do |link_path, rpm_filename|
|
105
|
+
next if File.exist? link_path
|
106
|
+
FileUtils.mkdir_p(File.dirname(link_path))
|
107
|
+
# Find paths where the signed rpm has the same basename, but different
|
108
|
+
# full path, as the one we need to link.
|
109
|
+
paths_to_link_to = rpms_to_sign.select { |rpm| File.basename(rpm) == rpm_filename && rpm != link_path }
|
110
|
+
paths_to_link_to.each do |path|
|
111
|
+
FileUtils.ln(path, link_path, :force => true, :verbose => true)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Pkg
|
2
|
+
class Tar
|
3
|
+
require 'fileutils'
|
4
|
+
require 'pathname'
|
5
|
+
include FileUtils
|
6
|
+
|
7
|
+
attr_accessor :files, :project, :version, :excludes, :target, :templates
|
8
|
+
attr_reader :tar
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@tar = Pkg::Util::Tool.find_tool('tar', :required => true)
|
12
|
+
@project = Pkg::Config.project
|
13
|
+
@version = Pkg::Config.version
|
14
|
+
@files = Pkg::Config.files
|
15
|
+
@target = File.join(Pkg::Config.project_root, "pkg", "#{@project}-#{@version}.tar.gz")
|
16
|
+
|
17
|
+
# If the user did not specify any files, then archive the entire working directory
|
18
|
+
# instead
|
19
|
+
@files ||= Dir.glob('*')
|
20
|
+
|
21
|
+
# We require that the excludes list be a string (which is space
|
22
|
+
# separated, we hope)(deprecated) or an array.
|
23
|
+
#
|
24
|
+
if Pkg::Config.tar_excludes
|
25
|
+
if Pkg::Config.tar_excludes.is_a?(String)
|
26
|
+
warn "warning: `tar_excludes` should be an array, not a string"
|
27
|
+
@excludes = Pkg::Config.tar_excludes.split(' ')
|
28
|
+
elsif Pkg::Config.tar_excludes.is_a?(Array)
|
29
|
+
@excludes = Pkg::Config.tar_excludes
|
30
|
+
else
|
31
|
+
fail "Tarball excludes must either be an array or a string, not #{@excludes.class}"
|
32
|
+
end
|
33
|
+
else
|
34
|
+
@excludes = []
|
35
|
+
end
|
36
|
+
|
37
|
+
# If the user has specified things to exclude via config file, they will be
|
38
|
+
# honored by the tar class, but we also always exclude the packaging repo
|
39
|
+
# and 'pkg' directory.
|
40
|
+
@excludes += ['pkg', 'ext/packaging']
|
41
|
+
|
42
|
+
# On the other hand, support for explicit templates started with Arrays,
|
43
|
+
# so that's all we support.
|
44
|
+
#
|
45
|
+
if Pkg::Config.templates
|
46
|
+
@templates = Pkg::Config.templates.dup
|
47
|
+
fail "templates must be an array" unless @templates.is_a?(Array)
|
48
|
+
expand_templates
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def install_files_to(workdir)
|
53
|
+
# It is nice to use arrays in YAML to represent array content, but we used
|
54
|
+
# to support a mode where a space-separated string was used. Support both
|
55
|
+
# to allow a gentle migration to a modern style...
|
56
|
+
patterns =
|
57
|
+
case @files
|
58
|
+
when String
|
59
|
+
$stderr.puts "warning: `files` should be an array, not a string"
|
60
|
+
@files.split(' ')
|
61
|
+
when Array
|
62
|
+
@files
|
63
|
+
else
|
64
|
+
raise "`files` must be a string or an array!"
|
65
|
+
end
|
66
|
+
|
67
|
+
Pkg::Util::File.install_files_into_dir(patterns, workdir)
|
68
|
+
end
|
69
|
+
|
70
|
+
# The templates of a project can include globs, which may expand to an
|
71
|
+
# arbitrary number of files. This method expands all of the templates using
|
72
|
+
# Dir.glob and then filters out any templates that live in the packaging
|
73
|
+
# tools themselves. If the template is a source/target combination, it is
|
74
|
+
# returned to the array untouched.
|
75
|
+
def expand_templates
|
76
|
+
@templates.map! do |tempfile|
|
77
|
+
if tempfile.is_a?(String)
|
78
|
+
# Expand possible globs to all matching entries
|
79
|
+
Dir.glob(File.join(Pkg::Config::project_root, tempfile))
|
80
|
+
elsif tempfile.is_a?(Hash)
|
81
|
+
tempfile
|
82
|
+
end
|
83
|
+
end
|
84
|
+
@templates.flatten!
|
85
|
+
|
86
|
+
# Reject matches that are templates from packaging itself. These will contain the packaging root.
|
87
|
+
# These tend to come from the current tar.rake implementation.
|
88
|
+
@templates.reject! { |temp| temp.is_a?(String) && temp.match(/#{Pkg::Config::packaging_root}/) }
|
89
|
+
end
|
90
|
+
|
91
|
+
# Given the tar object's template files (assumed to be in Pkg::Config.project_root), transform
|
92
|
+
# them, removing the originals. If workdir is passed, assume Pkg::Config.project_root
|
93
|
+
# exists in workdir
|
94
|
+
def template(workdir = nil)
|
95
|
+
workdir ||= Pkg::Config.project_root
|
96
|
+
root = Pathname.new(Pkg::Config.project_root)
|
97
|
+
|
98
|
+
# Templates can be either a string or a hash of source and target. If it
|
99
|
+
# is a string, the target is assumed to be the same path as the
|
100
|
+
# source,with the extension removed. If it is a hash, we assume nothing
|
101
|
+
# and use the provided source and target.
|
102
|
+
@templates.each do |cur_template|
|
103
|
+
if cur_template.is_a?(String)
|
104
|
+
template_file = File.expand_path(cur_template)
|
105
|
+
target_file = template_file.sub(File.extname(template_file), "")
|
106
|
+
elsif cur_template.is_a?(Hash)
|
107
|
+
template_file = File.expand_path(cur_template["source"])
|
108
|
+
target_file = File.expand_path(cur_template["target"])
|
109
|
+
end
|
110
|
+
|
111
|
+
# We construct paths to the erb template and its proposed target file
|
112
|
+
# relative to the project root, *not* fully qualified. This allows us
|
113
|
+
# to, given a temporary workdir containing a copy of the project,
|
114
|
+
# construct the full path to the erb and target file inside the
|
115
|
+
# temporary workdir.
|
116
|
+
#
|
117
|
+
rel_path_to_template = Pathname.new(template_file).relative_path_from(root).to_s
|
118
|
+
rel_path_to_target = Pathname.new(target_file).relative_path_from(root).to_s
|
119
|
+
|
120
|
+
# What we pass to Pkg::util::File.erb_file are the paths to the erb
|
121
|
+
# and target inside of a temporary project directory. We are, in
|
122
|
+
# essence, templating "in place." This is why we remove the original
|
123
|
+
# files - they're not the originals in the authoritative project
|
124
|
+
# directory, but the originals in the temporary working copy.
|
125
|
+
if File.exist?(File.join(workdir, rel_path_to_template))
|
126
|
+
mkpath(File.dirname(File.join(workdir, rel_path_to_target)), :verbose => false)
|
127
|
+
Pkg::Util::File.erb_file(File.join(workdir, rel_path_to_template), File.join(workdir, rel_path_to_target), true, :binding => Pkg::Config.get_binding)
|
128
|
+
elsif File.exist?(File.join(root, rel_path_to_template))
|
129
|
+
mkpath(File.dirname(File.join(workdir, rel_path_to_target)), :verbose => false)
|
130
|
+
Pkg::Util::File.erb_file(File.join(root, rel_path_to_template), File.join(workdir, rel_path_to_target), false, :binding => Pkg::Config.get_binding)
|
131
|
+
else
|
132
|
+
fail "Expected to find #{template_file} in #{root} for templating. But it was not there. Maybe you deleted it?"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def tar(target, source)
|
138
|
+
mkpath File.dirname(target)
|
139
|
+
cd File.dirname(source) do
|
140
|
+
%x(#{@tar} #{@excludes.map { |x| (" --exclude #{x} ") }.join if @excludes} -zcf '#{File.basename(target)}' '#{File.basename(source)}')
|
141
|
+
unless $?.success?
|
142
|
+
fail "Failed to create .tar.gz archive with #{@tar}. Please ensure the tar command in your path accepts the flags '-c', '-z', and '-f'"
|
143
|
+
end
|
144
|
+
mv File.basename(target), target
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def clean_up(workdir)
|
149
|
+
rm_rf workdir
|
150
|
+
end
|
151
|
+
|
152
|
+
def pkg!
|
153
|
+
workdir = File.join(Pkg::Util::File.mktemp, "#{@project}-#{@version}")
|
154
|
+
mkpath workdir
|
155
|
+
self.install_files_to workdir
|
156
|
+
self.template(workdir)
|
157
|
+
self.tar(@target, workdir)
|
158
|
+
self.clean_up workdir
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|