This commit is contained in:
92
src/depcheck/reporters/json.py
Normal file
92
src/depcheck/reporters/json.py
Normal file
@@ -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}")
|
||||
Reference in New Issue
Block a user