Skip to content

Commit 7ac5e9d

Browse files
committed
cshtml --cwe-names: load CWE names from a CSV file
1 parent 223cafd commit 7ac5e9d

File tree

13 files changed

+11694
-12
lines changed

13 files changed

+11694
-12
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_library(cs STATIC
2929
csv-parser.cc
3030
cswriter.cc
3131
cwe-mapper.cc
32+
cwe-name-lookup.cc
3233
deflookup.cc
3334
gcc-parser.cc
3435
html-writer.cc

src/cshtml.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
#include "abstract-parser.hh"
21+
#include "cwe-name-lookup.hh"
2122
#include "deflookup.hh"
2223
#include "html-writer.hh"
2324
#include "instream.hh"
@@ -26,6 +27,11 @@
2627

2728
#include <boost/program_options.hpp>
2829

30+
#ifndef DEFAULT_CWE_NAMES_FILE
31+
# define DEFAULT_CWE_NAMES_FILE "/usr/share/csdiff/cwe-names.csv"
32+
#endif
33+
static const char fnCweNamesDefault[] = DEFAULT_CWE_NAMES_FILE;
34+
2935
std::string titleFromFileName(const std::string &fileName)
3036
{
3137
if (!fileName.compare("-"))
@@ -57,9 +63,13 @@ int main(int argc, char *argv[])
5763

5864
typedef std::vector<string> TStringList;
5965
string defUrlTemplate, fnBase, checkerIgnRegex, plainTextUrl, spPosition;
66+
string fnCweNames;
6067

6168
try {
6269
desc.add_options()
70+
("cwe-names",
71+
po::value(&fnCweNames)->default_value(fnCweNamesDefault),
72+
"CSV file mapping CWE numbers to names")
6373
("defect-url-template", po::value(&defUrlTemplate),
6474
"e.g. http://localhost/index.php?proj=%d&defect=%d")
6575
("diff-base", po::value(&fnBase),
@@ -152,6 +162,14 @@ int main(int argc, char *argv[])
152162
diffTitleFallback);
153163
}
154164

165+
// initialize CWE names lookup
166+
CweNameLookup cweNames;
167+
if (!fnCweNames.empty()) {
168+
InStream strCweNames(fnCweNames);
169+
cweNames.parse(strCweNames);
170+
writer.setCweNameLookup(&cweNames);
171+
}
172+
155173
// write HTML
156174
writer.handleFile(pInput, fnInput);
157175
writer.flush();

src/csv-parser.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ bool AbstractCsvParser::parse(InStream &ins)
4848

4949
std::istream &str = ins.str();
5050
std::string line;
51-
for (d->lineno = 0; std::getline(str, line); d->lineno++) {
51+
for (d->lineno = 1; std::getline(str, line); d->lineno++) {
5252
// initialize tokenizer
5353
typedef boost::escaped_list_separator<char> TSeparator;
5454
typedef boost::tokenizer<TSeparator> TTokenizer;

src/cwe-name-lookup.cc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (C) 2020 Red Hat, Inc.
3+
*
4+
* This file is part of csdiff.
5+
*
6+
* csdiff is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* any later version.
10+
*
11+
* csdiff is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with csdiff. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "cwe-name-lookup.hh"
21+
22+
#include "parser-common.hh"
23+
24+
#include <map>
25+
26+
struct CweNameLookup::Private {
27+
typedef std::map<int, std::string> TMap;
28+
TMap nameByCwe;
29+
const std::string emp;
30+
};
31+
32+
CweNameLookup::CweNameLookup():
33+
d(new Private)
34+
{
35+
}
36+
37+
CweNameLookup::~CweNameLookup()
38+
{
39+
delete d;
40+
}
41+
42+
bool CweNameLookup::handleLine(const TStringList &fields)
43+
{
44+
if (2U != fields.size()) {
45+
this->parseError("invalid count of fields");
46+
return /* continue */ true;
47+
}
48+
49+
// parse CWE number
50+
const std::string &cweId = fields[/* CWE */ 0];
51+
const int cwe = parse_int(cweId, -1);
52+
if (cwe < 0) {
53+
this->parseError("invalid CWE ID");
54+
return /* continue */ true;
55+
}
56+
57+
// lookup by CWE number
58+
if (d->nameByCwe.count(cwe))
59+
this->parseError("CWE name redefinition");
60+
61+
// define the mapping
62+
const std::string &cweName = fields[/* name */ 1];
63+
d->nameByCwe[cwe] = cweName;
64+
65+
return /* continue */ true;
66+
}
67+
68+
const std::string& CweNameLookup::lookup(const int cwe) const
69+
{
70+
const Private::TMap::const_iterator it = d->nameByCwe.find(cwe);
71+
return (d->nameByCwe.end() == it)
72+
? d->emp
73+
: it->second;
74+
}

src/cwe-name-lookup.hh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (C) 2020 Red Hat, Inc.
3+
*
4+
* This file is part of csdiff.
5+
*
6+
* csdiff is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* any later version.
10+
*
11+
* csdiff is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with csdiff. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef H_GUARD_CWE_NAME_LOOKUP_H
21+
#define H_GUARD_CWE_NAME_LOOKUP_H
22+
23+
#include "abstract-filter.hh"
24+
#include "csv-parser.hh"
25+
26+
#include <iostream>
27+
28+
class CweNameLookup: public AbstractCsvParser {
29+
public:
30+
CweNameLookup();
31+
virtual ~CweNameLookup();
32+
33+
/// return name of the given CWE ID, or an empty string if not found
34+
const std::string& lookup(const int cwe) const;
35+
36+
protected:
37+
virtual bool /* continue */ handleLine(const TStringList &);
38+
39+
private:
40+
struct Private;
41+
Private *d;
42+
};
43+
44+
#endif /* H_GUARD_CWE_NAME_LOOKUP_H */

src/html-writer.cc

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "html-writer.hh"
2121

22+
#include "cwe-name-lookup.hh"
2223
#include "deflookup.hh"
2324
#include "regex.hh"
2425

@@ -195,12 +196,16 @@ void linkifyShellCheckMsg(std::string *pMsg)
195196
"\\1SC\\2\\3</a>");
196197
}
197198

198-
void printCweLink(std::ostream &str, const int cwe)
199+
void printCweLink(std::ostream &str, const int cwe, const std::string &cweName)
199200
{
200201
str << "<a href=\"https://cwe.mitre.org/data/definitions/"
201-
<< cwe << ".html\""
202-
<< " title=\"definition of CWE-"
203-
<< cwe << " by MITRE\">"
202+
<< cwe << ".html\" title=\"";
203+
if (cweName.empty())
204+
str << "definition of CWE-" << cwe << " by MITRE";
205+
else
206+
str << "CWE-" << cwe << ": " << cweName;
207+
208+
str << "\">"
204209
<< "CWE-" << cwe
205210
<< "</a>";
206211
}
@@ -303,11 +308,12 @@ struct HtmlWriter::Private {
303308
HtmlWriterCore core;
304309
TScanProps scanProps;
305310
const std::string defUrlTemplate;
306-
unsigned defCnt;
307-
DefLookup *baseLookup;
311+
unsigned defCnt = 0U;
312+
DefLookup *baseLookup = nullptr;
308313
RE checkerIgnRegex;
309314
std::string newDefMsg;
310315
std::string plainTextUrl;
316+
const CweNameLookup *cweNames = nullptr;
311317

312318
Private(
313319
std::ostream &str_,
@@ -316,9 +322,7 @@ struct HtmlWriter::Private {
316322
const std::string &spPlacement_):
317323
str(str_),
318324
core(str_, titleFallback_, spPlacement_),
319-
defUrlTemplate(defUrlTemplate_),
320-
defCnt(0),
321-
baseLookup(0)
325+
defUrlTemplate(defUrlTemplate_)
322326
{
323327
if (!defUrlTemplate.empty())
324328
// just make sure that the format string is correct
@@ -394,6 +398,11 @@ void HtmlWriter::setPlainTextUrl(const std::string &url)
394398
d->plainTextUrl = url;
395399
}
396400

401+
void HtmlWriter::setCweNameLookup(const CweNameLookup *cweNames)
402+
{
403+
d->cweNames = cweNames;
404+
}
405+
397406
void HtmlWriter::Private::writeLinkToDetails(const Defect &def)
398407
{
399408
const int defId = def.defectId;
@@ -451,13 +460,19 @@ void HtmlWriter::handleDef(const Defect &def)
451460

452461
d->str << "<b>Error: <span style='background: #C0FF00;'>"
453462
<< HtmlLib::escapeTextInline(def.checker) << "</span>";
454-
if (def.cwe) {
463+
464+
const int cwe = def.cwe;
465+
if (cwe) {
466+
std::string cweName;
467+
if (d->cweNames)
468+
cweName = d->cweNames->lookup(cwe);
455469
d->str << " (";
456-
printCweLink(d->str, def.cwe);
470+
printCweLink(d->str, cwe, cweName);
457471
d->str << ")";
458472
}
459473
else
460474
d->str << HtmlLib::escapeTextInline(def.annotation);
475+
461476
d->str << ":</b>";
462477

463478
d->writeLinkToDetails(def);

src/html-writer.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "abstract-writer.hh"
2424

25+
class CweNameLookup;
2526
class DefLookup;
2627

2728
class HtmlWriter: public AbstractWriter {
@@ -49,6 +50,9 @@ class HtmlWriter: public AbstractWriter {
4950

5051
void setPlainTextUrl(const std::string &);
5152

53+
/// @attention cweNames needs to stay valid long enough (no deep copy)
54+
void setCweNameLookup(const CweNameLookup *cweNames);
55+
5256
private:
5357
struct Private;
5458
Private *d;

tests/cshtml/0001-smoke/runtest.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ set -x
44

55
# run cshtml
66
"${CSHTML_BIN}" \
7+
--cwe-names "" \
78
--diff-base "${TEST_SRC_DIR}/old/scan-results.js" \
89
--diff-base-ignore-checkers "SHELLCHECK_WARNING" \
910
--plain-text-url "scan-results.err" \

0 commit comments

Comments
 (0)