From d1ccbceca4b67fc9af8b023fbcd9a42ffef9767d Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Wed, 4 Feb 2026 14:57:54 +0000 Subject: [PATCH] Add analyzers, reporters, and utilities --- src/depcheck/reporters/json.py | 92 ++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/depcheck/reporters/json.py diff --git a/src/depcheck/reporters/json.py b/src/depcheck/reporters/json.py new file mode 100644 index 0000000..0fc11da --- /dev/null +++ b/src/depcheck/reporters/json.py @@ -0,0 +1,92 @@ +"""JSON reporter for CI/CD integration.""" + +import json +from typing import Any, Optional + +from depcheck.config import Config +from depcheck.models import ScanResult, Severity + + +class JSONReporter: + """Report results in JSON format for CI/CD pipelines.""" + + def __init__(self, config: Optional[Config] = None): + self.config = config or Config() + + def report(self, result: ScanResult) -> str: + """Generate JSON report.""" + report_data = self._build_report(result) + return json.dumps(report_data, indent=2) + + def _build_report(self, result: ScanResult) -> dict[str, Any]: + """Build report dictionary.""" + highest_severity = result.get_highest_severity() + report: dict[str, Any] = { + "summary": { + "status": "success" if result.outdated_count == 0 and result.vulnerable_count == 0 else "issues_found", + "dependencies_scanned": len(result.dependencies), + "outdated_packages": result.outdated_count, + "vulnerabilities": result.vulnerable_count, + "highest_severity": highest_severity.value if highest_severity else None, + }, + "dependencies": [], + "vulnerabilities": [], + "errors": result.scan_errors, + } + + for dep in result.dependencies: + dep_data = { + "name": dep.name, + "current_version": dep.current_version, + "latest_version": dep.latest_version, + "is_outdated": dep.is_outdated, + "package_manager": dep.package_manager.value, + "category": dep.category, + "source_file": dep.source_file, + } + report["dependencies"].append(dep_data) + + for dep, vuln in result.vulnerabilities: + vuln_data = { + "package": dep.name, + "current_version": dep.current_version, + "cve_id": vuln.cve_id, + "severity": vuln.severity.value, + "description": vuln.description, + "affected_versions": vuln.affected_versions, + "fixed_version": vuln.fixed_version, + "references": vuln.references, + } + report["vulnerabilities"].append(vuln_data) + + return report + + def get_exit_code(self, result: ScanResult) -> int: + """Determine exit code based on results.""" + if result.scan_errors: + return 2 + + highest_severity = result.get_highest_severity() + if not highest_severity: + return 0 + + severity_order = [Severity.CRITICAL, Severity.HIGH, Severity.MEDIUM, Severity.LOW] + threshold = self.config.fail_level + + try: + threshold_index = severity_order.index(threshold) + except ValueError: + threshold_index = 2 + + if highest_severity in severity_order[:threshold_index + 1]: + return 1 + + return 0 + + def print_error(self, message: str) -> None: + """Print error message (for CLI output).""" + print(f"ERROR: {message}") + + def print_warning(self, message: str) -> None: + """Print warning message (for CLI output).""" + print(f"WARNING: {message}")