Add ZeroZeroZeroZero cop

Add a new RuboCop to detect the use of 0.0.0.0 in formulae which
indicates binding to all network interfaces, internally or externally,
so is a bad default and potentially a security risk.

Co-authored-by: Issy Long <me@issylong.com>
This commit is contained in:
Mike McQuaid 2025-07-10 17:41:12 +01:00
parent 5692ea6c17
commit 71bab462e1
No known key found for this signature in database
3 changed files with 184 additions and 0 deletions

View File

@ -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"

View File

@ -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

View File

@ -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