simp-rake-helpers 5.11.6 → 5.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +1 -1
  5. data/lib/simp/command_utils.rb +21 -0
  6. data/lib/simp/local_gpg_signing_key.rb +128 -79
  7. data/lib/simp/rake.rb +3 -17
  8. data/lib/simp/rake/build/pkg.rb +102 -40
  9. data/lib/simp/rake/helpers/version.rb +1 -1
  10. data/lib/simp/rake/pkg.rb +5 -1
  11. data/lib/simp/rake/pupmod/helpers.rb +2 -0
  12. data/lib/simp/rake/rubygem.rb +5 -1
  13. data/lib/simp/rpm.rb +10 -127
  14. data/lib/simp/rpm_signer.rb +321 -0
  15. data/spec/acceptance/00_pkg_rpm_custom_scriptlets_spec.rb +18 -19
  16. data/spec/acceptance/10_pkg_rpm_spec.rb +46 -48
  17. data/spec/acceptance/50_local_gpg_signing_key_spec.rb +7 -3
  18. data/spec/acceptance/55_build_pkg_signing_spec.rb +293 -42
  19. data/spec/acceptance/files/testpackage/README +8 -0
  20. data/spec/acceptance/files/testpackage/spec/classes/init_spec.rb +1 -0
  21. data/spec/acceptance/files/testpackage/spec/files/mock_something.rb +3 -0
  22. data/spec/acceptance/files/testpackage/utils/convert_v1_to_v2.rb +3 -0
  23. data/spec/acceptance/nodesets/default.yml +15 -2
  24. data/spec/acceptance/support/build_project_helpers.rb +32 -8
  25. data/spec/lib/simp/command_utils_spec.rb +29 -0
  26. data/spec/lib/simp/local_gpg_signing_key_spec.rb.beaker-only +115 -18
  27. data/spec/lib/simp/rake/pupmod/fixtures/simpmod/README.md +2 -2
  28. data/spec/lib/simp/rpm_signer_spec.rb +98 -0
  29. data/spec/lib/simp/rpm_spec.rb +0 -6
  30. metadata +12 -67
  31. data/.travis.yml +0 -41
  32. data/spec/acceptance/20_pkg_rpm_upgrade_spec.rb +0 -236
  33. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-2.1/CHANGELOG +0 -2
  34. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-2.1/Rakefile +0 -3
  35. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-2.1/build/rpm_metadata/custom/overrides +0 -14
  36. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-2.1/build/rpm_metadata/requires +0 -1
  37. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-2.1/metadata.json +0 -33
  38. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-3.0/CHANGELOG +0 -2
  39. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-3.0/Rakefile +0 -3
  40. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-3.0/build/rpm_metadata/custom/overrides +0 -14
  41. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-3.0/build/rpm_metadata/requires +0 -1
  42. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-new-package-3.0/metadata.json +0 -33
  43. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-1.0/CHANGELOG +0 -2
  44. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-1.0/Rakefile +0 -3
  45. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-1.0/build/rpm_metadata/requires +0 -1
  46. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-1.0/metadata.json +0 -33
  47. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.0/CHANGELOG +0 -2
  48. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.0/Rakefile +0 -3
  49. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.0/build/rpm_metadata/requires +0 -1
  50. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.0/metadata.json +0 -33
  51. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.2/CHANGELOG +0 -2
  52. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.2/Rakefile +0 -3
  53. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.2/build/rpm_metadata/custom/overrides +0 -14
  54. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.2/build/rpm_metadata/requires +0 -1
  55. data/spec/acceptance/files/custom_scriptlet_triggers/pupmod-old-package-2.2/metadata.json +0 -33
  56. data/spec/acceptance/files/mock_packages/pupmod-puppetlabs-stdlib.spec +0 -32
  57. data/spec/acceptance/files/mock_packages/pupmod-simp-foo.spec +0 -32
  58. data/spec/acceptance/files/mock_packages/pupmod-simp-simplib.spec +0 -32
  59. data/spec/acceptance/files/mock_packages/rpmbuild.sh +0 -25
  60. data/spec/acceptance/files/mock_packages/simp-adapter.spec +0 -43
  61. data/spec/acceptance/files/mock_packages/simp-adapter/etc/simp/adapter_config.yaml +0 -3
  62. data/spec/acceptance/files/mock_packages/simp-adapter/usr/local/sbin/simp_rpm_helper +0 -495
  63. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/CHANGELOG +0 -2
  64. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/Rakefile +0 -3
  65. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/build/rpm_metadata/requires +0 -2
  66. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/data/os/CentOS.yaml +0 -2
  67. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/data/os/RedHat.yaml +0 -2
  68. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/hiera.yaml +0 -14
  69. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/manifests/init.pp +0 -2
  70. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-1.0/metadata.json +0 -37
  71. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/CHANGELOG +0 -5
  72. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/Rakefile +0 -3
  73. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/build/rpm_metadata/requires +0 -2
  74. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/data/os/CentOS.yaml +0 -2
  75. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/data/os/RedHat.yaml +0 -2
  76. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/hiera.yaml +0 -14
  77. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/manifests/init.pp +0 -3
  78. data/spec/acceptance/files/package_upgrades/pupmod-simp-testpackage-2.0/metadata.json +0 -37
  79. data/spec/lib/simp/ci/files/job_broken_link_nodeset/spec/acceptance/suites/default/nodesets +0 -1
  80. data/spec/lib/simp/ci/files/job_invalid_nodeset/spec/acceptance/suites/default/nodesets +0 -1
  81. data/spec/lib/simp/ci/files/job_invalid_suite/spec/acceptance/suites/default/nodesets +0 -1
  82. data/spec/lib/simp/ci/files/job_missing_nodeset/spec/acceptance/suites/default/nodesets +0 -1
  83. data/spec/lib/simp/ci/files/job_missing_suite_and_nodeset/spec/acceptance/suites/default/nodesets +0 -1
  84. data/spec/lib/simp/ci/files/multiple_invalid_jobs/spec/acceptance/suites/default/nodesets +0 -1
  85. data/spec/lib/simp/ci/files/multiple_valid_jobs/spec/acceptance/suites/default/nodesets +0 -1
  86. data/spec/lib/simp/ci/files/no_gitlab_config_with_tests/spec/acceptance/suites/default/nodesets +0 -1
  87. data/spec/lib/simp/ci/files/no_gitlab_config_without_tests/spec/acceptance/suites/default/nodesets +0 -1
  88. data/spec/lib/simp/ci/files/suite_skeleton_only/spec/acceptance/nodesets/default.yml +0 -1
  89. data/spec/lib/simp/ci/files/suite_skeleton_only/spec/acceptance/suites/default/nodesets +0 -1
  90. data/spec/lib/simp/ci/files/valid_job_nodeset_dir_link/spec/acceptance/suites/default/nodesets +0 -1
  91. data/spec/lib/simp/ci/files/valid_job_nodeset_link/spec/acceptance/suites/default/nodesets/default.yml +0 -1
  92. data/spec/lib/simp/files/build/testpackage.spec +0 -1
  93. data/spec/lib/simp/rake/pupmod/fixtures/simpmod/spec/acceptance/nodesets/default.yml +0 -1
  94. data/spec/lib/simp/rake/pupmod/fixtures/simpmod/spec/acceptance/suites/default/nodesets +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd1fc58d4764acdc2a2160e63a50a2a16015c1dd2a41f7b530baad394d6a397e
