Skip to content

Commit def0646

Browse files
committed
Just do all the signing in vanagon
1 parent 90d3619 commit def0646

File tree

1 file changed

+130
-47
lines changed

1 file changed

+130
-47
lines changed

lib/vanagon/platform/osx.rb

Lines changed: 130 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -35,56 +35,139 @@ def generate_package(project) # rubocop:disable Metrics/AbcSize
3535
bom_install = []
3636
end
3737

38-
if project.extra_files_to_sign.any?
39-
method = project.use_local_signing ? 'local_commands' : 'commands'
40-
sign_commands = Vanagon::Utilities::ExtraFilesSigner.send(method, project, @mktemp, "/osx/build/root/#{project.name}-#{project.version}")
41-
else
42-
sign_commands = []
38+
# Previously, the "commands" method would test if it could SSH to the signer node and just skip
39+
# all the signing stuff if it couldn't and VANAGON_FORCE_SIGNING was not set. It never really tested
40+
# that signing actually worked and skipped it if it didn't. Now with the local commands, we really
41+
# can't even do that test. So just don't even try signing unless VANAGON_FORCE_SIGNING is set.
42+
unlock = 'security unlock-keychain -p $$SIGNING_KEYCHAIN_PW $$SIGNING_KEYCHAIN'
43+
extra_sign_commands = []
44+
sign_files_commands = []
45+
# If we're not signing, move the pkg to the right place
46+
sign_package_commands = [ "mv #{project.name}-#{project.version}-#{project.release}-installer.pkg pkg/" ]
47+
sign_dmg_commands = []
48+
notarize_dmg_commands = []
49+
if ENV['VANAGON_FORCE_SIGNING']
50+
# You should no longer really need to do this, but it's here just in case.
51+
if project.extra_files_to_sign.any?
52+
method = project.use_local_signing ? 'local_commands' : 'commands'
53+
extra_sign_commands = Vanagon::Utilities::ExtraFilesSigner.send(method, project, @mktemp, "/osx/build/root/#{project.name}-#{project.version}")
54+
end
55+
56+
# As of MacOS 15, we have to notarize the dmg. In order to get notarization, we have to
57+
# code sign every single binary, .bundle, and .dylib file in the package. So instead of
58+
# only signing a few files we specify, sign everything we can find that needs to be signed.
59+
# We then need to notarize the resulting dmg.
60+
#
61+
# This requires the VM to have the following env vars set in advance.
62+
# SIGNING_KEYCHAIN - the name of the keychain containing the code/installer signing identities
63+
# SIGNING_KEYCHAIN_PW - the password to unlock the keychain
64+
# APPLICATION_SIGNING_CERT - the identity description used for application signing
65+
# INSTALLER_SIGNING_CERT - the identity description used for installer .pkg signing
66+
# NOTARY_PROFILE - The name of the notary profile stored in the keychain
67+
68+
69+
70+
paths_with_binaries = {
71+
"root/#{project.name}-#{project.version}/opt/puppetlabs/bin/" => '*',
72+
"root/#{project.name}-#{project.version}/opt/puppetlabs/puppet/bin/" => '*',
73+
"root/#{project.name}-#{project.version}/opt/puppetlabs/puppet/lib/ruby/vendor_gems/bin" => '*',
74+
"root/#{project.name}-#{project.version}/opt/puppetlabs/puppet/lib/" => '*.dylib',
75+
"root/#{project.name}-#{project.version}/opt/puppetlabs/puppet/lib" => '*.bundle',
76+
'plugins' => 'puppet-agent-installer-plugin',
77+
}
78+
79+
sign_files_commands = [ unlock ]
80+
sign_files_commands += paths_with_binaries.map do |path, name|
81+
"find $(tempdir)/osx/build/#{path} -name '#{name}' -type f -exec codesign --timestamp --options runtime --keychain $$SIGNING_KEYCHAIN -vfs \"$$APPLICATION_SIGNING_CERT\" {} \;"
82+
end
83+
sign_files_commands += paths_with_binaries.map do |path, name|
84+
"find $(tempdir)/osx/build/#{path} -name '#{name}' -type f -exec codesign --verify --strict --verbose=2 {} \;"
85+
end
86+
87+
sign_package_commands = [
88+
unlock,
89+
"productsign --keychain $$SIGNING_KEYCHAIN --sign \"$$INSTALLER_SIGNING_CERT\" #{project.name}-#{project.version}-#{project.release}-installer.pkg pkg/#{project.name}-#{project.version}-#{project.release}-installer.pkg",
90+
"rm #{project.name}-#{project.version}-#{project.release}-installer.pkg",
91+
]
92+
93+
dmg = "dmg/#{project.package_name}"
94+
sign_dmg_commands = [
95+
unlock,
96+
"codesign --timestamp --keychain $$SIGNING_KEYCHAIN --sign \"$$APPLICATION_SIGNING_CERT\" #{dmg}",
97+
"codesign --verify --strict --verbose=2 #{dmg}",
98+
]
99+
100+
notarize_dmg_commands = ENV['NO_NOTARIZE'] ? [] : [
101+
unlock,
102+
"xcrun notarytool submit #{dmg} --keychain-profile \"$$NOTARY_PROFILE\" --wait",
103+
"xcrun stapler staple #{dmg}",
104+
"spctl --assess --type open --verbose #{dmg}"
105+
]
43106
end
44107

