Add cop for IO.read usage
This commit is contained in:
		
							parent
							
								
									6c9ef43e72
								
							
						
					
					
						commit
						e5285b5ed8
					
				@ -54,6 +54,10 @@ FormulaAudit:
 | 
				
			|||||||
FormulaAuditStrict:
 | 
					FormulaAuditStrict:
 | 
				
			||||||
  Enabled: true
 | 
					  Enabled: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# enable all Homebrew custom cops
 | 
				
			||||||
 | 
					Homebrew:
 | 
				
			||||||
 | 
					  Enabled: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# makes DSL usage ugly.
 | 
					# makes DSL usage ugly.
 | 
				
			||||||
Layout/SpaceBeforeBrackets:
 | 
					Layout/SpaceBeforeBrackets:
 | 
				
			||||||
  Exclude:
 | 
					  Exclude:
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ require "rubocop-rails"
 | 
				
			|||||||
require "rubocop-rspec"
 | 
					require "rubocop-rspec"
 | 
				
			||||||
require "rubocop-sorbet"
 | 
					require "rubocop-sorbet"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require "rubocops/io_read"
 | 
				
			||||||
require "rubocops/shell_commands"
 | 
					require "rubocops/shell_commands"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require "rubocops/formula_desc"
 | 
					require "rubocops/formula_desc"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								Library/Homebrew/rubocops/io_read.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Library/Homebrew/rubocops/io_read.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					# typed: true
 | 
				
			||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module RuboCop
 | 
				
			||||||
 | 
					  module Cop
 | 
				
			||||||
 | 
					    module Homebrew
 | 
				
			||||||
 | 
					      # This cop restricts usage of IO.read functions for security reasons.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # @api private
 | 
				
			||||||
 | 
					      class IORead < Base
 | 
				
			||||||
 | 
					        MSG = "The use of `IO.%<method>s` is a security risk."
 | 
				
			||||||
 | 
					        RESTRICT_ON_SEND = [:read, :readlines].freeze
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_send(node)
 | 
				
			||||||
 | 
					          return if node.receiver != s(:const, nil, :IO)
 | 
				
			||||||
 | 
					          return if safe?(node.arguments.first)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          add_offense(node, message: format(MSG, method: node.method_name))
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def safe?(node)
 | 
				
			||||||
 | 
					          if node.str_type?
 | 
				
			||||||
 | 
					            !node.str_content.empty? && !node.str_content.start_with?("|")
 | 
				
			||||||
 | 
					          elsif node.dstr_type? || (node.send_type? && node.method?(:+))
 | 
				
			||||||
 | 
					            safe?(node.children.first)
 | 
				
			||||||
 | 
					          else
 | 
				
			||||||
 | 
					            false
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -6,7 +6,7 @@ require "rubocops/shared/helper_functions"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
module RuboCop
 | 
					module RuboCop
 | 
				
			||||||
  module Cop
 | 
					  module Cop
 | 
				
			||||||
    module Style
 | 
					    module Homebrew
 | 
				
			||||||
      # https://github.com/ruby/ruby/blob/v2_6_3/process.c#L2430-L2460
 | 
					      # https://github.com/ruby/ruby/blob/v2_6_3/process.c#L2430-L2460
 | 
				
			||||||
      SHELL_BUILTINS = %w[
 | 
					      SHELL_BUILTINS = %w[
 | 
				
			||||||
        !
 | 
					        !
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										75
									
								
								Library/Homebrew/test/rubocops/io_read_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								Library/Homebrew/test/rubocops/io_read_spec.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					# typed: false
 | 
				
			||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require "rubocops/io_read"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe RuboCop::Cop::Homebrew::IORead do
 | 
				
			||||||
 | 
					  subject(:cop) { described_class.new }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "reports an offense when `IO.read` is used with a pipe character" do
 | 
				
			||||||
 | 
					    expect_offense(<<~RUBY)
 | 
				
			||||||
 | 
					      IO.read("|echo test")
 | 
				
			||||||
 | 
					      ^^^^^^^^^^^^^^^^^^^^^ The use of `IO.read` is a security risk.
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "does not report an offense when `IO.read` is used without a pipe character" do
 | 
				
			||||||
 | 
					    expect_no_offenses(<<~RUBY)
 | 
				
			||||||
 | 
					      IO.read("file.txt")
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "reports an offense when `IO.read` is used with untrustworthy input" do
 | 
				
			||||||
 | 
					    expect_offense(<<~RUBY)
 | 
				
			||||||
 | 
					      input = "input value from an unknown source"
 | 
				
			||||||
 | 
					      IO.read(input)
 | 
				
			||||||
 | 
					      ^^^^^^^^^^^^^^ The use of `IO.read` is a security risk.
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "reports an offense when `IO.read` is used with a dynamic string starting with a pipe character" do
 | 
				
			||||||
 | 
					    expect_offense(<<~'RUBY')
 | 
				
			||||||
 | 
					      input = "test"
 | 
				
			||||||
 | 
					      IO.read("|echo #{input}")
 | 
				
			||||||
 | 
					      ^^^^^^^^^^^^^^^^^^^^^^^^^ The use of `IO.read` is a security risk.
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "reports an offense when `IO.read` is used with a dynamic string at the start" do
 | 
				
			||||||
 | 
					    expect_offense(<<~'RUBY')
 | 
				
			||||||
 | 
					      input = "|echo test"
 | 
				
			||||||
 | 
					      IO.read("#{input}.txt")
 | 
				
			||||||
 | 
					      ^^^^^^^^^^^^^^^^^^^^^^^ The use of `IO.read` is a security risk.
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "does not report an offense when `IO.read` is used with a dynamic string safely" do
 | 
				
			||||||
 | 
					    expect_no_offenses(<<~'RUBY')
 | 
				
			||||||
 | 
					      input = "test"
 | 
				
			||||||
 | 
					      IO.read("somefile#{input}.txt")
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "reports an offense when `IO.read` is used with a concatenated string starting with a pipe character" do
 | 
				
			||||||
 | 
					    expect_offense(<<~'RUBY')
 | 
				
			||||||
 | 
					      input = "|echo test"
 | 
				
			||||||
 | 
					      IO.read("|echo " + input)
 | 
				
			||||||
 | 
					      ^^^^^^^^^^^^^^^^^^^^^^^^^ The use of `IO.read` is a security risk.
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "reports an offense when `IO.read` is used with a concatenated string starting with untrustworthy input" do
 | 
				
			||||||
 | 
					    expect_offense(<<~'RUBY')
 | 
				
			||||||
 | 
					      input = "|echo test"
 | 
				
			||||||
 | 
					      IO.read(input + ".txt")
 | 
				
			||||||
 | 
					      ^^^^^^^^^^^^^^^^^^^^^^^ The use of `IO.read` is a security risk.
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "does not report an offense when `IO.read` is used with a concatenated string safely" do
 | 
				
			||||||
 | 
					    expect_no_offenses(<<~'RUBY')
 | 
				
			||||||
 | 
					      input = "test"
 | 
				
			||||||
 | 
					      IO.read("somefile" + input + ".txt")
 | 
				
			||||||
 | 
					    RUBY
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -5,7 +5,7 @@ require "rubocops/shell_commands"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
module RuboCop
 | 
					module RuboCop
 | 
				
			||||||
  module Cop
 | 
					  module Cop
 | 
				
			||||||
    module Style
 | 
					    module Homebrew
 | 
				
			||||||
      describe ShellCommands do
 | 
					      describe ShellCommands do
 | 
				
			||||||
        subject(:cop) { described_class.new }
 | 
					        subject(:cop) { described_class.new }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user