Skip to content

Commit

Permalink
make report html tags configurable (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
darkspirit510 authored Jun 16, 2024
1 parent 0d2973d commit 0862b3b
Show file tree
Hide file tree
Showing 11 changed files with 353 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,31 +92,6 @@ public class BenchmarkScore extends AbstractMojo {
// The values stored in this is pulled from the categories.xml config file
// public static Categories CATEGORIES;

// This is the default project link. This is set to "" if includeProjectLink set to false.
// TODO: Make this value configurable via .yaml file
public static String PROJECTLINKENTRY =
" <p>\n"
+ " For more information, please visit the <a href=\"https://owasp.org/www-project-benchmark/\">OWASP Benchmark Project Site</a>.\n"
+ " </p>\n";

// This is the Key Entry for Precision, which is added to the Key for tables that include
// Precision. If includePrecision explicitly set to false via .yaml, then this default value set
// to "".
public static String PRECISIONKEYENTRY =
"<tr>\n"
+ " <th>Precision = TP / ( TP + FP )</th>\n"
+ " <td>The percentage of reported vulnerabilities that are true positives. Defined at <a href=\"https://en.wikipedia.org/wiki/Precision_and_recall\">Wikipedia</a>.</td>\n"
+ " </tr>\n";

// This is the Key Entry for F-Score, which is added to the Key for tables that also include
// Precision. If includePrecision explicitly set to false via .yaml, then this default value set
// to "".
public static String FSCOREKEYENTRY =
"<tr>\n"
+ " <th>F-score = 2 * Precision * Recall / (Precision + Recall)</th>\n"
+ " <td>The harmonic mean of the precision and recall. A value of 1.0 indicates perfect precision and recall. Defined at <a href=\"https://en.wikipedia.org/wiki/F-score\">Wikipedia</a>.</td>\n"
+ " </tr>\n";

/*
* The set of all the Tools. Each Tool includes the results for that tool.
*/
Expand Down Expand Up @@ -157,17 +132,6 @@ static void loadConfigFromCommandLineArguments(String[] args) {
throw new IllegalArgumentException();
}
}

// TODO: move to html class (once this has been extracted, too)
if (!config.includeProjectLink) {
PROJECTLINKENTRY = "";
}

if (!config.includePrecision) {
// These two values are both included or not included together (currently)
PRECISIONKEYENTRY = "";
FSCOREKEYENTRY = "";
}
}

@Override
Expand Down Expand Up @@ -497,9 +461,6 @@ public static void main(String[] args) {
config,
TESTSUITENAME,
TESTSUITEVERSION,
PROJECTLINKENTRY,
PRECISIONKEYENTRY,
FSCOREKEYENTRY,
commercialAveragesTable,
tools,
catSet,
Expand All @@ -516,13 +477,13 @@ public static void main(String[] args) {

String html =
new String(Files.readAllBytes(homeFilePath))
.replace("${projectlink}", BenchmarkScore.PROJECTLINKENTRY)
.replace("${projectlink}", config.report.html.projectLinkEntry)
.replace("${table}", overallStatsTable.generateFor(tools))
.replace("${tprlabel}", config.tprLabel)
.replace(
"${precisionkey}",
BenchmarkScore.PRECISIONKEYENTRY
+ BenchmarkScore.FSCOREKEYENTRY);
config.report.html.precisionKeyEntry
+ config.report.html.fsCoreEntry);

Files.write(homeFilePath, html.getBytes());
} catch (IOException e) {
Expand Down Expand Up @@ -980,14 +941,15 @@ private static void generateVulnerabilityScorecards(
"${vulnerability}",
cat + " (CWE #" + BenchmarkScore.translateNameToCWE(cat) + ")");
html = html.replace("${version}", TESTSUITEVERSION);
html = html.replace("${projectlink}", BenchmarkScore.PROJECTLINKENTRY);
html = html.replace("${projectlink}", config.report.html.projectLinkEntry);

html = html.replace("${table}", vulnerabilityStatsTable.generateFor(cat));
html = html.replace("${tprlabel}", config.tprLabel);
html =
html.replace(
"${precisionkey}",
BenchmarkScore.PRECISIONKEYENTRY + BenchmarkScore.FSCOREKEYENTRY);
config.report.html.precisionKeyEntry
+ config.report.html.fsCoreEntry);

