Class: Brew::Vulns::Formula

Inherits:
Object
  • Object
show all
Defined in:
lib/brew/vulns/formula.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Formula

Returns a new instance of Formula.



11
12
13
14
15
16
17
# File 'lib/brew/vulns/formula.rb', line 11

def initialize(data)
  @name = data["name"] || data["full_name"]
  @version = data.dig("versions", "stable") || data["version"]
  @source_url = data.dig("urls", "stable", "url")
  @head_url = data.dig("urls", "head", "url")
  @dependencies = data["dependencies"] || []
end

Instance Attribute Details

#dependenciesObject (readonly)

Returns the value of attribute dependencies.



9
10
11
# File 'lib/brew/vulns/formula.rb', line 9

def dependencies
  @dependencies
end

#head_urlObject (readonly)

Returns the value of attribute head_url.



9
10
11
# File 'lib/brew/vulns/formula.rb', line 9

def head_url
  @head_url
end

#nameObject (readonly)

Returns the value of attribute name.



9
10
11
# File 'lib/brew/vulns/formula.rb', line 9

def name
  @name
end

#source_urlObject (readonly)

Returns the value of attribute source_url.



9
10
11
# File 'lib/brew/vulns/formula.rb', line 9

def source_url
  @source_url
end

#versionObject (readonly)

Returns the value of attribute version.



9
10
11
# File 'lib/brew/vulns/formula.rb', line 9

def version
  @version
end

Class Method Details

.load_from_brewfile(brewfile_path, include_deps: false) ⇒ Object

Raises:



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/brew/vulns/formula.rb', line 94

def self.load_from_brewfile(brewfile_path, include_deps: false)
  raise Error, "Brewfile not found: #{brewfile_path}" unless File.exist?(brewfile_path)

  formula_names = parse_brewfile(brewfile_path)
  return [] if formula_names.empty?

  json, status = Open3.capture2("brew", "info", "--json=v2", *formula_names)
  raise Error, "brew info failed with status #{status.exitstatus}" unless status.success?

  data = JSON.parse(json)
  formulae = data["formulae"].map { |f| new(f) }

  if include_deps
    dep_names = []
    formula_names.each do |name|
      deps_output, = Open3.capture2("brew", "deps", name)
      dep_names.concat(deps_output.split("\n").map(&:strip))
    end
    dep_names.uniq!
    dep_names -= formula_names

    if dep_names.any?
      deps_json, deps_status = Open3.capture2("brew", "info", "--json=v2", *dep_names)
      if deps_status.success?
        deps_data = JSON.parse(deps_json)
        formulae.concat(deps_data["formulae"].map { |f| new(f) })
      end
    end
  end

  formulae.uniq { |f| f.name }
end

.load_installed(formula_filter = nil) ⇒ Object

Raises:



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/brew/vulns/formula.rb', line 53

def self.load_installed(formula_filter = nil)
  json, status = Open3.capture2("brew", "info", "--json=v2", "--installed")
  raise Error, "brew info failed with status #{status.exitstatus}" unless status.success?

  data = JSON.parse(json)
  formulae = data["formulae"].map { |f| new(f) }

  if formula_filter
    formulae.select! { |f| f.name == formula_filter || f.name.split("@").first == formula_filter }
  end

  formulae
end

.load_with_dependencies(formula_filter = nil) ⇒ Object

Raises:



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/brew/vulns/formula.rb', line 67

def self.load_with_dependencies(formula_filter = nil)
  json, status = Open3.capture2("brew", "info", "--json=v2", "--installed")
  raise Error, "brew info failed with status #{status.exitstatus}" unless status.success?

  data = JSON.parse(json)
  all_formulae = data["formulae"].map { |f| new(f) }
  formulae_by_name = all_formulae.each_with_object({}) { |f, h| h[f.name] = f }

  if formula_filter
    filtered = all_formulae.select { |f| f.name == formula_filter || f.name.split("@").first == formula_filter }
    return [] if filtered.empty?

    deps_output, = Open3.capture2("brew", "deps", "--installed", formula_filter)
    dep_names = deps_output.split("\n").map(&:strip)

    result = filtered.each_with_object({}) { |f, h| h[f.name] = f }
    dep_names.each do |dep_name|
      dep = formulae_by_name[dep_name]
      result[dep_name] = dep if dep && !result[dep_name]
    end

    result.values
  else
    all_formulae
  end
end

.parse_brewfile(brewfile_path) ⇒ Object

Raises:



127
128
129
130
131
132
# File 'lib/brew/vulns/formula.rb', line 127

def self.parse_brewfile(brewfile_path)
  output, status = Open3.capture2("brew", "bundle", "list", "--file=#{brewfile_path}", "--formula")
  raise Error, "brew bundle list failed with status #{status.exitstatus}" unless status.success?

  output.split("\n").map(&:strip).reject(&:empty?)
end

Instance Method Details

#codeberg?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/brew/vulns/formula.rb', line 39

def codeberg?
  repo_url&.include?("codeberg.org")
end

#github?Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/brew/vulns/formula.rb', line 31

def github?
  repo_url&.include?("github.com")
end

#gitlab?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/brew/vulns/formula.rb', line 35

def gitlab?
  repo_url&.include?("gitlab.com")
end

#repo_urlObject



19
20
21
22
23
# File 'lib/brew/vulns/formula.rb', line 19

def repo_url
  return @repo_url if defined?(@repo_url)

  @repo_url = extract_repo_url(source_url) || extract_repo_url(head_url)
end

#supported_forge?Boolean

Returns:

  • (Boolean)


43
44
45
# File 'lib/brew/vulns/formula.rb', line 43

def supported_forge?
  github? || gitlab? || codeberg?
end

#tagObject



25
26
27
28
29
# File 'lib/brew/vulns/formula.rb', line 25

def tag
  return @tag if defined?(@tag)

  @tag = extract_tag_from_url(source_url)
end

#to_osv_queryObject



47
48
49
50
51
# File 'lib/brew/vulns/formula.rb', line 47

def to_osv_query
  return nil unless repo_url && tag

  { repo_url: repo_url, version: tag, name: name }
end