class VRT::Mapping
Public Class Methods
new(scheme)
click to toggle source
# File lib/vrt/mapping.rb, line 3 def initialize(scheme) @scheme = scheme.to_s load_mappings end
Public Instance Methods
get(id_list, version)
click to toggle source
returns the most specific value provided in the mapping file for the given vrt id
if no mapping file exists for the given version, the mapping file for the earliest version available will be used
# File lib/vrt/mapping.rb, line 11 def get(id_list, version) # update the vrt id to the first version we have a mapping file for unless @mappings.key?(version) id_list = VRT.find_node(vrt_id: id_list.join('.'), preferred_version: @min_version).id_list version = @min_version end mapping = @mappings[version]['content'] default = @mappings[version]['metadata']['default'] keys = @mappings[version]['metadata']['keys'] if keys # Convert mappings with multiple keys to be nested under a single # top-level key. Remediation advice has keys 'remediation_advice' # and 'references' so we convert it to look like # { remediation_advice: { remediation_advice: '...', references: [...] } } keys.each_with_object({}) do |key, acc| acc[key.to_sym] = get_key( id_list: id_list, mapping: mapping, key: key ) || default&.dig(key) end else get_key(id_list: id_list, mapping: mapping, key: @scheme) || default end end
Private Instance Methods
get_key(id_list:, mapping:, key:)
click to toggle source
# File lib/vrt/mapping.rb, line 77 def get_key(id_list:, mapping:, key:) # iterate through the id components, keeping track of where we are in the mapping file # and the most specific mapped value found so far best_guess = nil id_list.each do |id| entry = mapping[id] break unless entry # mapping file doesn't go this deep, return previous value best_guess = merge_arrays(best_guess, entry[key]) if entry[key] # use the children mapping for the next iteration mapping = entry['children'] || {} end best_guess end
key_by_id(mapping)
click to toggle source
Converts arrays to hashes keyed by the id attribute (as a symbol) for easier lookup. So
[{'id': 'one', 'foo': 'bar'}, {'id': 'two', 'foo': 'baz'}]
becomes
{one: {'id': 'one', 'foo': 'bar'}, two: {'id': 'two', 'foo': 'baz'}}
# File lib/vrt/mapping.rb, line 67 def key_by_id(mapping) if mapping.is_a?(Array) && mapping.first.is_a?(Hash) && mapping.first.key?('id') mapping.each_with_object({}) { |entry, acc| acc[entry['id'].to_sym] = key_by_id(entry) } elsif mapping.is_a?(Hash) mapping.each_with_object({}) { |(key, value), acc| acc[key] = key_by_id(value) } else mapping end end
load_mappings()
click to toggle source
# File lib/vrt/mapping.rb, line 39 def load_mappings @mappings = {} VRT.versions.each do |version| filename = mapping_file_path(version) next unless File.file?(filename) mapping = JSON.parse(File.read(filename)) mapping['content'] = key_by_id(mapping['content']) @mappings[version] = mapping # VRT.versions is sorted in reverse semver order # so this will end up as the earliest version with a mapping file @min_version = version end raise VRT::Errors::MappingNotFound if @mappings.empty? end
mapping_file_path(version)
click to toggle source
# File lib/vrt/mapping.rb, line 55 def mapping_file_path(version) filename = VRT::DIR.join(version, 'mappings', "#{@scheme}.json") return filename if File.file?(filename) # Supports mappings that are nested under their scheme name e.g. `mappings/cvss/cvss.json` VRT::DIR.join(version, 'mappings', @scheme, "#{@scheme}.json") end
merge_arrays(previous_value, new_value)
click to toggle source
# File lib/vrt/mapping.rb, line 92 def merge_arrays(previous_value, new_value) if previous_value.is_a?(Array) && new_value.is_a?(Array) new_value | previous_value else new_value end end