diff --git a/Library/Homebrew/rubocops/all.rb b/Library/Homebrew/rubocops/all.rb index ebe0525542..d46a48b06a 100644 --- a/Library/Homebrew/rubocops/all.rb +++ b/Library/Homebrew/rubocops/all.rb @@ -43,5 +43,6 @@ require_relative "text" require_relative "urls" require_relative "uses_from_macos" require_relative "version" +require_relative "zero_zero_zero_zero" require_relative "rubocop-cask" diff --git a/Library/Homebrew/rubocops/zero_zero_zero_zero.rb b/Library/Homebrew/rubocops/zero_zero_zero_zero.rb new file mode 100644 index 0000000000..92879abded --- /dev/null +++ b/Library/Homebrew/rubocops/zero_zero_zero_zero.rb @@ -0,0 +1,48 @@ +# typed: strict +# frozen_string_literal: true + +require "rubocops/extend/formula_cop" + +module RuboCop + module Cop + module FormulaAudit + # This cop audits the use of 0.0.0.0 in formulae. + # 0.0.0.0 should not be used outside of test do blocks as it can be a security risk. + class ZeroZeroZeroZero < FormulaCop + sig { override.params(formula_nodes: FormulaNodes).void } + def audit_formula(formula_nodes) + return if formula_tap != "homebrew-core" + + body_node = formula_nodes.body_node + return if body_node.nil? + + test_block = find_block(body_node, :test) + + # Find all string literals in the formula + body_node.each_descendant(:str) do |str_node| + content = string_content(str_node) + next unless content.include?("0.0.0.0") + next if test_block && str_node.ancestors.any?(test_block) + + next if valid_ip_range?(content) + + offending_node(str_node) + problem "Do not use 0.0.0.0 as it can be a security risk." + end + end + + private + + sig { params(content: String).returns(T::Boolean) } + def valid_ip_range?(content) + # Allow private IP ranges like 10.0.0.0, 172.16.0.0-172.31.255.255, 192.168.0.0-192.168.255.255 + return true if content.match?(/\b(?:10|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\.\d+\.\d+\b/) + # Allow IP range notation like 0.0.0.0-255.255.255.255 + return true if content.match?(/\b0\.0\.0\.0\s*-\s*255\.255\.255\.255\b/) + + false + end + end + end + end +end diff --git a/Library/Homebrew/test/rubocops/zero_zero_zero_zero_spec.rb b/Library/Homebrew/test/rubocops/zero_zero_zero_zero_spec.rb new file mode 100644 index 0000000000..96aafc0125 --- /dev/null +++ b/Library/Homebrew/test/rubocops/zero_zero_zero_zero_spec.rb @@ -0,0 +1,135 @@ +# frozen_string_literal: true + +require "rubocops/zero_zero_zero_zero" + +RSpec.describe RuboCop::Cop::FormulaAudit::ZeroZeroZeroZero do + subject(:cop) { described_class.new } + + it "reports no offenses when 0.0.0.0 is used inside test do blocks" do + expect_no_offenses(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + test do + system "echo", "0.0.0.0" + end + end + RUBY + end + + it "reports no offenses for valid IP ranges like 10.0.0.0" do + expect_no_offenses(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + def install + system "echo", "10.0.0.0" + end + end + RUBY + end + + it "reports no offenses for IP range notation like 0.0.0.0-255.255.255.255" do + expect_no_offenses(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + def install + system "echo", "0.0.0.0-255.255.255.255" + end + end + RUBY + end + + it "reports no offenses for private IP ranges" do + expect_no_offenses(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + def install + system "echo", "192.168.1.1" + system "echo", "172.16.0.1" + system "echo", "10.0.0.1" + end + end + RUBY + end + + it "reports no offenses when outside of homebrew-core" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + service do + run [bin/"foo", "--host", "0.0.0.0"] + end + end + RUBY + end + + it "reports offenses when 0.0.0.0 is used in service blocks" do + expect_offense(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + service do + run [bin/"foo", "--host", "0.0.0.0"] + ^^^^^^^^^ FormulaAudit/ZeroZeroZeroZero: Do not use 0.0.0.0 as it can be a security risk. + end + end + RUBY + end + + it "reports offenses when 0.0.0.0 is used outside of test do blocks" do + expect_offense(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + def install + system "echo", "0.0.0.0" + ^^^^^^^^^ FormulaAudit/ZeroZeroZeroZero: Do not use 0.0.0.0 as it can be a security risk. + end + end + RUBY + end + + it "reports offenses for 0.0.0.0 in method definitions outside test blocks" do + expect_offense(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + def configure + system "./configure", "--bind-address=0.0.0.0" + ^^^^^^^^^^^^^^^^^^^^^^^^ FormulaAudit/ZeroZeroZeroZero: Do not use 0.0.0.0 as it can be a security risk. + end + end + RUBY + end + + it "reports multiple offenses when 0.0.0.0 is used in multiple places" do + expect_offense(<<~RUBY, "/homebrew-core/") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + desc "A test formula" + + def install + system "echo", "0.0.0.0" + ^^^^^^^^^ FormulaAudit/ZeroZeroZeroZero: Do not use 0.0.0.0 as it can be a security risk. + end + + def post_install + system "echo", "0.0.0.0" + ^^^^^^^^^ FormulaAudit/ZeroZeroZeroZero: Do not use 0.0.0.0 as it can be a security risk. + end + end + RUBY + end +end