From c90e6e7b4b75923d73389e7825203629ae912489 Mon Sep 17 00:00:00 2001 From: Razvan Azamfirei Date: Mon, 18 Sep 2023 12:38:10 -0400 Subject: [PATCH 1/3] cask/audit: add audit_min_os --- Library/Homebrew/cask/audit.rb | 75 ++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 7c0a8a6ace..fbc9ff10c1 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -6,6 +6,7 @@ require "cask/download" require "digest" require "livecheck/livecheck" require "source_location" +require "system_command" require "utils/curl" require "utils/git" require "utils/shared_audits" @@ -540,7 +541,33 @@ module Cask false end - def audit_livecheck_min_os + sig { void } + def audit_min_os + return unless online? + + odebug "Auditing minimum OS version" + + sparkle_min_os = livecheck_min_os + plist_min_os = cask_plist_min_os + odebug "Minimum OS version: Plist #{plist_min_os} | Sparkle #{sparkle_min_os.inspect}" + min_os_string = [sparkle_min_os, plist_min_os].compact.max + + return if min_os_string.nil? || min_os_string <= HOMEBREW_MACOS_OLDEST_ALLOWED + + cask_min_os = cask.depends_on.macos&.version + return if cask_min_os == min_os_string + + min_os_symbol = if cask_min_os.present? + cask_min_os.to_sym.inspect + else + "no minimum OS version" + end + add_error "Upstream defined #{min_os_string.to_sym.inspect} as the minimum OS version " \ + "and the cask defined #{min_os_symbol}", + strict_only: true + end + + def livecheck_min_os return unless online? return unless cask.livecheckable? return if cask.livecheck.strategy != :sparkle @@ -566,24 +593,48 @@ module Cask return if min_os.blank? begin - min_os_string = MacOSVersion.new(min_os).strip_patch + MacOSVersion.new(min_os).strip_patch rescue MacOSVersion::Error - return + nil + end + end + + def cask_plist_min_os + return unless online? + + artifacts = cask.artifacts.select do |k| + k.is_a?(Artifact::Pkg) || k.is_a?(Artifact::App) || k.is_a?(Artifact::Binary) end - return if min_os_string <= HOMEBREW_MACOS_OLDEST_ALLOWED + return if artifacts.empty? - cask_min_os = cask.depends_on.macos&.version + downloaded_path = download.fetch + primary_container = UnpackStrategy.detect(downloaded_path, type: @cask.container&.type, merge_xattrs: true) - return if cask_min_os == min_os_string + return if primary_container.nil? - min_os_symbol = if cask_min_os.present? - cask_min_os.to_sym.inspect - else - "no minimum OS version" + plist_min_os = T.let(nil, T.untyped) + + Dir.mktmpdir do |tmpdir| + tmpdir = Pathname(tmpdir) + primary_container.extract_nestedly(to: tmpdir, basename: downloaded_path.basename, verbose: false) + + artifacts.each do |artifact| + artifact_path = artifact.is_a?(Artifact::Pkg) ? artifact.path : artifact.source + path = tmpdir/artifact_path.relative_path_from(cask.staged_path) + plist_path = "#{path}/Contents/Info.plist" + next unless File.exist?(plist_path) + + plist = system_command!("plutil", args: ["-convert", "xml1", "-o", "-", plist_path]).plist + plist_min_os = plist["LSMinimumSystemVersion"].presence + break if plist_min_os + end + end + begin + MacOSVersion.new(plist_min_os).strip_patch + rescue MacOSVersion::Error + nil end - add_error "Upstream defined #{min_os_string.to_sym.inspect} as the minimum OS version " \ - "and the cask defined #{min_os_symbol}" end sig { void } From e60523766e9f78f19d867939d12b12a2eae7563d Mon Sep 17 00:00:00 2001 From: Razvan Azamfirei Date: Thu, 26 Oct 2023 15:45:06 -0400 Subject: [PATCH 2/3] audit: code review changes --- Library/Homebrew/cask/audit.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index fbc9ff10c1..f64daf1028 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -544,6 +544,7 @@ module Cask sig { void } def audit_min_os return unless online? + return unless strict? odebug "Auditing minimum OS version" @@ -630,6 +631,7 @@ module Cask break if plist_min_os end end + begin MacOSVersion.new(plist_min_os).strip_patch rescue MacOSVersion::Error From df2aee4553fdee5449a249efa594543f5308ef81 Mon Sep 17 00:00:00 2001 From: Razvan Azamfirei Date: Sun, 5 Nov 2023 17:18:21 -0500 Subject: [PATCH 3/3] audit: add extract artifcats method --- Library/Homebrew/cask/audit.rb | 82 +++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index f64daf1028..74f255020d 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -475,21 +475,8 @@ module Cask return if !signing? || download.blank? || cask.url.blank? odebug "Auditing signing" - artifacts = cask.artifacts.select do |k| - k.is_a?(Artifact::Pkg) || k.is_a?(Artifact::App) || k.is_a?(Artifact::Binary) - end - - return if artifacts.empty? - - downloaded_path = download.fetch - primary_container = UnpackStrategy.detect(downloaded_path, type: @cask.container&.type, merge_xattrs: true) - - return if primary_container.nil? - - Dir.mktmpdir do |tmpdir| - tmpdir = Pathname(tmpdir) - primary_container.extract_nestedly(to: tmpdir, basename: downloaded_path.basename, verbose: false) + extract_artifacts do |artifacts, tmpdir| artifacts.each do |artifact| artifact_path = artifact.is_a?(Artifact::Pkg) ? artifact.path : artifact.source path = tmpdir/artifact_path.relative_path_from(cask.staged_path) @@ -510,6 +497,38 @@ module Cask end end + sig { void } + def extract_artifacts + return unless online? + + artifacts = cask.artifacts.select do |artifact| + artifact.is_a?(Artifact::Pkg) || artifact.is_a?(Artifact::App) || artifact.is_a?(Artifact::Binary) + end + + if @artifacts_extracted && @tmpdir + yield artifacts, @tmpdir if block_given? + return + end + + return if artifacts.empty? + + @tmpdir ||= Pathname(Dir.mktmpdir) + + ohai "Downloading and extracting artifacts" + + downloaded_path = download.fetch + + primary_container = UnpackStrategy.detect(downloaded_path, type: @cask.container&.type, merge_xattrs: true) + return if primary_container.nil? + + # Extract the container to the temporary directory. + primary_container.extract_nestedly(to: @tmpdir, basename: downloaded_path.basename, verbose: false) + @artifacts_extracted = true # Set the flag to indicate that extraction has occurred. + + # Yield the artifacts and temp directory to the block if provided. + yield artifacts, @tmpdir if block_given? + end + sig { returns(T.any(NilClass, T::Boolean, Symbol)) } def audit_livecheck_version return unless online? @@ -548,26 +567,31 @@ module Cask odebug "Auditing minimum OS version" - sparkle_min_os = livecheck_min_os plist_min_os = cask_plist_min_os - odebug "Minimum OS version: Plist #{plist_min_os} | Sparkle #{sparkle_min_os.inspect}" - min_os_string = [sparkle_min_os, plist_min_os].compact.max + sparkle_min_os = livecheck_min_os - return if min_os_string.nil? || min_os_string <= HOMEBREW_MACOS_OLDEST_ALLOWED + debug_messages = [] + debug_messages << "Plist #{plist_min_os}" if plist_min_os + debug_messages << "Sparkle #{sparkle_min_os}" if sparkle_min_os + odebug "Minimum OS version: #{debug_messages.join(" | ")}" unless debug_messages.empty? + min_os = [sparkle_min_os, plist_min_os].compact.max + + return if min_os.nil? || min_os <= HOMEBREW_MACOS_OLDEST_ALLOWED cask_min_os = cask.depends_on.macos&.version - return if cask_min_os == min_os_string + return if cask_min_os == min_os min_os_symbol = if cask_min_os.present? cask_min_os.to_sym.inspect else "no minimum OS version" end - add_error "Upstream defined #{min_os_string.to_sym.inspect} as the minimum OS version " \ + add_error "Upstream defined #{min_os.to_sym.inspect} as the minimum OS version " \ "and the cask defined #{min_os_symbol}", strict_only: true end + sig { returns(T.nilable(MacOSVersion)) } def livecheck_min_os return unless online? return unless cask.livecheckable? @@ -600,26 +624,14 @@ module Cask end end + sig { returns(T.nilable(MacOSVersion)) } def cask_plist_min_os return unless online? - artifacts = cask.artifacts.select do |k| - k.is_a?(Artifact::Pkg) || k.is_a?(Artifact::App) || k.is_a?(Artifact::Binary) - end - - return if artifacts.empty? - - downloaded_path = download.fetch - primary_container = UnpackStrategy.detect(downloaded_path, type: @cask.container&.type, merge_xattrs: true) - - return if primary_container.nil? - plist_min_os = T.let(nil, T.untyped) + @staged_path ||= cask.staged_path - Dir.mktmpdir do |tmpdir| - tmpdir = Pathname(tmpdir) - primary_container.extract_nestedly(to: tmpdir, basename: downloaded_path.basename, verbose: false) - + extract_artifacts do |artifacts, tmpdir| artifacts.each do |artifact| artifact_path = artifact.is_a?(Artifact::Pkg) ? artifact.path : artifact.source path = tmpdir/artifact_path.relative_path_from(cask.staged_path)