Class: HeimdallTools::SarifMapper

Inherits:
Object
  • Object
show all
Defined in:
lib/heimdall_tools/sarif_mapper.rb

Instance Method Summary collapse

Constructor Details

#initialize(sarif_json, _name = nil, verbose = false) ⇒ SarifMapper

Returns a new instance of SarifMapper.



30
31
32
33
34
35
36
37
38
39
# File 'lib/heimdall_tools/sarif_mapper.rb', line 30

def initialize(sarif_json, _name = nil, verbose = false)
  @sarif_json = sarif_json
  @verbose = verbose
  begin
    @cwe_nist_mapping = parse_mapper
    @sarif_log = JSON.parse(@sarif_json)
  rescue StandardError => e
    raise "Invalid SARIF JSON file provided\n\nException: #{e}"
  end
end

Instance Method Details

#add_nist_tag_from_cwe(cweid, taxonomy_name, tags_node) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/heimdall_tools/sarif_mapper.rb', line 73

def add_nist_tag_from_cwe(cweid, taxonomy_name, tags_node)
  entries = @cwe_nist_mapping.select { |x| cweid.include?(x[:cweid].to_s) && !x[:nistid].nil? }
  tags = entries.map { |x| x[:nistid] }
  result_tags = tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
  if result_tags.count.positive?
    if !tags_node
      tags_node = {}
    end
    if !tags_node.key?(taxonomy_name)
      tags_node[taxonomy_name] = []
    end
    result_tags.each do |t|
      tags_node[taxonomy_name] |= [t]
    end
  end
  tags_node
end

#desc_tags(data, label) ⇒ Object



151
152
153
# File 'lib/heimdall_tools/sarif_mapper.rb', line 151

def desc_tags(data, label)
  { data: data || NA_STRING, label: label || NA_STRING }
end

#extract_scaninfo(sarif_log) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/heimdall_tools/sarif_mapper.rb', line 41

def extract_scaninfo(sarif_log)
  info = {}
  begin
    info['policy'] = 'SARIF'
    info['version'] = sarif_log['version']
    info['projectName'] = 'Static Analysis Results Interchange Format'
    info['summary'] = NA_STRING
    info
  rescue StandardError => e
    raise "Error extracting project info from SARIF JSON file provided Exception: #{e}"
  end
end

#finding(result) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/heimdall_tools/sarif_mapper.rb', line 54

def finding(result)
  finding = {}
  finding['status'] = 'failed'
  finding['code_desc'] = ''
  if get_location(result)['uri']
    finding['code_desc'] += " URL : #{get_location(result)['uri']}"
  end
  if get_location(result)['start_line']
    finding['code_desc'] += " LINE : #{get_location(result)['start_line']}"
  end
  if get_location(result)['start_column']
    finding['code_desc'] += " COLUMN : #{get_location(result)['start_column']}"
  end
  finding['code_desc'].strip!
  finding['run_time'] = NA_FLOAT
  finding['start_time'] = NA_STRING
  finding
end

#get_location(result) ⇒ Object



91
92
93
94
95
96
97
# File 'lib/heimdall_tools/sarif_mapper.rb', line 91

def get_location(result)
  location_info = {}
  location_info['uri'] = result.dig('locations', 0, 'physicalLocation', 'artifactLocation', 'uri')
  location_info['start_line'] = result.dig('locations', 0, 'physicalLocation', 'region', 'startLine')
  location_info['start_column'] = result.dig('locations', 0, 'physicalLocation', 'region', 'startColumn')
  location_info
end

#get_rule_info(run, result, rule_id) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/heimdall_tools/sarif_mapper.rb', line 99

def get_rule_info(run, result, rule_id)
  finding = {}
  driver = run.dig('tool', 'driver')
  finding['driver_name'] = driver['name']
  finding['driver_version'] = driver['version']
  rules = driver['rules']
  if rules
    rule = rules.find { |x| x['id'].eql?(rule_id) }
    if rule
      finding['rule_name'] = rule&.[]('name')
      finding['rule_short_description'] = rule&.[]('shortDescription')&.[]('text')
      finding['rule_tags'] = get_tags(rule)
      finding['rule_name'] = rule&.[]('messageStrings')&.[]('default')&.[]('text') unless finding['rule_name']
    end
  end
  finding['rule_name'] = result&.[]('message')&.[]('text') unless finding['rule_name']
  finding
end

#get_tags(rule) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/heimdall_tools/sarif_mapper.rb', line 118

def get_tags(rule)
  result = {}
  Array(rule&.[]('relationships')).each do |relationship|
    taxonomy_name = relationship['target']['toolComponent']['name'].downcase
    taxonomy_id = relationship['target']['id']
    if !result.key?(taxonomy_name)
      result[taxonomy_name] = []
    end
    result[taxonomy_name] |= [taxonomy_id]
  end
  result
end

#impact(severity) ⇒ Object



138
139
140
141
# File 'lib/heimdall_tools/sarif_mapper.rb', line 138

def impact(severity)
  severity_mapping = IMPACT_MAPPING[severity.to_sym]
  severity_mapping.nil? ? 0.1 : severity_mapping
end

#parse_identifiers(rule_tags, ref) ⇒ Object



131
132
133
134
135
136
# File 'lib/heimdall_tools/sarif_mapper.rb', line 131

def parse_identifiers(rule_tags, ref)
  # Extracting id number from reference style CWE-297
  rule_tags[ref.downcase].map { |e| e.downcase.split("#{ref.downcase}-")[1] }
rescue StandardError
  []
end

#parse_mapperObject



143
144
145
146
147
148
149
# File 'lib/heimdall_tools/sarif_mapper.rb', line 143

def parse_mapper
  csv_data = CSV.read(CWE_NIST_MAPPING_FILE, **{ encoding: 'UTF-8',
                                               headers: true,
                                               header_converters: :symbol,
                                               converters: :all })
  csv_data.map(&:to_hash)
end

#process_item(run, result, controls) ⇒ Object



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/heimdall_tools/sarif_mapper.rb', line 155

def process_item(run, result, controls)
  printf("\rProcessing: %s", $spinner.next)
  control = controls.find { |x| x['id'].eql?(result['ruleId']) }

  if control
    control['results'] << finding(result)
  else
    rule_info = get_rule_info(run, result, result['ruleId'])
    item = {}
    item['tags']               = rule_info['rule_tags']
    item['descriptions']       = []
    item['refs']               = NA_ARRAY
    item['source_location']    = { ref: get_location(result)['uri'], line: get_location(result)['start_line'] }
    item['descriptions']       = NA_ARRAY
    item['title']              = rule_info['rule_name'].to_s
    item['id']                 = result['ruleId'].to_s
    item['desc']               = rule_info['rule_short_description'].to_s
    item['impact']             = impact(result['level'].to_s)
    item['code']               = NA_STRING
    item['results']            = [finding(result)]
    item['tags']               = add_nist_tag_from_cwe(parse_identifiers(rule_info['rule_tags'], 'CWE'), 'nist', item['tags'])
    controls << item
  end
end

#to_hdfObject



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/heimdall_tools/sarif_mapper.rb', line 180

def to_hdf
  controls = []
  @sarif_log['runs'].each do |run|
    run['results'].each do |result|
      process_item(run, result, controls)
    end
  end

  scaninfo = extract_scaninfo(@sarif_log)
  results = HeimdallDataFormat.new(profile_name: scaninfo['policy'],
                                   version: scaninfo['version'],
                                   title: scaninfo['projectName'],
                                   summary: scaninfo['summary'],
                                   controls: controls,
                                   target_id: scaninfo['projectName'])
  results.to_hdf
end