compare_library_security
Compare security scores of multiple libraries to identify safer options for your project. Analyze vulnerabilities and get recommendations for informed selection.
Instructions
Compare security scores across multiple libraries to help with selection.
Args:
libraries: List of library names to compare
ecosystem: Package ecosystem for all libraries
Returns:
Security comparison with rankings and recommendations
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| libraries | Yes | ||
| ecosystem | No | PyPI |
Implementation Reference
- MCP tool handler for 'compare_library_security'. Compares security of multiple libraries by parallel scanning each with security_integration.get_security_summary, sorts by score, adds rankings and ratings, generates overall recommendation.async def compare_library_security(libraries: List[str], ecosystem: str = "PyPI"): """ Compare security scores across multiple libraries to help with selection. Args: libraries: List of library names to compare ecosystem: Package ecosystem for all libraries Returns: Security comparison with rankings and recommendations """ await enforce_rate_limit("compare_library_security") from .vulnerability_scanner import security_integration if len(libraries) > 10: return {"error": "Maximum 10 libraries allowed for comparison"} results = [] # Scan all libraries in parallel for faster comparison scan_tasks = [ security_integration.get_security_summary(lib, ecosystem) for lib in libraries ] try: summaries = await asyncio.gather(*scan_tasks, return_exceptions=True) for i, (library, summary_item) in enumerate(zip(libraries, summaries)): if isinstance(summary_item, Exception): results.append( { "library": library, "security_score": 0, "status": "scan_failed", "error": str(summary_item), } ) else: summary = summary_item results.append( { "library": library, "security_score": summary.get("security_score", 0), # type: ignore "status": summary.get("status", "unknown"), # type: ignore "vulnerabilities": summary.get("total_vulnerabilities", 0), # type: ignore "critical_vulnerabilities": summary.get( "critical_vulnerabilities", 0 ), # type: ignore "recommendation": summary.get("primary_recommendation", ""), # type: ignore } ) # Sort by security score (highest first) results.sort(key=lambda x: x.get("security_score", 0), reverse=True) # Add rankings for i, result in enumerate(results): result["rank"] = i + 1 score = result.get("security_score", 0) if score >= 90: result["rating"] = "🛡️ Excellent" elif score >= 70: result["rating"] = "✅ Secure" elif score >= 50: result["rating"] = "⚠️ Caution" else: result["rating"] = "🚨 High Risk" # Generate overall recommendation if results: best_lib = results[0] if best_lib.get("security_score", 0) >= 80: overall_rec = ( f"✅ Recommended: {best_lib['library']} has excellent security" ) elif best_lib.get("security_score", 0) >= 60: overall_rec = f"⚠️ Proceed with caution: {best_lib['library']} is the most secure option" else: overall_rec = "🚨 Security concerns: All libraries have significant vulnerabilities" else: overall_rec = "Unable to generate recommendation" return { "comparison_results": results, "total_libraries": len(libraries), "scan_timestamp": datetime.now().isoformat(), "overall_recommendation": overall_rec, "ecosystem": ecosystem, } except Exception as e: return { "error": f"Security comparison failed: {str(e)}", "libraries": libraries, "ecosystem": ecosystem, }
- Key helper function called by the handler. Fetches security summary for a single library using VulnerabilityScanner.scan_library, returns score, vuln counts, status, and recommendation.async def get_security_summary( self, library_name: str, ecosystem: str = "PyPI" ) -> Dict[str, Any]: """Get concise security summary""" try: report = await self.scanner.scan_library(library_name, ecosystem) return { "library": library_name, "security_score": report.security_score, "total_vulnerabilities": report.total_vulnerabilities, "critical_vulnerabilities": report.critical_count, "status": "secure" if report.security_score >= 70 else "at_risk", "primary_recommendation": ( report.recommendations[0] if report.recommendations else "No specific recommendations" ), } except Exception as e: return { "library": library_name, "security_score": 50.0, "error": str(e), "status": "unknown", }
- Core scanning logic in VulnerabilityScanner. Performs parallel scans on OSV, GitHub advisories, Safety DB; aggregates vulnerabilities; computes security score and report.async def scan_library( self, library_name: str, ecosystem: str = "PyPI" ) -> SecurityReport: """ Comprehensive vulnerability scan for a library Args: library_name: Name of the library (e.g., "fastapi", "react") ecosystem: Package ecosystem ("PyPI", "npm", "Maven", etc.) Returns: SecurityReport with vulnerability details """ cache_key = f"{library_name}_{ecosystem}" # Check cache first if self._is_cached(cache_key): return self.cache[cache_key]["data"] vulnerabilities = [] # Scan multiple sources in parallel scan_tasks = [ self._scan_osv(library_name, ecosystem), self._scan_github_advisories(library_name, ecosystem), ( self._scan_safety_db(library_name) if ecosystem.lower() == "pypi" else self._empty_scan() ), ] try: results = await asyncio.gather(*scan_tasks, return_exceptions=True) for result in results: if isinstance(result, list): vulnerabilities.extend(result) elif isinstance(result, Exception): print(f"Scan error: {result}", file=sys.stderr) except Exception as e: print(f"Vulnerability scan failed for {library_name}: {e}", file=sys.stderr) # Generate security report report = self._generate_security_report( library_name, ecosystem, vulnerabilities ) # Cache the result self._cache_result(cache_key, report) return report
- Data class defining the structure of security reports returned by scans, including scores, vuln counts, and details.class SecurityReport: """Comprehensive security report for a library""" library_name: str ecosystem: str # "pypi", "npm", "maven", etc. scan_date: str total_vulnerabilities: int critical_count: int high_count: int medium_count: int low_count: int security_score: float # 0-100, higher is better recommendations: List[str] vulnerabilities: List[Vulnerability] latest_secure_version: Optional[str] def to_dict(self) -> Dict[str, Any]: return { "library_name": self.library_name, "ecosystem": self.ecosystem, "scan_date": self.scan_date, "summary": { "total_vulnerabilities": self.total_vulnerabilities, "critical": self.critical_count, "high": self.high_count, "medium": self.medium_count, "low": self.low_count, "security_score": self.security_score, }, "latest_secure_version": self.latest_secure_version, "recommendations": self.recommendations, "vulnerabilities": [vuln.to_dict() for vuln in self.vulnerabilities], }