packaging 0.88.77 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +128 -74
  3. data/lib/packaging/artifactory.rb +60 -433
  4. data/lib/packaging/config/params.rb +7 -28
  5. data/lib/packaging/config.rb +50 -150
  6. data/lib/packaging/deb/repo.rb +19 -20
  7. data/lib/packaging/gem.rb +83 -41
  8. data/lib/packaging/ips.rb +57 -0
  9. data/lib/packaging/msi.rb +89 -0
  10. data/lib/packaging/nuget.rb +1 -1
  11. data/lib/packaging/osx.rb +36 -0
  12. data/lib/packaging/paths.rb +87 -225
  13. data/lib/packaging/platforms.rb +416 -443
  14. data/lib/packaging/repo.rb +22 -122
  15. data/lib/packaging/retrieve.rb +7 -36
  16. data/lib/packaging/rpm/repo.rb +8 -5
  17. data/lib/packaging/tar.rb +0 -9
  18. data/lib/packaging/util/date.rb +0 -5
  19. data/lib/packaging/util/execution.rb +2 -2
  20. data/lib/packaging/util/git.rb +1 -1
  21. data/lib/packaging/util/gpg.rb +1 -5
  22. data/lib/packaging/util/net.rb +37 -79
  23. data/lib/packaging/util/rake_utils.rb +0 -1
  24. data/lib/packaging/util/ship.rb +13 -142
  25. data/lib/packaging/util/tool.rb +1 -1
  26. data/lib/packaging/util/version.rb +0 -8
  27. data/lib/packaging/util.rb +2 -2
  28. data/lib/packaging.rb +3 -3
  29. data/spec/fixtures/config/params.yaml +2 -0
  30. data/spec/lib/packaging/artifactory_spec.rb +16 -66
  31. data/spec/lib/packaging/config_spec.rb +29 -49
  32. data/spec/lib/packaging/deb/repo_spec.rb +7 -16
  33. data/spec/lib/packaging/paths_spec.rb +56 -321
  34. data/spec/lib/packaging/platforms_spec.rb +21 -46
  35. data/spec/lib/packaging/repo_spec.rb +40 -78
  36. data/spec/lib/packaging/retrieve_spec.rb +8 -47
  37. data/spec/lib/packaging/rpm/repo_spec.rb +4 -4
  38. data/spec/lib/packaging/tar_spec.rb +40 -34
  39. data/spec/lib/packaging/util/git_tag_spec.rb +1 -1
  40. data/spec/lib/packaging/util/gpg_spec.rb +1 -1
  41. data/spec/lib/packaging/util/net_spec.rb +15 -35
  42. data/spec/lib/packaging/util/ship_spec.rb +63 -145
  43. data/spec/spec_helper.rb +14 -0
  44. data/tasks/00_utils.rake +6 -4
  45. data/tasks/apple.rake +0 -2
  46. data/tasks/config.rake +0 -5
  47. data/tasks/education.rake +5 -5
  48. data/tasks/fetch.rake +14 -17
  49. data/tasks/gem.rake +121 -134
  50. data/tasks/jenkins.rake +7 -51
  51. data/tasks/nightly_repos.rake +69 -20
  52. data/tasks/pe_ship.rake +11 -16
  53. data/tasks/retrieve.rake +6 -13
  54. data/tasks/ship.rake +256 -196
  55. data/tasks/sign.rake +135 -63
  56. data/tasks/tar.rake +6 -0
  57. data/templates/packaging.xml.erb +7 -9
  58. data/templates/repo.xml.erb +3 -6
  59. metadata +27 -80
  60. data/lib/packaging/archive.rb +0 -126
  61. data/lib/packaging/artifactory/extensions.rb +0 -94
  62. data/lib/packaging/config/validations.rb +0 -13
  63. data/lib/packaging/metrics.rb +0 -15
  64. data/lib/packaging/sign/deb.rb +0 -9
  65. data/lib/packaging/sign/dmg.rb +0 -41
  66. data/lib/packaging/sign/ips.rb +0 -57
  67. data/lib/packaging/sign/msi.rb +0 -124
  68. data/lib/packaging/sign/rpm.rb +0 -115
  69. data/lib/packaging/sign.rb +0 -8
  70. data/spec/lib/packaging/gem_spec.rb +0 -86
  71. data/spec/lib/packaging/sign_spec.rb +0 -133
  72. data/tasks/archive.rake +0 -69