4
- data.tar.gz: 6f322c3850b40ff56c8aa49a86146a176311e999495ada8cc8270ecf806f2d81
3
+ metadata.gz: 1d979c12113e415884ec44b2880134bde9e20a3efc99495520e3518a994118f6
4
+ data.tar.gz: f9da255f0c077f662f00757ca2428b9375b1b4bd2d39de1b484c1a047d87c1f4
5
5
  SHA512:
6
- metadata.gz: d58adb8bae7eba07b696cbfd3add6ce335672a7ddc6d9063f6057ca3da8f23e5492d6cecb805afe13104f377fac3c16cc38a8925791eef9c3f2543017c609bcf
7
- data.tar.gz: baaf3228b15df258dcdd6030f7fa95d995ac4a08cf735218cbc941543eef389c881f9f31bed619d605b230da154fee39353eabcebb9165cbb70f3b44b88e595a
6
+ metadata.gz: 493c503f1ead3608b3718e113188ef08af8905d96fd7297f439adc4809c44e70f4ec6b1c3d08c1eb09458ef4ab1499db61ec3519f1d18ab297e1b8812c5620d1
7
+ data.tar.gz: bf8bd8cbbf5c36ac268a23e346554a6f7132523f5f32a3f76162fdc8d77dd01898362d51dadd6012e2e07efb08e61737c1398c123e09092b422b94e631a0b43a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ ### 5.12.0 / 2021-02-16
2
+ - Ensure that pkg:install_gem uses the correct documentation options for the
3
+ version of Ruby in use.
4
+ - Disable brp-mangle-shebangs when building RPMs.
5
+ - Mitigated problem where gpg-agent daemon fails to start because
6
+ its socket path is longer than 108 characters.
7
+ - Changed the default location of the GPG keys directory used in the
8
+ pkg:key_prep and pkg:signrpms Rake tasks to <base_dir>/.dev_gpgkeys.
9
+ - Added a SIMP_PKG_build_keys_dir environment variable that overrides
10
+ the default location of the GPG keys directory used in the
11
+ pkg:key_prep and pkg:signrpms Rake tasks.
12
+ - Added SIMP_PKG_rpmsign_timeout environment variable that overrides
13
+ default timeout in seconds to wait for an individual RPM signing
14
+ operation to complete.
15
+ - Default timeout is 30 seconds.
16
+ - Most relevant when signing on RPMs on EL8 and the gpg-agent
17
+ started by rpmsign fails to start, but rpmsign does not detect
18
+ the failure and hangs.
19
+ - Improved pkg:signrpms error handling and reporting.
20
+ - Fixed bug in GPG handling for GPG 2.1+ in which an existing
21
+ GPG key that was not cached internally was not detected.
22
+ - Fixed bug where pkg:signrpms failed to sign RPMs on EL8.
23
+ - Fixed bug where pkg:checksig reported failure on EL8, even when
24
+ the signatures were valid.
25
+ - Deprecated the following top-level Rake tasks for Puppet modules:
26
+ - compare_latest_tag: use pkg:compare_latest_tag instead
27
+ - changelog_annotation: use pkg:create_tag_changelog instead
28
+
1
29
  ### 5.11.6 / 2021-02-03
