Skip to content

Commit

Permalink
conclusions: refine and cleanup (#416)
Browse files Browse the repository at this point in the history
* conclusions: refine and cleanup

* nit
  • Loading branch information
DavidKorczynski committed Jul 26, 2022
1 parent 18f1719 commit 18bb85f
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 64 deletions.
2 changes: 1 addition & 1 deletion src/fuzz_introspector/analyses/bug_digestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions: List[Tuple[int, str]]
conclusions: List[html_helpers.HTMLConclusion]
) -> str:
"""Digests and creates HTML about bugs found by the fuzzers."""
logger.info(f" - Running analysis {Analysis.get_name()}")
Expand Down
2 changes: 1 addition & 1 deletion src/fuzz_introspector/analyses/calltree_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions
conclusions: List[html_helpers.HTMLConclusion]
) -> str:
"""
Creates the HTML of the calltree. Returns the HTML as a string.
Expand Down
2 changes: 1 addition & 1 deletion src/fuzz_introspector/analyses/driver_synthesizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions: List[Tuple[int, str]],
conclusions: List[html_helpers.HTMLConclusion],
fuzz_targets=None
) -> str:
logger.info(f" - Running analysis {Analysis.get_name()}")
Expand Down
2 changes: 1 addition & 1 deletion src/fuzz_introspector/analyses/engine_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions: List[Tuple[int, str]]
conclusions: List[html_helpers.HTMLConclusion]
) -> str:
logger.info(f" - Running analysis {Analysis.get_name()}")

Expand Down
2 changes: 1 addition & 1 deletion src/fuzz_introspector/analyses/filepath_analyser.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions: List[Tuple[int, str]]
conclusions: List[html_helpers.HTMLConclusion]
) -> str:
logger.info(f" - Running analysis {Analysis.get_name()}")

Expand Down
4 changes: 2 additions & 2 deletions src/fuzz_introspector/analyses/optimal_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions: List[Tuple[int, str]],
conclusions: List[html_helpers.HTMLConclusion],
should_synthetise: bool = False
) -> str:
"""
Expand Down Expand Up @@ -290,7 +290,7 @@ def get_optimal_target_section(
def get_consequential_section(
self,
new_profile: project_profile.MergedProjectProfile,
conclusions: List[Tuple[int, str]],
conclusions: List[html_helpers.HTMLConclusion],
tables: List[str],
toc_list: List[Tuple[str, str, int]],
coverage_url: str,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions: List[Tuple[int, str]]
conclusions: List[html_helpers.HTMLConclusion]
) -> str:
logger.info(f" - Running analysis {Analysis.get_name()}")

Expand Down
5 changes: 3 additions & 2 deletions src/fuzz_introspector/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from fuzz_introspector import utils
from fuzz_introspector import cfg_load
from fuzz_introspector import cov_load
from fuzz_introspector import html_helpers
from fuzz_introspector.datatypes import (
project_profile,
fuzzer_profile,
Expand All @@ -53,7 +54,7 @@ def analysis_func(
profiles: List[fuzzer_profile.FuzzerProfile],
basefolder: str,
coverage_url: str,
conclusions: List[Tuple[int, str]]
conclusions: List[html_helpers.HTMLConclusion]
) -> str:
"""Entrypoint for analysis instance. This function can have side effects
on many of the arguments passed to it.
Expand All @@ -79,7 +80,7 @@ def analysis_func(
:param conclusions: List of high level conclusions to be shown in the final
report. Append to this list any conclusions that should
be shown at the top of the report page.
:type conclusions: List[Tuple[int, str]]
:type conclusions: List[html_helpers.HTMLConclusion]
:rtype: str
:returns: A string that corresponds to HTML that can be embedded in the
Expand Down
18 changes: 18 additions & 0 deletions src/fuzz_introspector/html_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@
from fuzz_introspector.datatypes import fuzzer_profile


class HTMLConclusion:
"""Represents high-level conclusions in HTML report
Attributes:
severity (int): Importance of conclusion. 100 max, 0 lowest.
title (str): One line description of conclusion.
description (str): Extended description.
"""
def __init__(self, severity, title, description):
self.title = title
self.severity = severity
self.description = description

def __lt__(self, other):
"""Implemented for sorting list of conclusions"""
return self.severity < other.severity


def html_table_add_row(elems: List[Any]) -> str:
html_str = "<tr>\n"
for elem in elems:
Expand Down
97 changes: 43 additions & 54 deletions src/fuzz_introspector/html_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@
import shutil
import json
import typing
import bs4
import random
import string
import matplotlib.pyplot as plt

from matplotlib.patches import Rectangle
from typing import (
Any,
Dict,
Expand All @@ -34,14 +39,6 @@
from fuzz_introspector import html_helpers
from fuzz_introspector.datatypes import project_profile, fuzzer_profile

# For pretty printing the html code:
from bs4 import BeautifulSoup as bs

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

import random
import string

logger = logging.getLogger(name=__name__)

Expand Down Expand Up @@ -366,7 +363,7 @@ def create_covered_func_box(covered_funcs: str) -> str:
def create_boxed_top_summary_info(
tables: List[str],
proj_profile: project_profile.MergedProjectProfile,
conclusions: List[Tuple[int, str]],
conclusions: List[html_helpers.HTMLConclusion],
extract_conclusion: bool,
display_coverage: bool = False
) -> str:
Expand Down Expand Up @@ -404,51 +401,36 @@ def create_boxed_top_summary_info(


def create_conclusions(
conclusions: List[Tuple[int, str]],
conclusions: List[html_helpers.HTMLConclusion],
reached_percentage: float,
reached_complexity_percentage: float
) -> None:
# Functions reachability
sentence = f"""Fuzzers reach { "%.5s%%"%(str(reached_percentage)) } of all functions. """
if reached_percentage > 90.0:
warning = 10
sentence += "This is great."
elif reached_percentage > 75.0:
warning = 8
sentence += "This is good"
elif reached_percentage > 50.0:
warning = 6
sentence += "This is good, but there's room for improvement."
elif reached_percentage > 25.0:
warning = 4
sentence += "Improvements should be made"
else:
warning = 2
sentence += "Improvements need to be made"
conclusions.append((warning, sentence))
conclusions.append(
html_helpers.HTMLConclusion(
severity=int(reached_percentage * 0.1),
title=sentence,
description=""
)
)

# Complexity reachability
percentage_str = "%.5s%%" % str(reached_complexity_percentage)
sentence = f"Fuzzers reach { percentage_str } of cyclomatic complexity. "
if reached_complexity_percentage > 90.0:
warning = 10
sentence += "This is great."
elif reached_complexity_percentage > 70.0:
warning = 8
sentence += "This is pretty nice."
elif reached_complexity_percentage > 50.0:
warning = 6
sentence += "This is okay."
else:
warning = 2
sentence += "Improvements could be made"
conclusions.append((warning, sentence))
conclusions.append(
html_helpers.HTMLConclusion(
severity=int(reached_percentage * 0.1),
title=sentence,
description=""
)
)


def create_top_summary_info(
tables: List[str],
proj_profile: project_profile.MergedProjectProfile,
conclusions: List[Tuple[int, str]],
conclusions: List[html_helpers.HTMLConclusion],
extract_conclusion: bool,
display_coverage: bool = False) -> str:
html_string = ""
Expand Down Expand Up @@ -497,7 +479,7 @@ def create_fuzzer_detailed_section(
toc_list: List[Tuple[str, str, int]],
tables: List[str],
curr_tt_profile: int,
conclusions: List[Tuple[int, str]],
conclusions: List[html_helpers.HTMLConclusion],
extract_conclusion: bool,
fuzzer_table_data: Dict[str, Any]
) -> str:
Expand Down Expand Up @@ -645,11 +627,18 @@ def create_fuzzer_detailed_section(
)
if extract_conclusion:
if cov_reach_proportion < 30.0:
conclusions.append((
2,
(f"Fuzzer { profile.identifier } is blocked: runtime coverage only "
f"covers { str_percentage } of its reachable functions.")
))
conclusions.append(
html_helpers.HTMLConclusion(
2,
f"Fuzzer { profile.identifier } is blocked:",
(
f"The runtime code coverage of { profile.identifier } "
f"covers { str_percentage } of its statically rechable code. "
f"This means there is some place that blocks the fuzzer "
f"to continue exploring more code at run time. "
)
)
)

html_string += "<div style=\"display: flex; margin-bottom: 10px;\">"
html_string += get_simple_box("Covered functions", str(total_hit_functions))
Expand Down Expand Up @@ -718,7 +707,7 @@ def get_simple_box(title: str, value: str) -> str:
</div>"""


def extract_highlevel_guidance(conclusions: List[Tuple[int, str]]) -> str:
def extract_highlevel_guidance(conclusions: List[html_helpers.HTMLConclusion]) -> str:
"""
Creates colorful boxes for the conlusions made throughout the analysis
"""
Expand All @@ -728,18 +717,18 @@ def extract_highlevel_guidance(conclusions: List[Tuple[int, str]]) -> str:

# Sort conclusions to show highest level (positive conclusion) first
conclusions = list(reversed(sorted(conclusions)))
for lvl, sentence in conclusions:
if lvl < 5:
for conclusion in conclusions:
if conclusion.severity < 5:
conclusion_color = "red"
elif lvl < 8:
elif conclusion.severity < 8:
conclusion_color = "yellow"
else:
conclusion_color = "green"
html_string += f"""<div class="line-wrapper">
<div class="high-level-conclusion { conclusion_color }-conclusion collapsed">
{ sentence }
{ conclusion.title }
<div class="high-level-extended" style="background:transparent; overflow:hidden">
Description
{ conclusion.description }
</div>
</div>
</div>"""
Expand All @@ -761,7 +750,7 @@ def create_html_report(
"""
tables: List[str] = list()
toc_list: List[Tuple[str, str, int]] = list()
conclusions: List[Tuple[int, str]] = []
conclusions: List[html_helpers.HTMLConclusion] = []

logger.info(" - Creating HTML report")

Expand Down Expand Up @@ -973,7 +962,7 @@ def create_html_report(
+ html_footer)

# Pretty print the html document
soup = bs(html_full_doc, "html.parser")
soup = bs4.BeautifulSoup(html_full_doc, "html.parser")
prettyHTML = soup.prettify()

# Remove existing html report
Expand Down

0 comments on commit 18bb85f

Please sign in to comment.