Class: Bootprint::Advisories

Inherits:
Object
  • Object
show all
Defined in:
lib/bootprint/advisories.rb

Overview

Matches snapshot gem versions against an offline advisory bundle.

Defined Under Namespace

Classes: Advisory, Match

Constant Summary collapse

DEFAULT_BUNDLE =
File.expand_path("../../data/advisories/schema/empty.json", __dir__).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bundle, path: nil) ⇒ Advisories

Returns a new instance of Advisories.



58
59
60
61
# File 'lib/bootprint/advisories.rb', line 58

def initialize(bundle, path: nil)
  @bundle = normalize_bundle(bundle)
  @path = path
end

Instance Attribute Details

#bundleObject (readonly)

Returns the value of attribute bundle.



35
36
37
# File 'lib/bootprint/advisories.rb', line 35

def bundle
  @bundle
end

Class Method Details

.advisories(bundle = DEFAULT_BUNDLE) ⇒ Object



50
51
52
53
54
55
56
# File 'lib/bootprint/advisories.rb', line 50

def self.advisories(bundle = DEFAULT_BUNDLE)
  case bundle
  when Advisories then bundle
  when Hash then new(bundle)
  else load(bundle)
  end
end

.load(path = DEFAULT_BUNDLE) ⇒ Object



37
38
39
40
41
42
43
44
# File 'lib/bootprint/advisories.rb', line 37

def self.load(path = DEFAULT_BUNDLE)
  parsed = JSON.parse(File.read(path, encoding: "UTF-8"))
  new(parsed, path:)
rescue JSON::ParserError => error
  raise InvalidSnapshotError, "#{File.expand_path(path)} is not valid advisory JSON: #{error.message}"
rescue Errno::ENOENT
  raise InvalidSnapshotError, "Advisory bundle not found: #{File.expand_path(path)}"
end

.match(snapshot, bundle: DEFAULT_BUNDLE) ⇒ Object



46
47
48
# File 'lib/bootprint/advisories.rb', line 46

def self.match(snapshot, bundle: DEFAULT_BUNDLE)
  advisories(bundle).matches(snapshot)
end

Instance Method Details

#clean?(snapshot) ⇒ Boolean

Returns:

  • (Boolean)


76
# File 'lib/bootprint/advisories.rb', line 76

def clean?(snapshot) = matches(snapshot).empty?

#matches(snapshot) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/bootprint/advisories.rb', line 63

def matches(snapshot)
  gems = extract_gems(snapshot)
  bundle_advisories.flat_map do |advisory|
    installed = gems[advisory.gem]
    next [] unless installed

    version = installed.is_a?(Hash) ? installed["version"] : installed
    next [] unless version && AdvisoryBundleMatcher.version_satisfies?(version, advisory.affected_versions)

    Match.new(gem: advisory.gem, version: version.to_s, advisory:)
  end
end

#to_h(snapshot = nil) ⇒ Object



78
79
80
81
82
83
84
85
86
# File 'lib/bootprint/advisories.rb', line 78

def to_h(snapshot = nil)
  matches = snapshot ? matches(snapshot) : []
  {
    "schema_version" => bundle.fetch("schema_version", 1),
    "bundle" => @path || "inline",
    "clean" => matches.empty?,
    "matches" => matches.map(&:to_h)
  }
end