Module: VRT

Extended by:
CrossVersionMapping
Defined in:
lib/vrt.rb,
lib/vrt/map.rb,
lib/vrt/node.rb,
lib/vrt/errors.rb,
lib/vrt/mapping.rb,
lib/vrt/cross_version_mapping.rb

Defined Under Namespace

Modules: CrossVersionMapping, Errors Classes: Map, Mapping, Node

Constant Summary collapse

DIR =
Pathname.new(__dir__).join('data')
OTHER_OPTION =
{ 'id' => 'other',
'name' => 'Other',
'priority' => nil,
'type' => 'category' }.freeze
MAPPINGS =
%i[cvss_v3 remediation_advice cwe].freeze

Class Method Summary collapse

Methods included from CrossVersionMapping

cross_version_category_mapping, deprecated_node?, deprecated_node_json, find_deprecated_node, find_valid_parent_node, latest_version_for_deprecated_node

Class Method Details

.all_matching_categories(categories) ⇒ Object

Get all deprecated ids that would match in the given categories from the current version



62
63
64
65
66
67
68
# File 'lib/vrt.rb', line 62

def all_matching_categories(categories)
  cross_version_category_mapping
    .select { |key, _value| categories.include?(key) }
    .values
    .flatten
    .uniq
end

.current_categories ⇒ Object



57
58
59
# File 'lib/vrt.rb', line 57

def current_categories
  get_map.categories
end

.current_version ⇒ Object

Get the most recent version of the VRT.



39
40
41
# File 'lib/vrt.rb', line 39

def current_version
  versions.first
end

.current_version?(version) ⇒ Boolean

Returns:

  • (Boolean)


43
44
45
# File 'lib/vrt.rb', line 43

def current_version?(version)
  version == current_version
end

.find_node(vrt_id:, preferred_version: nil, max_depth: 'variant', version: nil) ⇒ VRT::Node|Nil

Finds the best match valid node. First looks at valid nodes in the given new version or finds the appropriate deprecated mapping. If neither is found it will walk up the tree to find a valid parent node before giving up and returning nil.

Parameters:

  • vrt_id (String) —

    A valid vrt_id

  • preferred_version (string) (defaults to: nil) —

    (Optional) The preferred vrt_version of the returned node (defaults to current_version)

  • max_depth (String) (defaults to: 'variant') —

    (Optional) The maximum depth to match in

  • version (String) (defaults to: nil) —

    (deprecated) This parameter is no longer used

Returns:

  • (VRT::Node|Nil) —

    A valid VRT::Node object or nil if no best match could be found



80
81
82
83
84
85
86
87
88
89
# File 'lib/vrt.rb', line 80

def find_node(vrt_id:, preferred_version: nil, max_depth: 'variant', version: nil) # rubocop:disable Lint/UnusedMethodArgument
  new_version = preferred_version || current_version
  if get_map(version: new_version).valid?(vrt_id)
    get_map(version: new_version).find_node(vrt_id, max_depth: max_depth)
  elsif deprecated_node?(vrt_id)
    find_deprecated_node(vrt_id, preferred_version, max_depth)
  else
    find_valid_parent_node(vrt_id, new_version, max_depth)
  end
end

.get_json(version: nil, other: true) ⇒ Object

Load the VRT from text files, and parse it as JSON. If other: true, we append the OTHER_OPTION hash at runtime (not cached)



93
94
95
96
97
# File 'lib/vrt.rb', line 93

def get_json(version: nil, other: true)
  version ||= current_version
  @version_json[version] ||= json_for_version(version)
  other ? @version_json[version] + [OTHER_OPTION] : @version_json[version]
end

.get_map(version: nil) ⇒ Object



99
100
101
102
# File 'lib/vrt.rb', line 99

def get_map(version: nil)
  version ||= current_version
  @maps[version] ||= Map.new(version)
end

.json_dir_names ⇒ Object

Get names of directories matching lib/data/-/



105
106
107
108
109
110
# File 'lib/vrt.rb', line 105

def json_dir_names
  DIR.entries
     .map(&:basename)
     .map(&:to_s)
     .select { |dirname| dirname =~ /^[0-9]+\.[0-9]/ }.sort
end

.json_for_version(version) ⇒ Object

Load and parse JSON for some VRT version



118
119
120
# File 'lib/vrt.rb', line 118

def json_for_version(version)
  JSON.parse(json_pathname(version).read)['content']
end

.json_pathname(version) ⇒ Object

Get the Pathname for a particular version



113
114
115
# File 'lib/vrt.rb', line 113

def json_pathname(version)
  DIR.join(version, 'vulnerability-rating-taxonomy.json')
end

.last_updated(version = nil) ⇒ Object

Get the last updated timestamp of the VRT data (not schema!) Passing nil for version will return the latest version.



49
50
51
52
53
54
55
# File 'lib/vrt.rb', line 49

def last_updated(version = nil)
  version ||= current_version
  return @last_update[version] if @last_update[version]

   = JSON.parse(json_pathname(version).read)['metadata']
  @last_update[version] = Date.parse(['release_date'])
end

.mappings ⇒ Object



122
123
124
# File 'lib/vrt.rb', line 122

def mappings
  @mappings ||= Hash[MAPPINGS.map { |name| [name, VRT::Mapping.new(name)] }]
end

.reload! ⇒ Object

Cache the VRT contents in-memory, so we're not hitting File I/O multiple times per request that needs it.



128
129
130
131
132
133
134
135
# File 'lib/vrt.rb', line 128

def reload!
  unload!
  versions
  get_json
  get_map
  last_updated
  mappings
end

.unload! ⇒ Object

We separate unload! out, as we need to call it in test environments.



138
139
140
141
142
143
144
# File 'lib/vrt.rb', line 138

def unload!
  @versions = nil
  @version_json = {}
  @last_update = {}
  @maps = {}
  @mappings = nil
end

.versions ⇒ Object

Infer the available versions of the VRT from the names of the files in the repo. The returned list is in semver order with the current version first.



34
35
36
# File 'lib/vrt.rb', line 34

def versions
  @versions ||= json_dir_names.sort_by { |v| Gem::Version.new(v) }.reverse!
end