@@ -1,126 +0,0 @@
1
- module Pkg::Archive
2
- module_function
3
-
4
- # Array of base paths for foss artifacts on weth
5
- def base_paths
6
- [Pkg::Config.yum_repo_path, Pkg::Config.apt_repo_staging_path, Pkg::Config.apt_repo_path, '/opt/downloads'].compact.freeze
7
- end
8
-
9
- # Array of paths for temporarily staging artifacts before syncing to release-archives on s3
10
- def archive_paths
11
- [Pkg::Config.yum_archive_path, Pkg::Config.apt_archive_path, Pkg::Config.freight_archive_path, Pkg::Config.downloads_archive_path, '/opt/tmp-apt'].compact.freeze
12
- end
13
-
14
- # Move yum directories from repo path to archive staging path
15
- def stage_yum_archives(directory)
16
- # /opt/repository/yum/#{directory}
17
- full_directory = File.join(Pkg::Config.yum_repo_path, directory)
18
- archive_path = File.join(Pkg::Config.yum_archive_path, directory)
19
- command = <<-CMD
20
- if [ ! -d #{full_directory} ]; then
21
- if [ -d #{archive_path} ]; then
22
- echo "Directory #{full_directory} has already been staged, skipping . . ."
23
- exit 0
24
- else
25
- echo "ERROR: Couldn't find directory #{full_directory}, exiting . . ."
26
- exit 1
27
- fi
28
- fi
29
- find #{full_directory} -type l -delete
30
- sudo chattr -i -R #{full_directory}
31
- sudo mkdir --parents #{File.dirname(archive_path)}
32
- sudo chown root:release -R #{Pkg::Config.yum_archive_path}
33
- sudo chmod g+w -R #{Pkg::Config.yum_archive_path}
34
- mv #{full_directory} #{archive_path}
35
- CMD
36
- Pkg::Util::Net.remote_execute(Pkg::Config.staging_server, command)
37
- end
38
-
39
- # Move directories from freight path (aka repo staging path) to archive staging paths
40
- def stage_apt_archives(directory)
41
- find_command = "find #{Pkg::Config.apt_repo_staging_path} -type d -name #{directory}"
42
- find_command = "find #{Pkg::Config.apt_repo_staging_path} -maxdepth 2 -type f" if directory == 'main'
43
- command = <<-CMD
44
- for stuff in $(#{find_command}); do
45
- find $stuff -type l -delete
46
- codename=$(dirname ${stuff##{Pkg::Config.apt_repo_staging_path}/})
47
- sudo mkdir --parents #{Pkg::Config.freight_archive_path}/$codename
48
- sudo chown root:release -R #{Pkg::Config.freight_archive_path}/$codename
49
- sudo chmod g+w -R #{Pkg::Config.freight_archive_path}/$codename
50
- mv $stuff #{Pkg::Config.freight_archive_path}/$codename
51
-
52
- pool_directory=#{Pkg::Config.apt_repo_path}/pool/$codename/#{directory}
53
- if [ ! -d $pool_directory ]; then
54
- echo "Can't find directory $pool_directory, it may have already been archived, skipping . . ."
55
- continue
56
- fi
57
- sudo mkdir --parents /opt/tmp-apt
58
- sudo chown root:release -R /opt/tmp-apt
59
- sudo chmod g+w -R /opt/tmp-apt
60
- mv $pool_directory /opt/tmp-apt
61
- done
62
- CMD
63
- Pkg::Util::Net.remote_execute(Pkg::Config.staging_server, command)
64
- end
65
-
66
- # Move downloads directories to archive staging path
67
- def stage_downloads_archives(directory)
68
- # /opt/downloads/#{directory}
69
- full_directory = File.join('/', 'opt', 'downloads', directory)
70
- archive_path = File.join(Pkg::Config.downloads_archive_path, directory)
71
- command = <<-CMD
72
- if [ ! -d #{full_directory} ]; then
73
- if [ -d #{archive_path} ]; then
74
- echo "Directory #{full_directory} has already been staged, skipping . . ."
75
- exit 0
76
- else
77
- echo "ERROR: Couldn't find directory #{full_directory}, exiting . . ."
78
- exit 1
79
- fi
80
- fi
81
- find #{full_directory} -type l -delete
82
- sudo chattr -i -R #{full_directory}
83
- sudo mkdir --parents #{File.dirname(archive_path)}
84
- sudo chown root:release -R #{Pkg::Config.downloads_archive_path}
85
- sudo chmod g+w -R #{Pkg::Config.downloads_archive_path}
86
- mv #{full_directory} #{archive_path}
87
- CMD
88
- Pkg::Util::Net.remote_execute(Pkg::Config.staging_server, command)
89
- end
90
-
91
- # Delete empty directories from repo paths on weth
92
- def remove_empty_directories
93
- base_paths.each do |path|
94
- command = <<-CMD
95
- for directory in $(find #{path} -type d); do
96
- if [ ! -d $directory ]; then
97
- echo "Can't find directory $directory, it was probably already deleted, skipping . . ."
98
- continue
99
- fi
100
- files=$(find $directory -type f)
101
- if [ -z "$files" ]; then
102
- echo "No files in directory $directory, deleting . . ."
103
- sudo rm -rf $directory
104
- fi
105
- done
106
- CMD
107
- Pkg::Util::Net.remote_execute(Pkg::Config.staging_server, command)
108
- end
109
- end
110
-
111
- # Delete broken symlinks from repo paths on weth
112
- def remove_dead_symlinks
113
- base_paths.each do |path|
114
- command = "find #{path} -xtype l -delete"
115
- Pkg::Util::Net.remote_execute(Pkg::Config.staging_server, command)
116
- end
117
- end
118
-
119
- # Delete artifacts from archive staging paths (after they've been synced to s3)
120
- def delete_staged_archives
121
- archive_paths.each do |archive_path|
122
- command = "sudo rm -rf #{File.join(archive_path, '*')}"
123
- Pkg::Util::Net.remote_execute(Pkg::Config.staging_server, command)
124
- end
125
- end
126
- end
@@ -1,94 +0,0 @@
1
- require 'artifactory'
2
-
3
- module ArtifactoryExtensions
4
- module ClassMethods
5
- #
6
- # Search for an artifact in a repo using an Ant-like pattern.
7
- # Unlike many Artifactory searches, this one is restricted to a single
8
- # repository.
9
- #
10
- # @example Search in a repository named 'foo_local' for an artifact in a directory containing
11
- # the word "recent", named "artifact[0-9].txt"
12
- # Artifact.pattern_search(pattern: '*recent*/artifact[0-9].txt',
13
- # repo: 'foo_local')
14
- #
15
- # @param [Hash] options
16
- # A hash of options, as follows:
17
- #
18
- # @option options [Artifactory::Client] :client
19
- # the client object to make the request with
20
- # @option options [String] :pattern
21
- # the Ant-like pattern to use for finding artifacts within the repos. Note that the
22
- # Ant pattern '**' is barred in this case by JFrog.
23
- # @option options [String] :repo
24
- # the repo to search
25
- #
26
- # @return [Array<Resource::Artifact>]
27
- # a list of artifacts that match the query
28
- #
29
- def pattern_search(options = {})
30
- client = extract_client!(options)
31
- params = Artifactory::Util.slice(options, :pattern, :repo)
32
- pattern_search_parameter = { :pattern => "#{params[:repo]}:#{params[:pattern]}" }
33
- response = client.get('/api/search/pattern', pattern_search_parameter)
34
- return [] if response['files'].nil? || response['files'].empty?
35
-
36
- # A typical response:
37
- # {
38
- # "repoUri"=>"https:<artifactory endpoint>/<repo>",
39
- # "sourcePattern"=>"<repo>:<provided search pattern>",
40
- # "files"=>[<filename that matched pattern>, ...]
41
- # }
42
- #
43
- # Inserting '/api/storage' before the repo makes the 'from_url' call work correctly.
44
- #
45
- repo_uri = response['repoUri']
46
- unless repo_uri.include?('/api/storage/')
47
- # rubocop:disable Style/PercentLiteralDelimiters
48
- repo_uri.sub!(%r(/#{params[:repo]}$), "/api/storage/#{params[:repo]}")
49
- end
50
- response['files'].map do |file_path|
51
- from_url("#{repo_uri}/#{file_path}", client: client)
52
- end
53
- end
54
-
55
- # This adds the `exact_match` option to artifactory search, and defaults it
56
- # to true. With `exact_match` set to `true` the artifact will only be
57
- # returned if the name in the download uri matches the name we're trying to
58
- # download
59
- def search(options = {})
60
- exact_match = options[:exact_match].nil? ? true : options[:exact_match]
61
- artifacts = super
62
-
63
- if exact_match
64
- artifacts.select! { |artifact| File.basename(artifact.download_uri) == options[:name] }
65
- end
66
- artifacts
67
- end
68
-
69
- # This adds the `name` option to artifactory checksum search. It defaults to
70
- # unset. If set, the artifact is only returned if the download uri matches
71
- # the passed name
72
- def checksum_search(options = {})
73
- artifacts = super
74
- if options[:name]
75
- artifacts.select! { |artifact| File.basename(artifact.download_uri) == options[:name] }
76
- end
77
- artifacts
78
- end
79
- end
80
-
81
- # needed to prepend class methods, see https://stackoverflow.com/questions/18683750/how-to-prepend-classmethods
82
- def self.prepended(base)
83
- class << base
84
- prepend ClassMethods
85
- end
86
- end
87
- end
88
-
89
- module Artifactory
90
- class Resource::Artifact
91
- # use prepend instead of monkeypatching so we can call `super`
92
- prepend ArtifactoryExtensions
93
- end
94
- end
@@ -1,13 +0,0 @@
1
- module Pkg
2
- class ConfigValidations
3
-
4
- class << self
5
-
6
- # As a validation, this one is kindof lame but is intended as a seed pattern for possibly
7
- # more robust ones.
8
- def not_empty?(value)
9
- value.to_s.empty? ? false : true
10
- end
11
- end
12
- end
13
- end
@@ -1,15 +0,0 @@
1
- module Pkg::Metrics
2
- module_function
3
-
4
- def update_release_metrics
5
- metrics_repo = 'release-metrics'
6
- command = <<CMD
7
- git clone git@github.com:puppetlabs/#{metrics_repo}.git
8
- cd #{metrics_repo}
9
- bundle exec add-release --date #{Pkg::Util::Date.today} --project #{Pkg::Config.project} --version #{Pkg::Config.ref}
10
- cd ..
11
- rm -r #{metrics_repo}
12
- CMD
13
- Pkg::Util::Execution.capture3(command, true)
14
- end
15
- end
@@ -1,9 +0,0 @@
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
@@ -1,41 +0,0 @@
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
@@ -1,57 +0,0 @@
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
@@ -1,124 +0,0 @@
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
@@ -1,115 +0,0 @@
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
@@ -1,8 +0,0 @@
1
- module Pkg::Sign
2
- require 'packaging/sign/deb'
3
- require 'packaging/sign/dmg'
4
- require 'packaging/sign/ips'
5
- require 'packaging/sign/msi'
6
- require 'packaging/sign/rpm'
7
- module_function
8
- end