45108
# Setup build directories
46-
["bash -c 'mkdir -p $(tempdir)/osx/build/{dmg,pkg,scripts,resources,root,payload,plugins}'",
47-
"mkdir -p $(tempdir)/osx/build/root/#{project.name}-#{project.version}",
48-
"mkdir -p $(tempdir)/osx/build/pkg",
49-
# Grab distribution xml, scripts and other external resources
50-
"cp #{project.name}-installer.xml $(tempdir)/osx/build/",
51-
#copy the uninstaller to the pkg dir, where eventually the installer will go too
52-
"cp #{project.name}-uninstaller.tool $(tempdir)/osx/build/pkg/",
53-
"cp scripts/* $(tempdir)/osx/build/scripts/",
54-
"if [ -d resources/osx/productbuild ] ; then cp -r resources/osx/productbuild/* $(tempdir)/osx/build/; fi",
55-
# Unpack the project
56-
"gunzip -c #{project.name}-#{project.version}.tar.gz | '#{@tar}' -C '$(tempdir)/osx/build/root/#{project.name}-#{project.version}' --strip-components 1 -xf -",
57-
58-
bom_install,
59-
60-
# Sign extra files
61-
sign_commands,
62-
63-
# Package the project
64-
"(cd $(tempdir)/osx/build/; #{@pkgbuild} --root root/#{project.name}-#{project.version} \
65-
--scripts $(tempdir)/osx/build/scripts \
66-
--identifier #{project.identifier}.#{project.name} \
67-
--version #{project.version} \
68-
--preserve-xattr \
69-
--install-location / \
70-
payload/#{project.name}-#{project.version}-#{project.release}.pkg)",
71-
# Create a custom installer using the pkg above
72-
"(cd $(tempdir)/osx/build/; #{@productbuild} --distribution #{project.name}-installer.xml \
73-
--identifier #{project.identifier}.#{project.name}-installer \
74-
--package-path payload/ \
75-
--resources $(tempdir)/osx/build/resources \
76-
--plugins $(tempdir)/osx/build/plugins \
77-
pkg/#{project.name}-#{project.version}-#{project.release}-installer.pkg)",
78-
# Create a dmg and ship it to the output directory
79-
"(cd $(tempdir)/osx/build; \
80-
#{@hdiutil} create \
81-
-volname #{project.name}-#{project.version} \
82-
-fs JHFS+ \
83-
-format UDBZ \
84-
-srcfolder pkg \
85-
dmg/#{project.package_name})",
86-
"mkdir -p output/#{target_dir}",
87-
"cp $(tempdir)/osx/build/dmg/#{project.package_name} ./output/#{target_dir}"].flatten.compact
109+
[
110+
"bash -c 'mkdir -p $(tempdir)/osx/build/{dmg,pkg,scripts,resources,root,payload,plugins}'",
111+
"mkdir -p $(tempdir)/osx/build/root/#{project.name}-#{project.version}",
112+
"mkdir -p $(tempdir)/osx/build/pkg",
113+
# Grab distribution xml, scripts and other external resources
114+
"cp #{project.name}-installer.xml $(tempdir)/osx/build/",
115+
#copy the uninstaller to the pkg dir, where eventually the installer will go too
116+
"cp #{project.name}-uninstaller.tool $(tempdir)/osx/build/pkg/",
117+
"cp scripts/* $(tempdir)/osx/build/scripts/",
118+
"if [ -d resources/osx/productbuild ] ; then cp -r resources/osx/productbuild/* $(tempdir)/osx/build/; fi",
119+
# Unpack the project
120+
"gunzip -c #{project.name}-#{project.version}.tar.gz | '#{@tar}' -C '$(tempdir)/osx/build/root/#{project.name}-#{project.version}' --strip-components 1 -xf -",
121+
122+
bom_install,
123+
124+
# Sign extra files
125+
extra_sign_commands,
126+
127+
# As of MacOS 15, we have to notarize the dmg. In order to get notarization, we have to
128+
# code sign every single binary, .bundle, and .dylib file in the package. So instead of
129+
# only signing a few files we specify, sign everything we can find that needs to be signed.
130+
#
131+
# This requires the VM to have the following env vars set in advance.
132+
# SIGNING_KEYCHAIN - the name of the keychain containing the code/installer signing identities
133+
# SIGNING_KEYCHAIN_PW - the password to unlock the keychain
134+
# APPLICATION_SIGNING_CERT - the identity description used for application signing
135+
# INSTALLER_SIGNING_CERT - the identity description used for installer .pkg signing
136+
# NOTARY_PROFILE - The name of the notary profile stored in the keychain
137+
138+
# Package the project
139+
"(cd $(tempdir)/osx/build/; #{@pkgbuild} --root root/#{project.name}-#{project.version} \
140+
--scripts $(tempdir)/osx/build/scripts \
141+
--identifier #{project.identifier}.#{project.name} \
142+
--version #{project.version} \
143+
--preserve-xattr \
144+
--install-location / \
145+
payload/#{project.name}-#{project.version}-#{project.release}.pkg)",
146+
147+
# Create a custom installer using the pkg above
148+
"(cd $(tempdir)/osx/build/; #{@productbuild} --distribution #{project.name}-installer.xml \
149+
--identifier #{project.identifier}.#{project.name}-installer \
150+
--package-path payload/ \
151+
--resources $(tempdir)/osx/build/resources \
152+
--plugins $(tempdir)/osx/build/plugins \
153+
#{project.name}-#{project.version}-#{project.release}-installer.pkg)",
154+
155+
sign_package_commands,
156+
157+
# Create a dmg and ship it to the output directory
158+
"(cd $(tempdir)/osx/build; \
159+
#{@hdiutil} create \
160+
-volname #{project.name}-#{project.version} \
161+
-fs JHFS+ \
162+
-format UDBZ \
163+
-srcfolder pkg \
164+
dmg/#{project.package_name})",
165+
166+
sign_dmg_commands,
167+
notarize_dmg_commands,
168+
"mkdir -p output/#{target_dir}",
169+
"cp $(tempdir)/osx/build/dmg/#{project.package_name} ./output/#{target_dir}"
170+
].flatten.compact
88171
end
89172

90173
# Method to generate the files required to build a osx package for the project

0 commit comments

Comments
 (0)