Skip to content

Commit a769671

Browse files
committed
LCORE-2631: Generate graphs
1 parent 890a6f7 commit a769671

1 file changed

Lines changed: 100 additions & 3 deletions

File tree

scripts/vulnerability_report.py

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ def process_dependabot_file(dependabot_file: str) -> dict[str, Any]:
409409
410410
Returns:
411411
dict[str, Any]: A dictionary with keys: "count", "state", "severity", "severities",
412-
"days", "packages", and "dates", each containing the corresponding computed metrics.
412+
"days", "packages", and "dates", each containing the
413+
corresponding computed metrics.
413414
"""
414415
source_data = load_dependabot_file(dependabot_file)
415416

@@ -491,6 +492,98 @@ def generate_severity_graph(
491492
save_graph(fig, prefix, "severity", svg_output, png_output)
492493

493494

495+
def generate_vuln_for_days_graph(
496+
stat: dict[str, Any], prefix: str, svg_output: bool, png_output: bool
497+
) -> None:
498+
"""
499+
Generate a histogram of the distribution of days required to fix vulnerabilities.
500+
501+
Parameters:
502+
stat (dict[str, Any]): Statistics dictionary
503+
prefix (str): Prefix for the output file name.
504+
svg_output (bool): If true, save the graph as SVG.
505+
png_output (bool): If true, save the graph as PNG.
506+
"""
507+
fig, ax = plt.subplots()
508+
D = stat["days"]["days"]
509+
ax.hist(D, bins=30, edgecolor="black")
510+
ax.set_ylim(top=100)
511+
ax.set_xlabel("Days")
512+
ax.set_title("Fixed in day(s)")
513+
save_graph(fig, prefix, "days", svg_output, png_output)
514+
515+
516+
def generate_vulnerable_packages_graph(
517+
stat: dict[str, Any], prefix: str, svg_output: bool, png_output: bool
518+
) -> None:
519+
"""
520+
Generate a bar chart showing the top 10 packages with the most CVEs.
521+
522+
Parameters:
523+
stat (dict[str, Any]): Statistics dictionary containing vulnerability
524+
data, with "packages" key holding package frequency counts.
525+
prefix (str): Prefix for the output file name.
526+
svg_output (bool): If true, save the graph as SVG.
527+
png_output (bool): If true, save the graph as PNG.
528+
"""
529+
fig, ax = plt.subplots()
530+
D = stat["packages"]
531+
names, counts = zip(*D.most_common(10))
532+
ax.bar(names, counts, edgecolor="black")
533+
ax.set_ylim(top=100)
534+
ax.set_title("CVEs per package")
535+
ax.tick_params(axis="x", labelrotation=90)
536+
fig.tight_layout()
537+
save_graph(fig, prefix, "packages", svg_output, png_output)
538+
539+
540+
def generate_new_cve_dates_graph(
541+
stat: dict[str, Any], prefix: str, svg_output: bool, png_output: bool
542+
) -> None:
543+
"""
544+
Create a line chart showing new CVE detection dates over time.
545+
546+
Parameters:
547+
stat (dict[str, Any]): Statistics dictionary with "dates" key
548+
containing a Counter of datetime objects mapped to occurrence counts.
549+
prefix (str): Base filename prefix for output files.
550+
svg_output (bool): Whether to save the graph as SVG.
551+
png_output (bool): Whether to save the graph as PNG.
552+
"""
553+
fig, ax = plt.subplots()
554+
D = stat["dates"]
555+
dates, counts = zip(*sorted(D.items(), key=lambda x: x[0]))
556+
ax.plot(dates, counts)
557+
ax.set_title("New CVEs timeline")
558+
save_graph(fig, prefix, "timeline", svg_output, png_output)
559+
560+
561+
def generate_graphs(
562+
stat: dict[str, Any], prefix: str, svg_output: bool, png_output: bool
563+
) -> None:
564+
"""
565+
Generate vulnerability visualization graphs.
566+
"""
567+
generate_overal_state_graph(stat, prefix, svg_output, png_output)
568+
generate_severity_graph(stat, prefix, svg_output, png_output)
569+
generate_vuln_for_days_graph(stat, prefix, svg_output, png_output)
570+
generate_vulnerable_packages_graph(stat, prefix, svg_output, png_output)
571+
generate_new_cve_dates_graph(stat, prefix, svg_output, png_output)
572+
573+
574+
def generate_page(
575+
stat: dict[str, Any], prefix: str, organization: str, repository: str
576+
) -> None:
577+
"""
578+
Generate HTML page containing visualization graphs.
579+
"""
580+
filename = f"vulnerabilities_{prefix}.html"
581+
output = f"""<!DOCTYPE html>
582+
"""
583+
with open(filename, "w", encoding="utf-8") as fout:
584+
fout.write(output)
585+
586+
494587
def main() -> int:
495588
"""
496589
CLI entry point that retrieves Dependabot issues and produces Vulnerability report.
@@ -514,8 +607,12 @@ def main() -> int:
514607
dependabot_file = dependabot_file_name(args)
515608
prefix = args.repository
516609
stat = process_dependabot_file(dependabot_file)
517-
print(stat)
518-
print(prefix)
610+
611+
if args.generate_graphs:
612+
generate_graphs(stat, prefix, args.svg_output, args.png_output)
613+
614+
if args.generate_page:
615+
generate_page(stat, prefix, args.organization, args.repository)
519616

520617
return 0
521618

0 commit comments

Comments
 (0)