from __future__ import annotations from prettytable import PrettyTable from vuln_scan.core.models import Finding from vuln_scan.reporting.base import Reporter class PrettyTableReporter(Reporter): def render(self, findings: list[Finding], dependabot_url: str) -> str: if not findings: message = "No Vulnerabilities Found." print(message) return message rows = [self.extract_row(f) for f in findings] blocking_count, non_blocking_count = self.summary_counts(findings) table = PrettyTable( [ "File", "Package", "Current Version", "Min. Required Version", "Vulnerable Range", "Severity", "Blocking", "Grace Period", "Blocking Date", "Reason", ] ) table.title = "Dependency Vulnerabilities" table.align["Reason"] = "l" table.align["Package"] = "l" table.align["File"] = "l" for row in rows: table.add_row( [ row.file, row.package, row.version, row.patch, row.vuln_range, row.severity.upper(), "YES" if row.is_blocking else "NO", row.grace_period, row.blocking_date, row.reason, ] ) table_output = table.get_string().strip() total = len(rows) summary = ( f"\nTotal findings: {total} " f"({blocking_count} blocking, {non_blocking_count} non-blocking)" ) # Terminal output includes everything print(table_output) print(summary) print(f"Dependabot alerts: {dependabot_url}") # Return table and summary separated by a null byte delimiter # so the publisher can format them independently return f"{table_output}\x00{summary}"