2
30
  * Fix GPG handling for GPG 2.1+
3
31
 
data/CONTRIBUTING.md CHANGED
@@ -1,4 +1,4 @@
1
1
  ## Contributing
2
2
 
3
- Please refer to the main [SIMP Project Contributing Guide](https://github.com/NationalSecurityAgency/SIMP/blob/master/CONTRIBUTING.md)
3
+ Please refer to the main [SIMP Project Contributing Guide](https://simp-doc.readthedocs.io/en/stable/contributors_guide/index.html)
4
4
  for details on contributing to this project.
data/README.md CHANGED
@@ -39,7 +39,7 @@ The `simp-rake-helpers` gem provides common Rake tasks to support the SIMP build
39
39
 
40
40
  ### This gem is part of SIMP
41
41
 
42
- This gem is part of (the build tooling for) the [System Integrity Management Platform](https://github.com/NationalSecurityAgency/SIMP), a compliance-management framework built on [Puppet](https://puppetlabs.com/).
42
+ This gem is part of (the build tooling for) the [System Integrity Management Platform](https://simp-project.com), a compliance-management framework built on [Puppet](https://puppetlabs.com/).
43
43
 
44
44
 
45
45
  ### Features
@@ -0,0 +1,21 @@
1
+ module Simp; end
2
+ module Simp::CommandUtils
3
+ require 'facter'
4
+
5
+ def which(cmd, fail=false)
6
+ @which_cache ||= {}
7
+
8
+ if @which_cache.has_key?(cmd)
9
+ command = @which_cache[cmd]
10
+ else
11
+ command = Facter::Core::Execution.which(cmd)
12
+ @which_cache[cmd] = command
13
+ end
14
+
15
+ msg = "Warning: Command #{cmd} not found on the system."
16
+
17
+ ( fail ? raise(msg) : warn(msg) ) unless command
18
+
19
+ command
20
+ end
21
+ end
@@ -1,5 +1,6 @@
1
1
  require 'securerandom'
2
2
  require 'rake'
3
+ require 'simp/command_utils'
3
4
 
4
5
  module Simp
5
6
  # Ensure that a valid GPG signing key exists in a local directory
@@ -14,49 +15,52 @@ module Simp
14
15
  # - New keys are generated using a temporary GPG agent with its own
15
16
  # settings and socket.
16
17
  #
17
- # The local signing key's directory is structured like this:
18
+ # The local signing key's directory includes the following:
19
+ # gpg < 2.1.0 (EL7):
18
20
  #
19
21
  # ```
20
22
  # #{key_name}/ # key directory
21
23
  # +-- RPM-GPG-KEY-SIMP-#{key_name} # key file
22
24
  # +-- gengpgkey # --gen-key params file **
25
+ # +-- gpg-agent-info.env # Lists location of gpg-agent socket + pid
26
+ # +-- run_gpg_agnet # Script used to start gpg-agent
23
27
  # +-- pubring.gpg
24
28
  # +-- secring.gpg
25
- # +-- trustring.gpg
29
+ # +-- trustdb.gpg
26
30
  # ```
27
31
  #
28
- # `**` = `SIMP::RPM.sign_keys` will use the values in the `gengpgkey` file
32
+ # gpg >= 2.1.0 (EL8):
33
+ # ```
34
+ # #{key_name}/ # key directory
35
+ # +-- RPM-GPG-KEY-SIMP-#{key_name} # key file
36
+ # +-- gengpgkey # --gen-key params file **
37
+ # +-- openpgp-revocs.d/<fingerprint id>.rev
38
+ # +-- private-keys-v1.d/<user id>.key
39
+ # +-- pubring.kbx
40
+ # +-- trustdb.gpg
41
+ # ```
42
+ #
43
+ # `**` = `SIMP::RpmSigner.sign_rpms` will use the values in the `gengpgkey` file
29
44
  # for the GPG signing key's email and passphrase
30
45
  #
31
46
  # If a new key is required, a project-only `gpg-agent` daemon is momentarily
32
47
  # created to generate it, and destroyed after this is done. The daemon does
33
- # not interact with any other `gpg-agent` daemons on the system--it is
34
- # launched on a random socket and keeps all its files under the
35
- # #{key_name/} directory.
36
- #
37
- # When instantiated, the daemon writes an "env-file" to the #{key_name}
38
- # directory. This file specifies the location of the daemon's socket and
39
- # pid.
40
- #
41
- # A typical env-file looks like:
42
- #
43
- # ```sh
44
- # GPG_AGENT_INFO=/tmp/gpg-4yhfOB/S.gpg-agent:15495:1
45
- # ```
48
+ # not interact with any other `gpg-agent` daemons on the system. It is
49
+ # launched on random socket(s) whose socket file(s) can be found as follows:
46
50
  #
47
- # A brand-new gpg-agent daemon will output similar information, with an
48
- # additional export:
51
+ # Location Environment
52
+ # #{key_name} dir Docker container for EL8
53
+ # temp dir in /run/user/<uid>/gnupg EL8
54
+ # temp dir in /tmp EL7
49
55
  #
50
- # ```sh
51
- # GPG_AGENT_INFO=/tmp/gpg-4yhfOB/S.gpg-agent:15495:1; export GPG_AGENT_INFO;\n"
52
- # ```
53
56
  class LocalGpgSigningKey
54
57
  include FileUtils
58
+ include Simp::CommandUtils
55
59
 
56
- # `SIMP::RPM.sign_keys` will look for a 'gengpgkey' file to
60
+ # `SIMP::RpmSigner.sign_rpms` will look for a 'gengpgkey' file to
57
61
  # non-interactively sign packages.
58
62
  #
59
- # @see SIMP::RPM.sign_keys
63
+ # @see SIMP::RpmSigner.sign_rpms
60
64
  GPG_GENKEY_PARAMS_FILENAME = 'gengpgkey'.freeze
61
65
 
62
66
  # @param dir [String] path to gpg-agent / key directory
@@ -74,11 +78,12 @@ module Simp
74
78
  @key_file = opts[:file] || "RPM-GPG-KEY-SIMP-#{@label.capitalize}"
75
79
  @verbose = opts[:verbose] || false
76
80
 
81
+ # for EL7 only
77
82
  @gpg_agent_env_file = 'gpg-agent-info.env'
78
83
  @gpg_agent_script = 'run_gpg_agent'
79
84
  end
80
85
 
81
- # Return the version of GPG instealled on the system
86
+ # Return the version of GPG installed on the system
82
87
  #
83
88
  # @return [Gem::Version]
84
89
  def gpg_version
@@ -111,17 +116,45 @@ module Simp
111
116
  info
112
117
  end
113
118
 
114
- # Return the number of days left before the GPG signing key expires
119
+ # Return the number of days left before the GPG signing key expires or
120
+ # 0 if the key does not exist or the key is missing an expiration date.
115
121
  def dev_key_days_left
122
+ which('gpg', true)
116
123
  ensure_gpg_directory
117
- days_left = 0
118
124
 
119
- which('gpg', true)
120
- current_key = %x(GPG_AGENT_INFO='' gpg --homedir=#{@dir} --list-keys #{@key_email} 2>/dev/null)
121
- unless current_key.empty?
122
- lasts_until = current_key.lines.first.strip.split("\s").last.delete(']')
123
- days_left = (Date.parse(lasts_until) - Date.today).to_i
125
+ days_left = 0
126
+ cmd = "gpg --with-colons --homedir=#{@dir} --list-keys '<#{@key_email}>' 2>&1"
127
+ puts "Executing: #{cmd}" if @verbose
128
+ %x(#{cmd}).each_line do |line|
129
+ # See https://github.com/CSNW/gnupg/blob/master/doc/DETAILS
130
+ # Index Content
131
+ # 0 record type
132
+ # 6 expiration date
133
+ #
134
+ # If expiration date contains a 'T', it is in an ISO 8601 format
135
+ # (e.g., 20210223T091500). Otherwise it is seconds since the epoch.
136
+ #
137
+ fields = line.split(':')
138
+ if fields[0] && (fields[0] == 'pub')
139
+ raw_exp_date = fields[6]
140
+ unless raw_exp_date.nil? || raw_exp_date.strip.empty?
141
+ require 'date'
142
+
143
+ exp_date = nil
144
+ if raw_exp_date.include?('T')
145
+ exp_date = DateTime.parse(raw_exp_date).to_date
146
+ else
147
+ exp_date = Time.at(raw_exp_date.to_i).to_date
148
+ end
149
+
150
+ days_left = (exp_date - Date.today).to_i
151
+ days_left = 0 if days_left < 0
152
+ end
153
+
154
+ break
155
+ end
124
156
  end
157
+
125
158
  days_left
126
159
  end
127
160
 
@@ -153,55 +186,16 @@ module Simp
153
186
 
154
187
  clean_gpg_agent_directory
155
188
  write_genkey_parameter_file
156
- write_gpg_agent_startup_script
157
189
 
190
+ agent_info = nil
158
191
  begin
159
192
  if gpg_version < Gem::Version.new('2.1')
160
- # Start the GPG agent.
161
- gpg_agent_output = %x(./#{@gpg_agent_script}).strip
162
-
163
- # Provide a local socket (needed by the `gpg` command when
164
- local_socket = File.join(Dir.pwd, 'S.gpg-agent')
165
-
166
- # This condition was handled differently in previous logic.
167
- #
168
- # a.) As the surrounding logic works now, it will _always_ be a new
169
- # agent by this point, because the directory is cleaned out
170
- # b.) The agent's information will be read from the env-file it
171
- # writes at startup
172
- # c.) The old command `gpg-agent --homedir=#{Dir.pwd} /get serverpid`
173
- # did not work on EL6 or EL7.
174
- #
175
- warn(empty_gpg_agent_message) if gpg_agent_output.empty?
176
-
177
- agent_info = gpg_agent_info
178
-
179
- # The socket is useful to get back info on the command line.
180
- unless File.exist?(File.join(Dir.pwd, File.basename(agent_info[:socket])))
181
- ln_s(agent_info[:socket], local_socket, :verbose => @verbose)
182
- end
183
-
184
- generate_key(agent_info[:info])
193
+ agent_info = start_gpg_agent_old
185
194
  else
186
- which('gpg', true)
187
- which('gpg-agent', true)
188
- which('gpg-connect-agent', true)
189
-
190
- # Start the GPG agent
191
- %x{gpg-agent --homedir=#{Dir.pwd} >&/dev/null || gpg-agent --homedir=#{Dir.pwd} --daemon >&/dev/null}
192
-
193
- agent_info = {}
194
-
195
- # Provide a local socket (needed by the `gpg` command when
196
- agent_info[:socket] = %x{echo 'GETINFO socket_name' | gpg-connect-agent --homedir=#{Dir.pwd}}.lines.first[1..-1].strip
197
-
198
- # Get the pid
199
- agent_info[:pid] = %x{echo 'GETINFO pid' | gpg-connect-agent --homedir=#{Dir.pwd}}.lines.first[1..-1].strip.to_i
200
-
201
- generate_key(%{#{agent_info[:socket]}:#{agent_info[:pid]}:1})
195
+ agent_info = start_gpg_agent
202
196
  end
203
197
  ensure
204
- kill_agent(agent_info[:pid])
198
+ kill_agent(agent_info[:pid]) if agent_info
205
199
  end
206
200
 
207
201
  agent_info
@@ -213,7 +207,7 @@ module Simp
213
207
  #
214
208
  # @return [String] Warning message
215
209
  def empty_gpg_agent_message
216
- <<-WARNING.gsub(/^\s{8}/,'')
210
+ <<~WARNING
217
211
  WARNING: Tried to start an project-only gpg-agent daemon on a random socket by
218
212
  running the script:
219
213
 
@@ -234,7 +228,6 @@ module Simp
234
228
  #
235
229
  # @param pid [String] The GPG Agent PID to kill
236
230
  def kill_agent(pid)
237
- rm('S.gpg-agent') if File.symlink?('S.gpg-agent')
238
231
  if pid
239
232
  Process.kill(0, pid)
240
233
  Process.kill(15, pid)
@@ -254,8 +247,8 @@ module Simp
254
247
  gpg_cmd = %(GPG_AGENT_INFO=#{gpg_agent_info_str} gpg --homedir="#{@dir}")
255
248
 
256
249
  pipe = @verbose ? '| tee' : '>'
257
- sh %(#{gpg_cmd} --batch --gen-key #{GPG_GENKEY_PARAMS_FILENAME})
258
- sh %(#{gpg_cmd} --armor --export #{@key_email} #{pipe} "#{@key_file}")
250
+ %x(#{gpg_cmd} --batch --gen-key #{GPG_GENKEY_PARAMS_FILENAME})
251
+ %x(#{gpg_cmd} --armor --export '<#{@key_email}>' #{pipe} "#{@key_file}")
259
252
 
260
253
  if File.stat(@key_file).size == 0
261
254
  fail "Error: Something went wrong generating #{@key_file}"
@@ -271,6 +264,62 @@ module Simp
271
264
  { info: info.strip, socket: matches[:socket], pid: matches[:pid].to_i }
272
265
  end
273
266
 
267
+ # Start the gpg-agent
268
+ # @return Hash of agent info
269
+ # @raise if gpg-agent fails to start
270
+ def start_gpg_agent
271
+ which('gpg', true)
272
+ which('gpg-agent', true)
273
+ which('gpg-connect-agent', true)
274
+
275
+ # Start the GPG agent, if it is not already running
276
+ check_agent = "gpg-agent -q --homedir=#{Dir.pwd} >&/dev/null"
277
+ start_agent = "gpg-agent --homedir=#{Dir.pwd} --daemon >&/dev/null"
278
+ cmd = "#{check_agent} || #{start_agent}"
279
+ puts "Executing: #{cmd}" if @verbose
280
+ %x(#{cmd})
281
+ if $? && ($?.exitstatus != 0)
282
+ err_msg = [
283
+ 'Failed to start gpg-agent during key creation.',
284
+ " Execute '#{start_agent.gsub(' >&/dev/null','')}' to debug."
285
+ ].join("\n")
286
+ raise(err_msg)
287
+ end
288
+
289
+ agent_info = {}
290
+
291
+ # Provide a local socket (needed by the `gpg` command when
292
+ agent_info[:socket] = %x{echo 'GETINFO socket_name' | gpg-connect-agent --homedir=#{Dir.pwd}}.lines.first[1..-1].strip
293
+
294
+ # Get the pid
295
+ agent_info[:pid] = %x{echo 'GETINFO pid' | gpg-connect-agent --homedir=#{Dir.pwd}}.lines.first[1..-1].strip.to_i
296
+
297
+ generate_key(%{#{agent_info[:socket]}:#{agent_info[:pid]}:1})
298
+
299
+ agent_info
300
+ end
301
+
302
+ # Start the gpg-agent with options suitable for gpg version < 2.1
303
+ # @return Hash of agent info
304
+ def start_gpg_agent_old
305
+ write_gpg_agent_startup_script
306
+ gpg_agent_output = %x(./#{@gpg_agent_script}).strip
307
+
308
+ # By the time we get here, we can be assured we will be starting a
309
+ # new agent, because the directory is cleaned out.
310
+ #
311
+ # Follow-on gpg actions will read the agent's information from
312
+ # the env-file the agent writes at startup.
313
+
314
+ # We're using the --sh option which will spew out the agent config
315
+ # when the agent starts. If it is empty, this is a problem.
316
+ warn(empty_gpg_agent_message) if gpg_agent_output.empty?
317
+
318
+ agent_info = gpg_agent_info
319
+ generate_key(agent_info[:info])
320
+ agent_info
321
+ end
322
+
274
323
  # Write the `gpg --genkey --batch` control parameter file
275
324
  #
276
325
  # @see "Unattended key generation" in /usr/share/doc/gnupg2-*/DETAILS for
@@ -311,7 +360,7 @@ module Simp
311
360
  which('gpg-agent', true)
312
361
  pinentry_cmd = which('pinentry-curses', true)
313
362
 
314
- gpg_agent_script = <<-AGENT_SCRIPT.gsub(%r{^ {20}}, '')
363
+ gpg_agent_script = <<~AGENT_SCRIPT
315
364
  #!/bin/sh
316
365
 
317
366
  gpg-agent --homedir=#{Dir.pwd} --daemon \
data/lib/simp/rake.rb CHANGED
@@ -9,9 +9,12 @@ module Simp::Rake
9
9
  require 'parallel'
10
10
  require 'tempfile'
11
11
  require 'facter'
12
+ require 'simp/command_utils'
12
13
  require 'simp/rpm'
13
14
  require 'simp/rake/pkg'
14
15
 
16
+ include Simp::CommandUtils
17
+
15
18
  attr_reader(:puppetfile)
16
19
  attr_reader(:module_paths)
17
20
 
@@ -96,23 +99,6 @@ module Simp::Rake
96
99
  exec pager rescue exec "/bin/sh", "-c", pager
97
100
  end
98
101
 
99
- def which(cmd, fail=false)
100
- @which_cache ||= {}
101
-
102
- if @which_cache.has_key?(cmd)
103
- command = @which_cache[cmd]
104
- else
105
- command = Facter::Core::Execution.which(cmd)
106
- @which_cache[cmd] = command
107
- end
108
-
109
- msg = "Warning: Command #{cmd} not found on the system."
110
-
111
- fail ? raise(msg) : warn(msg) unless command
112
-
113
- command
114
- end
115
-
116
102
  def help
117
103
  run_pager
118
104
 
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/rake -T
2
2
 
3
3
  require 'simp/yum'
4
- require 'simp/local_gpg_signing_key.rb'
5
4
  require 'simp/rake/pkg'
6
5
  require 'simp/rake/build/constants'
7
6
  require 'simp/rake/build/rpmdeps'
@@ -17,9 +16,18 @@ module Simp::Rake::Build
17
16
  def initialize( base_dir )
18
17
  init_member_vars( base_dir )
19
18
 
19
+ @cpu_limit = get_cpu_limit
20
20
  @verbose = ENV.fetch('SIMP_PKG_verbose','no') == 'yes'
21
21
  @rpm_build_metadata = 'last_rpm_build_metadata.yaml'
22
22
  @rpm_dependency_file = File.join(@base_dir, 'build', 'rpm', 'dependencies.yaml')
23
+ @build_keys_dir = ENV.fetch('SIMP_PKG_build_keys_dir', File.join(@base_dir, '.dev_gpgkeys'))
24
+ @long_gpg_socket_err_msg = <<~EOM
25
+ If the problem is 'socket name <xxx> is too long', use SIMP_PKG_build_keys_dir
26
+ to override
27
+ #{@build_keys_dir}
28
+ with a shorter path. The socket name must be < 108 characters.
29
+
30
+ EOM
23
31
 
24
32
  define_tasks
25
33
  end
@@ -66,7 +74,7 @@ module Simp::Rake::Build
66
74
  @build_dirs.each_pair do |k,dirs|
67
75
  Parallel.map(
68
76
  Array(dirs),
69
- :in_processes => get_cpu_limit,
77
+ :in_processes => @cpu_limit,
70
78
  :progress => t.name
71
79
  ) do |dir|
72
80
  Dir.chdir(dir) do
@@ -95,7 +103,7 @@ module Simp::Rake::Build
95
103
  @build_dirs.each_pair do |k,dirs|
96
104
  Parallel.map(
97
105
  Array(dirs),
98
- :in_processes => get_cpu_limit,
106
+ :in_processes => @cpu_limit,
99
107
  :progress => t.name
100
108
  ) do |dir|
101
109
  Dir.chdir(dir) do
@@ -109,36 +117,49 @@ module Simp::Rake::Build
109
117
  desc <<-EOM
110
118
  Prepare a GPG signing key to sign build packages
111
119
 
112
- * :key - the name of the directory under build/build_keys to
113
- prepare (defaults to 'dev')
120
+ * :key - the name of the build keys subdirectory to prepare
121
+ (defaults to 'dev')
122
+
123
+ - The default build keys directory is
124
+ `#{@build_keys_dir}`
125
+
114
126
 
115
127
  When :key is `dev`, a temporary signing key is created, if needed:
116
128
 
117
- - A 14-day `dev` key will be created if none exists, including:
118
- - The `<build_dir>/build_keys/dev/` dir
119
- - gpgagent assets to create/update the key
129
+ * A 14-day `dev` key will be created if none exists or the existing
130
+ key has expired. This includes creating
131
+ - A `dev` directory in the build keys directory
132
+ - gpg-agent assets to create/update the key within that `dev`
133
+ directory
120
134
 
121
135
  When :key is *not* `dev`, the logic is much stricter:
122
136
 
123
- - You must already have create `<build_dir>/build_keys/<:key>/`
124
- directoy, and placed a valid GPG signing key inside
137
+ - You must already have created the `<:key>` subdirectory within
138
+ the build keys directory and placed a valid GPG signing key and
139
+ requisite gpg-agent assets to access the key within the directory.
125
140
  - If the directory or key are missing, the task will fail.
126
141
 
127
142
  ENV vars:
128
143
  - Set `SIMP_PKG_verbose=yes` to report file operations as they happen.
144
+ - Set `SIMP_PKG_build_keys_dir` to override the default build keys path.
129
145
  EOM
130
146
  task :key_prep,[:key] => [:prep] do |t,args|
131
147
  args.with_defaults(:key => 'dev')
132
148
  key = args.key
133
- build_keys_dir = File.join(@build_dir, 'build_keys')
134
- key_dir = File.join(build_keys_dir,key)
149
+ key_dir = File.join(@build_keys_dir,key)
135
150
  dvd_dir = @dvd_src
136
151
 
137
- FileUtils.mkdir_p build_keys_dir
152
+ FileUtils.mkdir_p @build_keys_dir
138
153
 
139
- Dir.chdir(build_keys_dir) do
154
+ Dir.chdir(@build_keys_dir) do
140
155
  if key == 'dev'
141
- Simp::LocalGpgSigningKey.new(key_dir,{verbose: @verbose}).ensure_key
156
+ require 'simp/local_gpg_signing_key'
157
+
158
+ begin
159
+ Simp::LocalGpgSigningKey.new(key_dir,{verbose: @verbose}).ensure_key
160
+ rescue Exception => e
161
+ raise("#{e.message}\n\n#{@long_gpg_socket_err_msg}")
162
+ end
142
163
  else
143
164
  unless File.directory?(key_dir)
144
165
  fail("Could not find GPG keydir '#{key_dir}' in '#{Dir.pwd}'")
@@ -356,41 +377,79 @@ module Simp::Rake::Build
356
377
  Sign a set of RPMs.
357
378
 
358
379
  Signs any unsigned RPMs in the specified directory
359
- * :key - The key directory to use under #{@build_dir}/build_keys
360
- * Defaults to #{File.join(File.dirname(@rpm_dir), '*RPMS')}
380
+ * :key - The key directory to use under the build keys directory
381
+ * key defaults to 'dev'
382
+ * build keys directory defaults to
383
+ `#{@build_keys_dir}`
361
384
  * :rpm_dir - A directory containing RPM files to sign. Will recurse!
362
- * Defaults to 'dev'
385
+ * Defaults to #{File.join(File.dirname(@rpm_dir), '*RPMS')}
363
386
  * :force - Force rpms that are already signed to be resigned
364
387
  * Defaults to 'false', can be enabled with 'true'
388
+ * :digest_algo - Digest algorithm to be used when signing the RPMs
389
+ * Defaults to 'sha256'
390
+
391
+ ENV vars:
392
+ * Set `SIMP_RPM_verbose=yes` to report RPM operations as they happen.
393
+ * Set `SIMP_PKG_build_keys_dir` to override the default build keys path.
394
+ * Set `SIMP_PKG_rpmsign_timeout` to override the maximum time in seconds
395
+ to wait for an individual RPM signing operation to complete.
396
+ - Defaults to 60 seconds.
365
397
  EOM
366
- task :signrpms,[:key,:rpm_dir,:force] => [:prep,:key_prep] do |t,args|
367
- which('rpmsign') || raise(StandardError, 'Could not find rpmsign on your system. Exiting.')
398
+ task :signrpms,[:key,:rpm_dir,:force,:digest_algo] => [:prep,:key_prep] do |t,args|
399
+ require 'simp/rpm_signer'
368
400
 
369
401
  args.with_defaults(:key => 'dev')
370
402
  args.with_defaults(:rpm_dir => File.join(File.dirname(@rpm_dir), '*RPMS'))
371
403
  args.with_defaults(:force => 'false')
404
+ args.with_defaults(:digest_algo => 'sha256')
372
405
 
373
406
  force = (args[:force].to_s == 'false' ? false : true)
407
+ timeout = ENV['SIMP_PKG_rpmsign_timeout'] ? ENV['SIMP_PKG_rpmsign_timeout'].to_i : 60
408
+
409
+ opts = {
410
+ :digest_algo => args[:digest_algo],
411
+ :force => force,
412
+ :max_concurrent => @cpu_limit,
413
+ :progress_bar_title => t.name,
414
+ :timeout_seconds => timeout,
415
+ :verbose => @verbose
416
+ }
374
417
 
375
- rpm_dirs = Dir.glob(args[:rpm_dir])
376
- to_sign = []
418
+ results = nil
419
+ begin
420
+ results = Simp::RpmSigner.sign_rpms(
421
+ args[:rpm_dir],
422
+ File.join(@build_keys_dir, args[:key]),
423
+ opts
424
+ )
425
+ rescue Exception => e
426
+ raise("#{e.message}\n\n#{@long_gpg_socket_err_msg}")
427
+ end
377
428
 
378
- rpm_dirs.each do |rpm_dir|
379
- Find.find(rpm_dir) do |rpm|
380
- next unless File.readable?(rpm)
381
- to_sign << rpm if rpm =~ /\.rpm$/
429
+ if results
430
+ successes = results.select { |rpm,status| status == :signed }
431
+ failures = results.select { |rpm,status| status == :unsigned }
432
+ already_signed = results.select { |rpm,status| status == :skipped_already_signed }
433
+
434
+ if opts[:verbose]
435
+ puts
436
+ puts 'Summary'
437
+ puts '======='
438
+ puts "# RPMs already signed: #{already_signed.size}"
439
+ puts "# RPMs successfully signed: #{successes.size}"
440
+ puts "# RPM signing failures: #{failures.size}"
441
+ puts
382
442
  end
383
- end
384
443
 
385
- Parallel.map(
386
- to_sign,
387
- :in_processes => get_cpu_limit,
388
- :progress => t.name
389
- ) do |rpm|
390
- rpm_info = Simp::RPM.new(rpm)
391
-
392
- if force || !rpm_info.signature
393
- Simp::RPM.signrpm(rpm, "#{@build_dir}/build_keys/#{args[:key]}")
444
+ if !failures.empty?
445
+ if ((results.size - already_signed.size) == (failures.size))
446
+ detail = already_signed.empty? ? '' : 'unsigned '
447
+ raise("ERROR: Failed to sign all #{detail}RPMs in #{args[:rpm_dir]}")
448
+ else
449
+ err_msg = "ERROR: Failed to sign some RPMs in #{args[:rpm_dir]}:\n"
450
+ err_msg += " #{failures.keys.join("\n ")}"
451
+ raise(err_msg)
452
+ end
394
453
  end
395
454
  end
396
455
  end
@@ -446,7 +505,9 @@ module Simp::Rake::Build
446
505
  $stderr.puts "pkg:checksig: Warning no GPG keys found in #{key_dirs_tried}"
447
506
  end
448
507
  end
449
- public_keys += Dir.glob(File.join(@build_dir, 'build_keys', '*', 'RPM-GPG-KEY*'))
508
+
509
+ # be sure to include any development keys packaged with the DVD
510
+ public_keys += Dir.glob(File.join(@dvd_src, 'RPM-GPG-KEY*'))
450
511
 
451
512
  # Only import thngs that look like GPG keys...
452
513
  public_keys.each do |key|
@@ -464,8 +525,9 @@ module Simp::Rake::Build
464
525
  rpm_dirs.each do |rpm_dir|
465
526
  Find.find(rpm_dir) do |path|
466
527
  if (path =~ /.*\.rpm$/)
467
- result = %x{#{rpm_cmd} --checksig #{path}}.strip
468
- if result !~ /:.*\(\S+\).* OK$/
528
+ %x{#{rpm_cmd} --checksig #{path}}.strip
529
+ result = $?
530
+ unless result && (result.exitstatus == 0)
469
531
  bad_rpms << path.split(/\s/).first
470
532
  end
471
533
  end
@@ -862,7 +924,7 @@ protect=1
862
924
  Parallel.map(
863
925
  # Allow for shell globs
864
926
  Array(dirs),
865
- :in_processes => get_cpu_limit,
927
+ :in_processes => @cpu_limit,
866
928
  :progress => task.name
867
929
  ) do |dir|
868
930
  fail("Could not find directory #{dir}") unless Dir.exist?(dir)