Skip to content

Commit

Permalink
per fuzzer coverage plots in overview
Browse files Browse the repository at this point in the history
Signed-off-by: phi-go <dev@philipp-goerz.com>
  • Loading branch information
phi-go committed Feb 17, 2025
1 parent f3bddd0 commit 970d262
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 5 deletions.
16 changes: 16 additions & 0 deletions tools/web-fuzzing-introspection/app/static/assets/db/oss_fuzz.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ def get_code_coverage_summary_url(project_name, datestr):
project_url = base_url.format(project_name, datestr)
return project_url

def get_fuzzer_code_coverage_summary_url(project_name, datestr, fuzzer):
base_url = 'https://storage.googleapis.com/oss-fuzz-coverage/{0}/reports-by-target/{1}/{2}/linux/summary.json'
project_url = base_url.format(project_name, datestr, fuzzer)
return project_url

def get_coverage_report_url(project_name, datestr, language):
if language == 'java' or language == 'python' or language == 'go':
Expand Down Expand Up @@ -255,6 +259,18 @@ def get_code_coverage_summary(project_name, datestr):
except:
return None

def get_fuzzer_code_coverage_summary(project_name, datestr, fuzzer):
cov_summary_url = get_fuzzer_code_coverage_summary_url(project_name, datestr, fuzzer)
try:
coverage_summary_raw = requests.get(cov_summary_url, timeout=20).text
except:
return None
try:
json_dict = json.loads(coverage_summary_raw)
return json_dict
except:
return None


def extract_new_introspector_functions(project_name, date_str):
introspector_functions_url = get_introspector_report_url_all_functions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,8 @@ def extract_and_refine_functions(all_function_list, date_str):
return refined_proj_list


