simp-rake-helpers 5.11.6 → 5.12.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 (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)