lib/omnibus/packagers/pkg.rb in omnibus-6.1.9 vs lib/omnibus/packagers/pkg.rb in omnibus-7.0.12

- old
+ new

@@ -62,10 +62,12 @@ end build do write_scripts + sign_software_libs_and_bins + build_component_pkg write_distribution_file build_product_pkg @@ -175,28 +177,93 @@ copy_file(source_path, destination_path) end end end + def sign_software_libs_and_bins + if signing_identity + log.info(log_key) { "Finding libraries and binaries that require signing." } + + bin_dirs = Set[] + lib_dirs = Set[] + binaries = Set[] + libraries = Set[] + + # Capture lib_dirs and bin_dirs from each software + project.softwares.each do |software| + lib_dirs.merge(software.lib_dirs) + bin_dirs.merge(software.bin_dirs) + end + + # Find all binaries in each bind_dir + bin_dirs.each do |dir| + binaries.merge Dir["#{dir}/*"] + end + # Filter out symlinks, non-files, and non-executables + log.debug(log_key) { " Filtering non-binary files:" } + binaries.select! { |bin| is_binary?(bin) } + + # Use otool to find all libries that are used by our binaries + binaries.each do |bin| + libraries.merge find_linked_libs bin + end + + # Find all libraries in each lib_dir and add any we missed with otool + lib_dirs.each do |dir| + libraries.merge Dir["#{dir}/*"] + end + + # Filter Mach-O libraries and bundles + log.debug(log_key) { " Filtering non-library files:" } + libraries.select! { |lib| is_macho?(lib) } + + # Use otool to find all libries that are used by our libraries + otool_libs = Set[] + libraries.each do |lib| + otool_libs.merge find_linked_libs lib + end + + # Filter Mach-O libraries and bundles + otool_libs.select! { |lib| is_macho?(lib) } + libraries.merge otool_libs + + log.info(log_key) { " Signing libraries:" } unless libraries.empty? + libraries.each do |library| + log.debug(log_key) { " Signing: #{library}" } + sign_library(library) + end + + log.info(log_key) { " Signing binaries:" } unless binaries.empty? + binaries.each do |binary| + log.debug(log_key) { " Signing: #{binary}" } + sign_binary(binary, true) + end + end + end + # # Construct the intermediate build product. It can be installed with the # Installer.app, but doesn't contain the data needed to customize the # installer UI. # # @return [void] # def build_component_pkg - command = <<-EOH.gsub(/^ {8}/, "") + command = <<~EOH pkgbuild \\ --identifier "#{safe_identifier}" \\ --version "#{safe_version}" \\ --scripts "#{scripts_dir}" \\ --root "#{project.install_dir}" \\ --install-location "#{project.install_dir}" \\ - "#{component_pkg}" + --preserve-xattr \\ EOH + command << %Q{ --sign "#{signing_identity}" \\\n} if signing_identity + command << %Q{ "#{component_pkg}"} + command << %Q{\n} + Dir.chdir(staging_dir) do shellout!(command) end end @@ -227,11 +294,11 @@ # product that is shipped to end users. # # @return [void] # def build_product_pkg - command = <<-EOH.gsub(/^ {8}/, "") + command = <<~EOH productbuild \\ --distribution "#{staging_dir}/Distribution" \\ --resources "#{resources_dir}" \\ EOH @@ -317,8 +384,60 @@ "`#{project.build_version}' to `#{converted}'." end converted end + end + + # + # Given a file path return any linked libraries. + # + # @param [String] file_path + # The path to a file + # @return [Array<String>] + # The linked libs + # + def find_linked_libs(file_path) + # Find all libaries for each bin + command = "otool -L #{file_path}" + + stdout = shellout!(command).stdout + stdout.slice!(file_path) + stdout.scan(/#{install_dir}\S*/) + end + + def sign_library(lib) + sign_binary(lib) + end + + def sign_binary(bin, hardened_runtime = false) + command = "codesign -s '#{signing_identity}' '#{bin}'" + command << %q{ --options=runtime} if hardened_runtime + command << %Q{ --entitlements #{resource_path("entitlements.plist")}} if File.exist?(resource_path("entitlements.plist")) && hardened_runtime + ## Force re-signing to deal with binaries that have the same sha. + command << %q{ --force} + command << %Q{\n} + + shellout!(command) + end + + def is_binary?(bin) + is_binary = File.file?(bin) && + File.executable?(bin) && + !File.symlink?(bin) + log.debug(log_key) { " removing from signing: #{bin}" } unless is_binary + is_binary + end + + def is_macho?(lib) + is_macho = false + if is_binary?(lib) + command = "file #{lib}" + + stdout = shellout!(command).stdout + is_macho = stdout.match?(/Mach-O.*library/) || stdout.match?(/Mach-O.*bundle/) + end + log.debug(log_key) { " removing from signing: #{lib}" } unless is_macho + is_macho end end end