def extract_code_coverage_data(code_coverage_summary, project_name, date_str,
project_language) -> Optional[Dict[str, Any]]:
"""Gets coverage URL and line coverage total of a project"""
def extract_code_coverage_data(code_coverage_summary):
"""Extract the coverage data from a loaded coverage summary.json"""
# Extract data from the code coverage reports
if code_coverage_summary is None:
return None
Expand All @@ -307,6 +306,14 @@ def extract_code_coverage_data(code_coverage_summary, project_name, date_str,
except:
pass

return line_total_summary


def prepare_code_coverage_dict(code_coverage_summary, project_name: str, date_str: str,
project_language: str) -> Optional[Dict[str, Any]]:
"""Gets coverage URL and line coverage total of a project"""
line_total_summary = extract_code_coverage_data(code_coverage_summary)

coverage_url = oss_fuzz.get_coverage_report_url(project_name,
date_str.replace("-", ""),
project_language)
Expand Down Expand Up @@ -442,7 +449,7 @@ def extract_local_project_data(project_name, oss_fuzz_path,
project_name
}

code_coverage_data_dict = extract_code_coverage_data(
code_coverage_data_dict = prepare_code_coverage_dict(
code_coverage_summary, project_name, '', project_language)

if cov_fuzz_stats is not None:
Expand Down Expand Up @@ -704,20 +711,29 @@ def extract_project_data(project_name, date_str, should_include_details,
'project_name': project_name
}

code_coverage_data_dict = extract_code_coverage_data(
code_coverage_data_dict = prepare_code_coverage_dict(
code_coverage_summary, project_name, date_str, project_language)

per_fuzzer_cov = {}
if cov_fuzz_stats is not None:
all_fuzzers = cov_fuzz_stats.split("\n")
if all_fuzzers[-1] == '':
all_fuzzers = all_fuzzers[0:-1]
amount_of_fuzzers = len(all_fuzzers)
for ff in all_fuzzers:
try:
fuzzer_cov = oss_fuzz.get_fuzzer_code_coverage_summary(project_name, date_str.replace("-", ""), ff)
fuzzer_cov_data = extract_code_coverage_data(fuzzer_cov)
per_fuzzer_cov[ff] = fuzzer_cov_data
except:
pass

project_timestamp = {
"project_name": project_name,
"date": date_str,
'language': project_language,
'coverage-data': code_coverage_data_dict,
'per-fuzzer-coverage-data': per_fuzzer_cov,
'introspector-data': introspector_data_dict,
'fuzzer-count': amount_of_fuzzers,
'project_repository': project_repository,
Expand Down
1 change: 1 addition & 0 deletions tools/web-fuzzing-introspection/app/webapp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def load_db() -> None:
project_name=project_timestamp['project_name'],
language=project_timestamp['language'],
coverage_data=project_timestamp['coverage-data'],
per_fuzzer_coverage_data=project_timestamp.get('per-fuzzer-coverage-data', None),
introspector_data=project_timestamp['introspector-data'],
fuzzer_count=project_timestamp['fuzzer-count'],
introspector_url=project_timestamp.get('introspector_url',
Expand Down
2 changes: 2 additions & 0 deletions tools/web-fuzzing-introspection/app/webapp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def __init__(self,
date: str,
language: str,
coverage_data: Optional[Dict[str, Any]],
per_fuzzer_coverage_data: Optional[Dict[str, Dict[str, Any]]],
introspector_data: Optional[Dict[str, Any]],
fuzzer_count: int,
introspector_url: Optional[str] = None,
Expand All @@ -88,6 +89,7 @@ def __init__(self,
self.date = date
self.language = language
self.coverage_data = coverage_data
self.per_fuzzer_coverage_data = per_fuzzer_coverage_data
self.introspector_data = introspector_data
self.fuzzer_count = fuzzer_count
self.introspector_url = introspector_url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ <h2>Historical progression</h2>
<div id="staticReachabilityOverTimePlot" style="width:100%;max-width:500px"></div>
</div>
</div>
</div>
<h2>Per fuzzer progression</h2>
<div id="progress_graphs" class="progress__graph">
</div>
{% else %}
</div>
Expand Down Expand Up @@ -255,6 +258,7 @@ <h1 class="section__title">
const code_coverage_functions_y = [];
const code_reachability_y = [];
const fuzzer_count_y = [];
const fuzzers = new Map();
max_fuzzer_count = 0;


Expand All @@ -270,6 +274,17 @@ <h1 class="section__title">
code_coverage_functions_y.push({{project_timestamp.introspector_data.functions_covered_estimate}});
code_reachability_y.push({{project_timestamp.introspector_data.static_reachability}});
{% endif %}

{% if project_timestamp.per_fuzzer_coverage_data != None %}
{% for (fuzzer, cov_data) in project_timestamp.per_fuzzer_coverage_data.items() %}
if (fuzzers.get("{{fuzzer}}") === undefined) {
fuzzers.set("{{fuzzer}}", {x: [], y: []});
}
var vv = fuzzers.get("{{fuzzer}}");
vv.x.push("{{project_timestamp.date}}");
vv.y.push({{cov_data.percent}});
{%endfor%}
{% endif %}
{% endif %}
{%endfor%}

Expand All @@ -287,6 +302,39 @@ <h1 class="section__title">
};
Plotly.newPlot("codeCoverageLinesOverTimePlot", code_coverage_lines_data, code_coverage_lines_layout);

const progress_graph_div = document.getElementById("progress_graphs")

for (const [fuzzer_name, coverage_percentage] of fuzzers) {
const per_fuzzer_id = 'perFuzzerCoverageLinesOverTimePlot' + fuzzer_name;

const sg_div = document.createElement('div');
sg_div.classList.add('single__graph');
progress_graph_div.appendChild(sg_div);

const gc_div = document.createElement('div');
gc_div.classList.add('graph__chart')
sg_div.appendChild(gc_div);

const the_div = document.createElement('div')
the_div.id = per_fuzzer_id
the_div.style = "width:100%;max-width:500px"
gc_div.appendChild(the_div);

// Plot for fuzzer counter over time
const per_fuzzer_code_coverage_lines_data = [{
x: coverage_percentage.x,
y: coverage_percentage.y,
mode:"lines"
}];
const per_fuzzer_code_coverage_lines_layout = {
xaxis: {title: "Date"},
yaxis: {title: "Coverage", range: [0.0, 100.0]},
title: "Code Coverage (lines) %<br>" + fuzzer_name,
type: "scatter"
};
Plotly.newPlot(per_fuzzer_id, per_fuzzer_code_coverage_lines_data, per_fuzzer_code_coverage_lines_layout);
}

// Plot for fuzzer counter over time
const fuzzer_count_data = [{
x: code_coverage_lines_x,
Expand Down

0 comments on commit 970d262

Please sign in to comment.