![copilot-swe-agent[bot]](/assets/img/avatar_default.png) 7f6b4bee93
			
		
	
	
		7f6b4bee93
		
			
		
	
	
	
	
		
			
			Co-authored-by: p-linnane <105994585+p-linnane@users.noreply.github.com> Co-authored-by: MikeMcQuaid <125011+MikeMcQuaid@users.noreply.github.com>
		
			
				
	
	
		
			128 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # typed: strict
 | |
| # frozen_string_literal: true
 | |
| 
 | |
| require "forwardable"
 | |
| require "rubocops/shared/on_system_conditionals_helper"
 | |
| 
 | |
| module RuboCop
 | |
|   module Cop
 | |
|     module Cask
 | |
|       # This cop makes sure that OS conditionals are consistent.
 | |
|       #
 | |
|       # ### Example
 | |
|       #
 | |
|       # ```ruby
 | |
|       # # bad
 | |
|       # cask 'foo' do
 | |
|       #   if MacOS.version == :high_sierra
 | |
|       #     sha256 "..."
 | |
|       #   end
 | |
|       # end
 | |
|       #
 | |
|       # # good
 | |
|       # cask 'foo' do
 | |
|       #   on_high_sierra do
 | |
|       #     sha256 "..."
 | |
|       #   end
 | |
|       # end
 | |
|       # ```
 | |
|       class OnSystemConditionals < Base
 | |
|         extend Forwardable
 | |
|         extend AutoCorrector
 | |
|         include OnSystemConditionalsHelper
 | |
|         include CaskHelp
 | |
| 
 | |
|         FLIGHT_STANZA_NAMES = [:preflight, :postflight, :uninstall_preflight, :uninstall_postflight].freeze
 | |
| 
 | |
|         sig { override.params(cask_block: RuboCop::Cask::AST::CaskBlock).void }
 | |
|         def on_cask(cask_block)
 | |
|           @cask_block = T.let(cask_block, T.nilable(RuboCop::Cask::AST::CaskBlock))
 | |
| 
 | |
|           toplevel_stanzas.each do |stanza|
 | |
|             next unless FLIGHT_STANZA_NAMES.include? stanza.stanza_name
 | |
| 
 | |
|             audit_on_system_blocks(stanza.stanza_node, stanza.stanza_name)
 | |
|           end
 | |
| 
 | |
|           audit_arch_conditionals(cask_body, allowed_blocks: FLIGHT_STANZA_NAMES)
 | |
|           audit_macos_version_conditionals(cask_body, recommend_on_system: false)
 | |
|           simplify_sha256_stanzas
 | |
|           audit_identical_sha256_across_architectures
 | |
|         end
 | |
| 
 | |
|         private
 | |
| 
 | |
|         sig { returns(T.nilable(RuboCop::Cask::AST::CaskBlock)) }
 | |
|         attr_reader :cask_block
 | |
| 
 | |
|         def_delegators :cask_block, :toplevel_stanzas, :cask_body
 | |
| 
 | |
|         sig { void }
 | |
|         def simplify_sha256_stanzas
 | |
|           nodes = {}
 | |
| 
 | |
|           sha256_on_arch_stanzas(cask_body) do |node, method, value|
 | |
|             nodes[method.to_s.delete_prefix("on_").to_sym] = { node:, value: }
 | |
|           end
 | |
| 
 | |
|           return if !nodes.key?(:arm) || !nodes.key?(:intel)
 | |
| 
 | |
|           offending_node(nodes[:arm][:node])
 | |
|           replacement_string = "sha256 arm: #{nodes[:arm][:value].inspect}, intel: #{nodes[:intel][:value].inspect}"
 | |
| 
 | |
|           problem "Use `#{replacement_string}` instead of nesting the `sha256` stanzas in " \
 | |
|                   "`on_intel` and `on_arm` blocks" do |corrector|
 | |
|             corrector.replace(nodes[:arm][:node].source_range, replacement_string)
 | |
|             corrector.replace(nodes[:intel][:node].source_range, "")
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         sig { void }
 | |
|         def audit_identical_sha256_across_architectures
 | |
|           sha256_stanzas = toplevel_stanzas.select { |stanza| stanza.stanza_name == :sha256 }
 | |
| 
 | |
|           sha256_stanzas.each do |stanza|
 | |
|             sha256_node = stanza.stanza_node
 | |
|             next if sha256_node.arguments.count != 1
 | |
|             next unless sha256_node.arguments.first.hash_type?
 | |
| 
 | |
|             hash_node = sha256_node.arguments.first
 | |
|             arm_sha = T.let(nil, T.nilable(String))
 | |
|             intel_sha = T.let(nil, T.nilable(String))
 | |
| 
 | |
|             hash_node.pairs.each do |pair|
 | |
|               key = pair.key
 | |
|               next unless key.sym_type?
 | |
| 
 | |
|               value = pair.value
 | |
|               next unless value.str_type?
 | |
| 
 | |
|               case key.value
 | |
|               when :arm
 | |
|                 arm_sha = value.value
 | |
|               when :intel
 | |
|                 intel_sha = value.value
 | |
|               end
 | |
|             end
 | |
| 
 | |
|             next unless arm_sha
 | |
|             next unless intel_sha
 | |
|             next if arm_sha != intel_sha
 | |
| 
 | |
|             offending_node(sha256_node)
 | |
|             problem "sha256 values for different architectures should not be identical."
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def_node_search :sha256_on_arch_stanzas, <<~PATTERN
 | |
|           $(block
 | |
|             (send nil? ${:on_intel :on_arm})
 | |
|             (args)
 | |
|             (send nil? :sha256
 | |
|               (str $_)))
 | |
|         PATTERN
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |