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/third_party_links.rb,
lib/vrt/cross_version_mapping.rb

Defined Under Namespace

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

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



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

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

.current_categoriesObject



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

def current_categories
  get_map.categories
end

.current_versionObject

Get the most recent version of the VRT.



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

def current_version
  versions.first
end

.current_version?(version) ⇒ Boolean

Returns:

  • (Boolean)


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

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



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

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)



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

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



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

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

.json_dir_namesObject

Get names of directories matching lib/data/<major>-<minor>/



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

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



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

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

.json_pathname(version) ⇒ Object

Get the Pathname for a particular version



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

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.



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

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

.mappingsObject



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

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.



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

def reload!
  unload!
  versions
  get_json
  get_map
  last_updated
  third_party_links
  mappings
end


127
128
129
130
131
# File 'lib/vrt.rb', line 127

def third_party_links
  @third_party_links ||= {
    scw: VRT::ThirdPartyLinks.new('secure-code-warrior-links', 'remediation_training')
  }
end

.unload!Object

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



146
147
148
149
150
151
152
# File 'lib/vrt.rb', line 146

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

.versionsObject

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.



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

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