File size: 4,148 Bytes
a42b16d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""Security scanning for dependencies and secrets."""

from __future__ import annotations

import re
from pathlib import Path
from typing import Any, Dict, List

from codebase_analyzer import CodebaseAnalyzer


class SecurityScanner:
    """Scans codebase for security issues."""

    def __init__(self):
        self.analyzer = CodebaseAnalyzer()

    def scan_dependencies(self, folder_path: str) -> Dict[str, Any]:
        """Scan dependencies for known vulnerabilities."""
        analysis = self.analyzer.analyze_folder(folder_path)
        dependencies = analysis.get("dependencies", [])
        
        # Known vulnerable packages (simplified - would use real vulnerability DB)
        vulnerable_packages = {
            "lodash": "< 4.17.21",
            "axios": "< 0.21.1",
            "express": "< 4.17.1",
        }
        
        issues = []
        for dep in dependencies[:20]:  # Check first 20
            dep_name = dep.lower() if isinstance(dep, str) else dep.get("name", "").lower()
            if dep_name in vulnerable_packages:
                issues.append({
                    "package": dep_name,
                    "severity": "high",
                    "issue": f"Known vulnerability, update to {vulnerable_packages[dep_name]}",
                    "type": "dependency_vulnerability"
                })
        
        return {
            "total_dependencies": len(dependencies),
            "scanned": min(20, len(dependencies)),
            "vulnerabilities_found": len(issues),
            "issues": issues,
            "status": "safe" if not issues else "vulnerabilities_detected"
        }

    def scan_secrets(self, folder_path: str) -> Dict[str, Any]:
        """Scan for exposed secrets and API keys."""
        path = Path(folder_path)
        secrets_found = []
        
        # Patterns for common secrets
        secret_patterns = {
            "api_key": r'(?i)(api[_-]?key|apikey)\s*[:=]\s*["\']?([a-zA-Z0-9_\-]{20,})["\']?',
            "secret": r'(?i)(secret|password|pwd)\s*[:=]\s*["\']?([a-zA-Z0-9_\-]{10,})["\']?',
            "token": r'(?i)(token|bearer)\s*[:=]\s*["\']?([a-zA-Z0-9_\-]{20,})["\']?',
            "aws_key": r'AKIA[0-9A-Z]{16}',
            "private_key": r'-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----',
        }
        
        # Scan common config files
        config_files = ["*.env", "*.env.*", "*.config.js", "*.config.ts", "*.json"]
        
        for pattern in config_files:
            for file_path in path.rglob(pattern):
                if file_path.is_file() and ".git" not in str(file_path):
                    try:
                        content = file_path.read_text()
                        for secret_type, regex in secret_patterns.items():
                            matches = re.findall(regex, content)
                            if matches:
                                secrets_found.append({
                                    "file": str(file_path.relative_to(path)),
                                    "type": secret_type,
                                    "severity": "critical",
                                    "issue": f"Potential {secret_type} exposed in {file_path.name}"
                                })
                    except Exception:
                        pass
        
        return {
            "secrets_found": len(secrets_found),
            "issues": secrets_found[:10],  # Limit to 10
            "status": "safe" if not secrets_found else "secrets_detected",
            "recommendation": "Use environment variables and secrets management"
        }

    def scan_codebase(self, folder_path: str) -> Dict[str, Any]:
        """Complete security scan."""
        deps_scan = self.scan_dependencies(folder_path)
        secrets_scan = self.scan_secrets(folder_path)
        
        return {
            "dependencies": deps_scan,
            "secrets": secrets_scan,
            "overall_status": "safe" if deps_scan["status"] == "safe" and secrets_scan["status"] == "safe" else "issues_found",
            "total_issues": deps_scan["vulnerabilities_found"] + secrets_scan["secrets_found"]
        }