Files.write(htmlFile.toPath(), html.getBytes());

Expand Down Expand Up @@ -1015,14 +977,15 @@ private static void generateVulnerabilityScorecards(
String html = IOUtils.toString(vulnTemplateStream, StandardCharsets.UTF_8);
html = html.replace("${testsuite}", BenchmarkScore.TESTSUITENAME.fullName());
html = html.replace("${version}", TESTSUITEVERSION);
html = html.replace("${projectlink}", BenchmarkScore.PROJECTLINKENTRY);
html = html.replace("${projectlink}", config.report.html.projectLinkEntry);

html = html.replace("${table}", commercialAveragesTable.render());
html = html.replace("${tprlabel}", config.tprLabel);
html =
html.replace(
"${precisionkey}",
BenchmarkScore.PRECISIONKEYENTRY + BenchmarkScore.FSCOREKEYENTRY);
config.report.html.precisionKeyEntry
+ config.report.html.fsCoreEntry);

Files.write(htmlfile, html.getBytes());
System.out.println("Commercial average scorecard computed.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public class Configuration {
/** Indicates whether Precision score should be included in generated tables. By default, no. */
public final boolean includePrecision;

public final Report report;

private static final Yaml yaml = new Yaml();

public static Configuration fromDefaultConfig() {
Expand Down Expand Up @@ -110,7 +112,7 @@ private static Configuration fromInputStream(InputStream stream, String successM
}

private Configuration(Map<String, Object> yamlConfig) {
this.expectedResultsFileName = (String) yamlConfig.get("expectedresults");
expectedResultsFileName = (String) yamlConfig.get("expectedresults");
focus = (String) yamlConfig.get("focustool");
anonymousMode = (Boolean) yamlConfig.get("anonymousmode");
mixedMode = (Boolean) yamlConfig.get("mixedmode");
Expand All @@ -120,6 +122,8 @@ private Configuration(Map<String, Object> yamlConfig) {
tprLabel = (String) yamlConfig.get("tprlabel");
includeProjectLink = (Boolean) yamlConfig.get("includeprojectlink");
includePrecision = (Boolean) yamlConfig.get("includeprecision");

report = new Report(yamlConfig);
}

public static Configuration fromFile(String pathToFile) {
Expand All @@ -136,4 +140,113 @@ public ConfigCouldNotBeParsed(String message) {
super(message);
}
}

private Object deepGet(Map<?, ?> input, String... path) {
Map<?, ?> current = input;

for (int i = 0; i < path.length - 1; i++) {
current = (Map<?, ?>) current.get(path[i]);
}

return current.get(path[path.length - 1]);
}

private String getOrDefault(StringCallback sc, String defaultValue) {
try {
return sc.run();
} catch (Throwable ignored) {
return defaultValue;
}
}

public class Report {

public final Html html;

public Report(Map<String, Object> yamlConfig) {
this.html = new Html(yamlConfig);
}

public class Html {

/** Link to project, is empty if includeProjectLink is false */
public final String projectLinkEntry;

/**
* Key Entry for Precision, which is added to the Key for tables that include Precision.
* Is empty if includePrecision is set to false via config
*/
public final String precisionKeyEntry;

/**
* Key Entry for F-Score, which is added to the Key for tables that also include
* Precision. Is empty if includePrecision is set to false via config
*/
public final String fsCoreEntry;

private static final String DEFAULT_PROJECT_LINK =
" <p>\n"
+ " For more information, please visit the <a href=\"https://owasp.org/www-project-benchmark/\">OWASP Benchmark Project Site</a>.\n"
+ " </p>\n";

private static final String DEFAULT_PRECISION_KEY =
"<tr>\n"
+ " <th>Precision = TP / ( TP + FP )</th>\n"
+ " <td>The percentage of reported vulnerabilities that are true positives. Defined at <a href=\"https://en.wikipedia.org/wiki/Precision_and_recall\">Wikipedia</a>.</td>\n"
+ " </tr>\n";

private static final String DEFAULT_FS_CORE_ENTRY =
"<tr>\n"
+ " <th>F-score = 2 * Precision * Recall / (Precision + Recall)</th>\n"
+ " <td>The harmonic mean of the precision and recall. A value of 1.0 indicates perfect precision and recall. Defined at <a href=\"https://en.wikipedia.org/wiki/F-score\">Wikipedia</a>.</td>\n"
+ " </tr>\n";

public Html(Map<String, Object> yamlConfig) {
if ((Boolean) yamlConfig.get("includeprojectlink")) {
projectLinkEntry =
getOrDefault(
() ->
(String)
deepGet(
yamlConfig,
"report",
"html",
"projectLinkEntry"),
DEFAULT_PROJECT_LINK);
} else {
projectLinkEntry = "";
}

if ((Boolean) yamlConfig.get("includeprecision")) {
precisionKeyEntry =
getOrDefault(
() ->
(String)
deepGet(
yamlConfig,
"report",
"html",
"precisionKeyEntry"),
DEFAULT_PRECISION_KEY);
fsCoreEntry =
getOrDefault(
() ->
(String)
deepGet(
yamlConfig,
"report",
"html",
"fsCoreEntry"),
DEFAULT_FS_CORE_ENTRY);
} else {
precisionKeyEntry = "";
fsCoreEntry = "";
}
}
}
}

private interface StringCallback {
String run();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public String generateHtml(Tool currentTool, String title, File scorecardImageFi
.format(overallToolResults.getOverallScore()));
html = html.replace("${tool}", currentTool.getToolName());
html = html.replace("${version}", currentTool.getTestSuiteVersion());
html = html.replace("${projectlink}", BenchmarkScore.PROJECTLINKENTRY);
html = html.replace("${projectlink}", BenchmarkScore.config.report.html.projectLinkEntry);
html = html.replace("${cwecategoryname}", BenchmarkScore.config.cweCategoryName);
html = html.replace("${actualResultsFile}", currentTool.getActualResultsFileName());

Expand All @@ -88,7 +88,8 @@ public String generateHtml(Tool currentTool, String title, File scorecardImageFi
html =
html.replace(
"${precisionkey}",
BenchmarkScore.PRECISIONKEYENTRY + BenchmarkScore.FSCOREKEYENTRY);
BenchmarkScore.config.report.html.precisionKeyEntry
+ BenchmarkScore.config.report.html.fsCoreEntry);

// Calculate the image tags for the Precision/Recall tables, if includePrecision enabled
String precisionTablesVal =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ public class MenuUpdater {
private final Configuration config;
private final TestSuiteName testSuite;
private final String testSuiteVersion;
private final String projectLinkEntry;
private final String precisionKeyEntry;
private final String fsCoreEntry;
private final CommercialAveragesTable commercialAveragesTable;
private final Set<Tool> tools;
private final Set<String> catSet;
Expand All @@ -48,9 +45,6 @@ public MenuUpdater(
Configuration config,
TestSuiteName testSuite,
String testSuiteVersion,
String projectLinkEntry,
String precisionKeyEntry,
String fsCoreEntry,
CommercialAveragesTable commercialAveragesTable,
Set<Tool> tools,
Set<String> catSet,
Expand All @@ -59,9 +53,6 @@ public MenuUpdater(
this.config = config;
this.testSuite = testSuite;
this.testSuiteVersion = testSuiteVersion;
this.projectLinkEntry = projectLinkEntry;
this.precisionKeyEntry = precisionKeyEntry;
this.fsCoreEntry = fsCoreEntry;
this.commercialAveragesTable = commercialAveragesTable;
this.tools = tools;
this.catSet = catSet;
Expand Down Expand Up @@ -139,9 +130,12 @@ private void updateMenuFor(File f, String toolMenu, String vulnerabilityMenu) {
.replace("${vulnmenu}", vulnerabilityMenu)
.replace("${testsuite}", testSuite.fullName())
.replace("${version}", testSuiteVersion)
.replace("${projectlink}", projectLinkEntry)
.replace("${projectlink}", config.report.html.projectLinkEntry)
.replace("${cwecategoryname}", config.cweCategoryName)
.replace("${precisionkey}", precisionKeyEntry + fsCoreEntry);
.replace(
"${precisionkey}",
config.report.html.precisionKeyEntry
+ config.report.html.fsCoreEntry);

Files.write(f.toPath(), html.getBytes());
} catch (IOException e) {
Expand Down
Loading

0 comments on commit 0862b3b

Please sign in to comment.