-
Notifications
You must be signed in to change notification settings - Fork 360
/
cppcheck_createrules.py
156 lines (124 loc) · 5.43 KB
/
cppcheck_createrules.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# C++ Community Plugin (cxx plugin)
# Copyright (C) 2010-2022 SonarOpenCommunity
# http://github.com/SonarOpenCommunity/sonar-cxx
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import sys
import os
import textwrap
from utils_createrules import CDATA
from utils_createrules import write_rules_xml
from utils_createrules import get_cdata_capable_xml_etree
SEVERITY_TO_SONARQUBE = {
"error": {"type": "BUG", "priority": "MAJOR"},
"warning": {"type": "BUG", "priority": "MINOR"},
"portability": {"type": "BUG", "priority": "MINOR"},
"performance": {"type": "BUG", "priority": "MINOR"},
"style": {"type": "CODE_SMELL", "priority": "MINOR"},
"information": {"type": "CODE_SMELL", "priority": "MINOR"},
}
CWE_MAP = None
et = get_cdata_capable_xml_etree()
def message_with_cwe_reference(msg, cwe_nr):
cwe_msg = CWE_MAP.get(str(cwe_nr), None)
if cwe_msg is None:
sys.stderr.write('CWE ID ' + cwe_nr + ' was not found!\n')
href_text = "CWE-{}".format(
cwe_nr) if cwe_msg is None else "CWE-{}: {}".format(cwe_nr, cwe_msg)
msg_wrapped = textwrap.fill(msg)
return """<p>
{}
</p>
<h2>References</h2>
<p><a href="https://cwe.mitre.org/data/definitions/{}.html" target="_blank">{}</a></p>""".format(msg_wrapped.replace("\\012", "\n"), cwe_nr, href_text)
def error_to_rule(error):
rule = et.Element('rule')
errId = error.attrib["id"]
errMsg = error.attrib["msg"]
errDetails = error.attrib["verbose"]
errSeverity = error.attrib["severity"]
sonarQubeIssueType = SEVERITY_TO_SONARQUBE[errSeverity]["type"]
sonarQubeIssueSeverity = SEVERITY_TO_SONARQUBE[errSeverity]["priority"]
et.SubElement(rule, 'key').text = errId
et.SubElement(rule, 'name').text = errMsg if not errMsg.endswith(
".") else errMsg[:-1]
cweNr = None
if "cwe" in error.attrib:
cweNr = error.attrib["cwe"]
elif errId.endswith("Called") and errSeverity == "style":
# there is no CWE number, but such checks come from libraries and
# warn about obsolete or not thread-safe functions
cweNr = 477
if cweNr is not None:
errDetails = message_with_cwe_reference(errDetails, cweNr)
# encode description tag always as CDATA
cdata = CDATA(errDetails)
et.SubElement(rule, 'description').append(cdata)
if cweNr is not None:
et.SubElement(rule, 'tag').text = "cwe"
if sonarQubeIssueSeverity != 'MAJOR': # MAJOR is the default
et.SubElement(rule, 'severity').text = sonarQubeIssueSeverity
if sonarQubeIssueType != 'CODE_SMELL': # CODE_SMELL is the default
et.SubElement(rule, 'type').text = sonarQubeIssueType
if sonarQubeIssueSeverity != 'INFO': # INFO has no effort
et.SubElement(rule, 'remediationFunction').text = "CONSTANT_ISSUE"
et.SubElement(rule, 'remediationFunctionBaseEffort').text = "5min"
return rule
def create_cppcheck_rules(cppcheck_errors):
rules = et.Element('rules')
for cppcheck_error in cppcheck_errors:
rules.append(error_to_rule(cppcheck_error))
return rules
def load_cwe(path):
id_to_name = {}
tree = et.parse(path)
cwe_root = tree.getroot()
ns0 = '{http://cwe.mitre.org/cwe-6}'
for catalog_tag in cwe_root.iter(ns0 + 'Weakness_Catalog'):
for weaknesses_tag in catalog_tag.iter(ns0 + 'Weaknesses'):
for weakness_tag in weaknesses_tag.iter(ns0 + 'Weakness'):
id_attr = weakness_tag.attrib["ID"]
name_attr = weakness_tag.attrib["Name"]
id_to_name[id_attr] = name_attr
for categories_tag in catalog_tag.iter(ns0 + 'Categories'):
for category_tag in categories_tag.iter(ns0 + 'Category'):
id_attr = category_tag.attrib["ID"]
name_attr = category_tag.attrib["Name"]
id_to_name[id_attr] = name_attr
return id_to_name
def print_usage_and_exit():
script_name = os.path.basename(sys.argv[0])
print("""Usage: %s rules <cwec_vN.N.xml> < cppcheck --errorlist --xml-version=2 --library=<lib0.cfg> --library=<lib1.cfg>
see generate_cppcheck_resources.sh/.cmd for more details""" % (script_name))
sys.exit(1)
def parse_cppcheck_errorlist(f):
tree = et.parse(f)
cppcheck_root = tree.getroot()
cppcheck_errors = []
for errors_tag in cppcheck_root.iter('errors'):
for error_tag in errors_tag.iter('error'):
cppcheck_errors.append(error_tag)
return cppcheck_errors
if __name__ == "__main__":
if len(sys.argv) < 3:
print_usage_and_exit()
# transform to an other elementtree
if sys.argv[1] == "rules":
errors = parse_cppcheck_errorlist(sys.stdin)
CWE_MAP = load_cwe(sys.argv[2])
root = create_cppcheck_rules(errors)
write_rules_xml(root, sys.stdout)
else:
print_usage_and_exit()