packaging 0.99.2 → 0.99.3

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.
@@ -1,56 +1,12 @@
1
- def sign_rpm(rpm, sign_flags = nil)
2
-
3
- # To enable support for wrappers around rpm and thus support for gpg-agent
4
- # rpm signing, we have to be able to tell the packaging repo what binary to
5
- # use as the rpm signing tool.
6
- #
7
- rpm_cmd = ENV['RPM'] || Pkg::Util::Tool.find_tool('rpm')
8
-
9
- # If we're using the gpg agent for rpm signing, we don't want to specify the
10
- # input for the passphrase, which is what '--passphrase-fd 3' does. However,
11
- # if we're not using the gpg agent, this is required, and is part of the
12
- # defaults on modern rpm. The fun part of gpg-agent signing of rpms is
13
- # specifying that the gpg check command always return true
14
- #
15
- if Pkg::Util.boolean_value(ENV['RPM_GPG_AGENT'])
16
- gpg_check_cmd = "--define '%__gpg_check_password_cmd /bin/true'"
17
- else
18
- input_flag = "--passphrase-fd 3"
19
- end
20
-
21
- # Try this up to 5 times, to allow for incorrect passwords
22
- Pkg::Util::Execution.retry_on_fail(:times => 5) do
23
- # This definition of %__gpg_sign_cmd is the default on modern rpm. We
24
- # accept extra flags to override certain signing behavior for older
25
- # versions of rpm, e.g. specifying V3 signatures instead of V4.
26
- #
27
- sh "#{rpm_cmd} #{gpg_check_cmd} --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}"
28
- end
29
-
30
- end
31
-
32
- def sign_legacy_rpm(rpm)
33
- sign_rpm(rpm, "--force-v3-sigs --digest-algo=sha1")
34
- end
35
-
36
- def rpm_has_sig(rpm)
37
- %x(rpm -Kv #{rpm} | grep "#{Pkg::Util::Gpg.key.downcase}" &> /dev/null)
38
- $?.success?
39
- end
40
-
41
- def sign_deb_changes(file)
42
- # Lazy lazy lazy lazy lazy
43
- sign_program = "-p'gpg --use-agent --no-tty'" if ENV['RPM_GPG_AGENT']
44
- sh "debsign #{sign_program} --re-sign -k#{Pkg::Config.gpg_key} #{file}"
45
- end
46
-
47
1
  namespace :pl do
48
2
  desc "Sign the tarball, defaults to PL key, pass GPG_KEY to override or edit build_defaults"
49
3
  task :sign_tar do
50
4
  unless Pkg::Config.vanagon_project
51
- File.exist?("pkg/#{Pkg::Config.project}-#{Pkg::Config.version}.tar.gz") or fail "No tarball exists. Try rake package:tar?"
5
+ tarballs_to_sign = Pkg::Util::Ship.collect_packages(['pkg/*.tar.gz'], ['signing_bundle', 'packaging-bundle'])
52
6
  Pkg::Util::Gpg.load_keychain if Pkg::Util::Tool.find_tool('keychain')
53
- Pkg::Util::Gpg.sign_file "pkg/#{Pkg::Config.project}-#{Pkg::Config.version}.tar.gz"
7
+ tarballs_to_sign.each do |file|
8
+ Pkg::Util::Gpg.sign_file file
9
+ end
54
10
  end
55
11
  end
56
12
 
@@ -79,11 +35,27 @@ namespace :pl do
79
35
  task :sign_rpms, :root_dir do |t, args|
80
36
  rpm_dir = args.root_dir || "pkg"
81
37
 
82
- all_rpms = Dir["#{rpm_dir}/**/*.rpm"]
38
+ # Create a hash mapping full paths to basenames.
39
+ # This will allow us to keep track of the different paths that may be
40
+ # associated with a single basename, e.g. noarch packages.
41
+ all_rpms = {}
42
+ rpms_to_sign = Dir["#{rpm_dir}/**/*.rpm"]
43
+ rpms_to_sign.each do |rpm_path|
44
+ all_rpms[rpm_path] = File.basename(rpm_path)
45
+ end
46
+ # Delete a package, both from the signing server and from the rpm array, if
47
+ # there are other packages with the same basename so that we only sign the
48
+ # package once.
49
+ all_rpms.each do |rpm_path, rpm_filename|
50
+ if rpms_to_sign.map { |rpm| File.basename(rpm) }.count(rpm_filename) > 1
51
+ FileUtils.rm(rpm_path)
52
+ rpms_to_sign.delete(rpm_path)
53
+ end
54
+ end
83
55
 
84
56
  v3_rpms = []
85
57
  v4_rpms = []
86
- all_rpms.each do |rpm|
58
+ rpms_to_sign.each do |rpm|
87
59
  platform_tag = Pkg::Paths.tag_from_artifact_path(rpm)
88
60
  platform, version, _ = Pkg::Platforms.parse_platform_tag(platform_tag)
89
61
 
@@ -103,44 +75,38 @@ namespace :pl do
103
75
 
104
76
  unless v3_rpms.empty?
105
77
  puts "Signing old rpms..."
106
- sign_legacy_rpm(v3_rpms.join(' '))
78
+ Pkg::Sign::Rpm.legacy_sign(v3_rpms.join(' '))
107
79
  end
108
80
 
109
81
  unless v4_rpms.empty?
110
82
  puts "Signing modern rpms..."
111
- sign_rpm(v4_rpms.join(' '))
83
+ Pkg::Sign::Rpm.sign(v4_rpms.join(' '))
112
84
  end
113
85
 
114
- # Now we hardlink them back in
115
- Dir["#{rpm_dir}/**/*.noarch.rpm"].each do |rpm|
116
- platform_tag = Pkg::Paths.tag_from_artifact_path(rpm)
117
- platform, version, _ = Pkg::Platforms.parse_platform_tag(platform_tag)
118
- supported_arches = Pkg::Platforms.arches_for_platform_version(platform, version)
119
- cd File.dirname(rpm) do
120
- noarch_rpm = File.basename(rpm)
121
- supported_arches.each do |arch|
122
- arch_dir = File.join('..', arch)
123
- FileUtils.mkdir_p(arch_dir)
124
- unless File.exist?(File.join(arch_dir, noarch_rpm))
125
- FileUtils.ln(noarch_rpm, arch_dir, :force => true, :verbose => true)
126
- end
127
- end
86
+ # Using the map of paths to basenames, we re-hardlink the rpms we deleted.
87
+ all_rpms.each do |link_path, rpm_filename|
88
+ next if File.exist? link_path
89
+ FileUtils.mkdir_p(File.dirname(link_path))
90
+ # Find paths where the signed rpm has the same basename, but different
91
+ # full path, as the one we need to link.
92
+ paths_to_link_to = rpms_to_sign.select { |rpm| File.basename(rpm) == rpm_filename && rpm != link_path }
93
+ paths_to_link_to.each do |path|
94
+ FileUtils.ln(path, link_path, :force => true, :verbose => true)
128
95
  end
129
96
  end
130
97
  end
131
98
 
132
99
  desc "Sign ips package, uses PL certificates by default, update privatekey_pem, certificate_pem, and ips_inter_cert in build_defaults.yaml to override."
133
100
  task :sign_ips do
134
- Pkg::IPS.sign unless Dir['pkg/**/*.p5p'].empty?
101
+ Pkg::Sign::Ips.sign unless Dir['pkg/**/*.p5p'].empty?
135
102
  end
136
103
 
137
- if Pkg::Config.build_gem
138
- desc "Sign built gems, defaults to PL key, pass GPG_KEY to override or edit build_defaults"
139
- task :sign_gem do
140
- FileList["pkg/#{Pkg::Config.gem_name}-#{Pkg::Config.gemversion}*.gem"].each do |gem|
141
- puts "signing gem #{gem}"
142
- Pkg::Util::Gpg.sign_file(gem)
143
- end
104
+ desc "Sign built gems, defaults to PL key, pass GPG_KEY to override or edit build_defaults"
105
+ task :sign_gem do
106
+ gems = FileList["pkg/*.gem"]
107
+ gems.each do |gem|
108
+ puts "signing gem #{gem}"
109
+ Pkg::Util::Gpg.sign_file(gem)
144
110
  end
145
111
  end
146
112
 
@@ -150,7 +116,7 @@ namespace :pl do
150
116
  rpms = Dir["pkg/**/*.rpm"]
151
117
  print 'Checking rpm signatures'
152
118
  rpms.each do |rpm|
153
- if rpm_has_sig rpm
119
+ if Pkg::Sign::Rpm.has_sig? rpm
154
120
  print '.'
155
121
  else
156
122
  puts "#{rpm} is unsigned."
@@ -167,7 +133,7 @@ namespace :pl do
167
133
  change_files = Dir["pkg/**/*.changes"]
168
134
  unless change_files.empty?
169
135
  Pkg::Util::Gpg.load_keychain if Pkg::Util::Tool.find_tool('keychain')
170
- sign_deb_changes("pkg/**/*.changes")
136
+ Pkg::Sign::Deb.sign_changes("pkg/**/*.changes")
171
137
  end
172
138
  ensure
173
139
  Pkg::Util::Gpg.kill_keychain
@@ -176,12 +142,12 @@ namespace :pl do
176
142
 
177
143
  desc "Sign OSX packages"
178
144
  task :sign_osx => "pl:fetch" do
179
- Pkg::OSX.sign unless Dir['pkg/**/*.dmg'].empty?
145
+ Pkg::Sign::Dmg.sign unless Dir['pkg/**/*.dmg'].empty?
180
146
  end
181
147
 
182
148
  desc "Sign MSI packages"
183
149
  task :sign_msi => "pl:fetch" do
184
- Pkg::MSI.sign unless Dir['pkg/**/*.msi'].empty?
150
+ Pkg::Sign::Msi.sign unless Dir['pkg/**/*.msi'].empty?
185
151
  end
186
152
 
187
153
  ##
@@ -205,7 +171,8 @@ namespace :pl do
205
171
  signing_bundle = ENV['SIGNING_BUNDLE']
206
172
  rpm_sign_task = Pkg::Config.build_pe ? "pe:sign_rpms" : "pl:sign_rpms"
207
173
  deb_sign_task = Pkg::Config.build_pe ? "pe:sign_deb_changes" : "pl:sign_deb_changes"
208
- sign_tasks = [rpm_sign_task, deb_sign_task]
174
+ sign_tasks = [rpm_sign_task]
175
+ sign_tasks << deb_sign_task unless Dir['pkg/**/*.changes'].empty?
209
176
  sign_tasks << "pl:sign_tar" if Pkg::Config.build_tar
210
177
  sign_tasks << "pl:sign_gem" if Pkg::Config.build_gem
211
178
  sign_tasks << "pl:sign_osx" if Pkg::Config.build_dmg || Pkg::Config.vanagon_project
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packaging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.99.2
4
+ version: 0.99.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet Labs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-14 00:00:00.000000000 Z
11
+ date: 2018-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -83,16 +83,19 @@ files:
83
83
  - lib/packaging/deb.rb
84
84
  - lib/packaging/deb/repo.rb
85
85
  - lib/packaging/gem.rb
86
- - lib/packaging/ips.rb
87
- - lib/packaging/msi.rb
88
86
  - lib/packaging/nuget.rb
89
- - lib/packaging/osx.rb
90
87
  - lib/packaging/paths.rb
91
88
  - lib/packaging/platforms.rb
92
89
  - lib/packaging/repo.rb
93
90
  - lib/packaging/retrieve.rb
94
91
  - lib/packaging/rpm.rb
95
92
  - lib/packaging/rpm/repo.rb
93
+ - lib/packaging/sign.rb
94
+ - lib/packaging/sign/deb.rb
95
+ - lib/packaging/sign/dmg.rb
96
+ - lib/packaging/sign/ips.rb
97
+ - lib/packaging/sign/msi.rb
98
+ - lib/packaging/sign/rpm.rb
96
99
  - lib/packaging/tar.rb
97
100
  - lib/packaging/util.rb
98
101
  - lib/packaging/util/date.rb
@@ -1,57 +0,0 @@
1
- module Pkg::IPS
2
- class << self
3
- def sign(target_dir = 'pkg')
4
- use_identity = "-i #{Pkg::Config.ips_signing_ssh_key}" unless Pkg::Config.ips_signing_ssh_key.nil?
5
-
6
- ssh_host_string = "#{use_identity} #{ENV['USER']}@#{Pkg::Config.ips_signing_server}"
7
- rsync_host_string = "-e 'ssh #{use_identity}' #{ENV['USER']}@#{Pkg::Config.ips_signing_server}"
8
-
9
- p5ps = Dir.glob("#{target_dir}/solaris/11/**/*.p5p")
10
-
11
- p5ps.each do |p5p|
12
- work_dir = "/tmp/#{Pkg::Util.rand_string}"
13
- unsigned_dir = "#{work_dir}/unsigned"
14
- repo_dir = "#{work_dir}/repo"
15
- signed_dir = "#{work_dir}/pkgs"
16
-
17
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "mkdir -p #{repo_dir} #{unsigned_dir} #{signed_dir}")
18
- Pkg::Util::Net.rsync_to(p5p, rsync_host_string, unsigned_dir)
19
-
20
- # Before we can get started with signing packages we need to create a repo
21
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "sudo -E /usr/bin/pkgrepo create #{repo_dir}")
22
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "sudo -E /usr/bin/pkgrepo set -s #{repo_dir} publisher/prefix=puppetlabs.com")
23
- # And import all the packages into the repo.
24
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "sudo -E /usr/bin/pkgrecv -s #{unsigned_dir}/#{File.basename(p5p)} -d #{repo_dir} '*'")
25
- # We are going to hard code the values for signing cert locations for now.
26
- # This autmation will require an update to actually become reusable, but
27
- # for now these values will stay this way so solaris signing will stop
28
- # failing. Please update soon. 06/23/16
29
- #
30
- # - Sean P. McDonald
31
- #
32
- # We sign the entire repo
33
- sign_cmd = "sudo -E /usr/bin/pkgsign -c /root/signing/signing_cert_interim_SHA1.pem \
34
- -i /root/signing/Thawte_Code_Signing_Certificate_interim_SHA1.pem \
35
- -i /root/signing/Thawte_Primary_Root_CA_interim_SHA1.pem \
36
- -k /root/signing/signing_key_interim_SHA1.pem \
37
- -s 'file://#{work_dir}/repo' '*'"
38
- puts "About to sign #{p5p} with #{sign_cmd} in #{work_dir}"
39
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, sign_cmd.squeeze(' '))
40
- # pkgrecv with -a will pull packages out of the repo, so we need to do that too to actually get the packages we signed
41
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "sudo -E /usr/bin/pkgrecv -d #{signed_dir}/#{File.basename(p5p)} -a -s #{repo_dir} '*'")
42
- begin
43
- # lets make sure we actually signed something?
44
- # **NOTE** if we're repeatedly trying to sign the same version this
45
- # might explode because I don't know how to reset the IPS cache.
46
- # Everything is amazing.
47
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "sudo -E /usr/bin/pkg contents -m -g #{signed_dir}/#{File.basename(p5p)} '*' | grep '^signature '")
48
- rescue RuntimeError
49
- raise "Looks like #{File.basename(p5p)} was not signed correctly, quitting!"
50
- end
51
- # and pull the packages back.
52
- Pkg::Util::Net.rsync_from("#{signed_dir}/#{File.basename(p5p)}", rsync_host_string, File.dirname(p5p))
53
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "if [ -e '#{work_dir}' ] ; then sudo rm -r '#{work_dir}' ; fi")
54
- end
55
- end
56
- end
57
- end
@@ -1,89 +0,0 @@
1
- module Pkg::MSI
2
- class << self
3
- def sign(target_dir = 'pkg')
4
- use_identity = "-i #{Pkg::Config.msi_signing_ssh_key}" if Pkg::Config.msi_signing_ssh_key
5
-
6
- ssh_host_string = "#{use_identity} Administrator@#{Pkg::Config.msi_signing_server}"
7
- rsync_host_string = "-e 'ssh #{use_identity}' Administrator@#{Pkg::Config.msi_signing_server}"
8
-
9
- work_dir = "Windows/Temp/#{Pkg::Util.rand_string}"
10
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "mkdir -p C:/#{work_dir}")
11
- msis = Dir.glob("#{target_dir}/windows/**/*.msi")
12
- Pkg::Util::Net.rsync_to(msis.join(" "), rsync_host_string, "/cygdrive/c/#{work_dir}")
13
-
14
- # Please Note:
15
- # We are currently adding two signatures to the msi.
16
- #
17
- # Microsoft compatable Signatures are composed of three different
18
- # elements.
19
- # 1) The Certificate used to sign the package. This is the element that
20
- # is attached to organization. The certificate has an associated
21
- # algorithm. We recently (February 2016) had to switch from a sha1 to
22
- # a sha256 certificate. Sha1 was deprecated by many Microsoft
23
- # elements on 2016-01-01, which forced us to switch to a sha256 cert.
24
- # This sha256 certificate is recognized by all currently supported
25
- # windows platforms (Windows 8/Vista forward).
26
- # 2) The signature used to attach the certificate to the package. This
27
- # can be a done with a variety of digest algorithms. Older platforms
28
- # (i.e., Windows 8 and Windows Vista) don't recognize later
29
- # algorithms like sha256.
30
- # 3) The timestamp used to validate when the package was signed. This
31
- # comes from an external source and can be delivered with a variety
32
- # of digest algorithms. Older platforms do not recognize newer
33
- # algorithms like sha256.
34
- #
35
- # We could have only one signature with the Sha256 Cert, Sha1 Signature,
36
- # and Sha1 Timestamp, but that would be too easy. The sha256 signature
37
- # and timestamp add more security to our packages. We can't have only
38
- # sha256 elements in our package signature, though, because Windows 8
39
- # and Windows Vista just don't recognize them at all.
40
- #
41
- # In order to add two signatures to an MSI, we also need to change the
42
- # tool we use to sign packages with. Previously, we were using SignTool
43
- # which is the Microsoft blessed program used to sign packages. However,
44
- # this tool isn't able to add two signatures to an MSI specifically. It
45
- # can dual-sign an exe, just not an MSI. In order to get the dual-signed
46
- # packages, we decided to switch over to using osslsigncode. The original
47
- # project didn't have support to compile on a windows system, so we
48
- # decided to use this fork. The binaries on the signer were pulled from
49
- # https://sourceforge.net/u/keeely/osslsigncode/ci/master/tree/
50
- #
51
- # These are our signatures:
52
- # The first signature:
53
- # * Sha256 Certificate
54
- # * Sha1 Signature
55
- # * Sha1 Timestamp
56
- #
57
- # The second signature:
58
- # * Sha256 Certificate
59
- # * Sha256 Signature
60
- # * Sha256 Timestamp
61
- #
62
- # Once we no longer support Windows 8/Windows Vista, we can remove the
63
- # first Sha1 signature.
64
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, %Q(for msi in #{msis.map { |d| File.basename(d) }.join(" ")}; do
65
- "/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe" sign \
66
- -n "Puppet" -i "http://www.puppet.com" \
67
- -h sha1 \
68
- -pkcs12 "#{Pkg::Config.msi_signing_cert}" \
69
- -pass "#{Pkg::Config.msi_signing_cert_pw}" \
70
- -t "http://timestamp.verisign.com/scripts/timstamp.dll" \
71
- -in "C:/#{work_dir}/$msi" \
72
- -out "C:/#{work_dir}/signed-$msi"
73
- "/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe" sign \
74
- -n "Puppet" -i "http://www.puppet.com" \
75
- -nest -h sha256 \
76
- -pkcs12 "#{Pkg::Config.msi_signing_cert}" \
77
- -pass "#{Pkg::Config.msi_signing_cert_pw}" \
78
- -ts "http://sha256timestamp.ws.symantec.com/sha256/timestamp" \
79
- -in "C:/#{work_dir}/signed-$msi" \
80
- -out "C:/#{work_dir}/$msi"
81
- rm "C:/#{work_dir}/signed-$msi"
82
- done))
83
- msis.each do | msi |
84
- Pkg::Util::Net.rsync_from("/cygdrive/c/#{work_dir}/#{File.basename(msi)}", rsync_host_string, File.dirname(msi))
85
- end
86
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "if [ -d '/cygdrive/c/#{work_dir}' ]; then rm -rf '/cygdrive/c/#{work_dir}'; fi")
87
- end
88
- end
89
- end
@@ -1,36 +0,0 @@
1
- module Pkg::OSX
2
- class << self
3
- def sign(target_dir = 'pkg')
4
- use_identity = "-i #{Pkg::Config.osx_signing_ssh_key}" unless Pkg::Config.osx_signing_ssh_key.nil?
5
-
6
- if Pkg::Config.osx_signing_server =~ /@/
7
- host_string = "#{Pkg::Config.osx_signing_server}"
8
- else
9
- host_string = "#{ENV['USER']}@#{Pkg::Config.osx_signing_server}"
10
- end
11
- ssh_host_string = "#{use_identity} #{host_string}"
12
- rsync_host_string = "-e 'ssh #{use_identity}' #{host_string}"
13
-
14
- work_dir = "/tmp/#{Pkg::Util.rand_string}"
15
- mount = File.join(work_dir, "mount")
16
- signed = File.join(work_dir, "signed")
17
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "mkdir -p #{mount} #{signed}")
18
- dmgs = Dir.glob("#{target_dir}/apple/**/*.dmg")
19
- Pkg::Util::Net.rsync_to(dmgs.join(" "), rsync_host_string, work_dir)
20
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, %Q[for dmg in #{dmgs.map { |d| File.basename(d, ".dmg") }.join(" ")}; do
21
- /usr/bin/hdiutil attach #{work_dir}/$dmg.dmg -mountpoint #{mount} -nobrowse -quiet ;
22
- /usr/bin/security -q unlock-keychain -p "#{Pkg::Config.osx_signing_keychain_pw}" "#{Pkg::Config.osx_signing_keychain}" ;
23
- for pkg in $(ls #{mount}/*.pkg | xargs -n 1 basename); do
24
- /usr/bin/productsign --keychain "#{Pkg::Config.osx_signing_keychain}" --sign "#{Pkg::Config.osx_signing_cert}" #{mount}/$pkg #{signed}/$pkg ;
25
- done
26
- /usr/bin/hdiutil detach #{mount} -quiet ;
27
- /bin/rm #{work_dir}/$dmg.dmg ;
28
- /usr/bin/hdiutil create -volname $dmg -srcfolder #{signed}/ #{work_dir}/$dmg.dmg ;
29
- /bin/rm #{signed}/* ; done])
30
- dmgs.each do | dmg |
31
- Pkg::Util::Net.rsync_from("#{work_dir}/#{File.basename(dmg)}", rsync_host_string, File.dirname(dmg))
32
- end
33
- Pkg::Util::Net.remote_ssh_cmd(ssh_host_string, "if [ -d '#{work_dir}' ]; then rm -rf '#{work_dir}'; fi")
34
- end
35
- end
36
- end