#!/usr/bin/env python3
"""
Red Team Auto Review - 보안 취약점 분석 및 리스크 평가 도구

Usage:
    python3 memory/red-team-auto-review.py scan <파일경로>     # 전체 보안 검사
    python3 memory/red-team-auto-review.py vuln <파일경로>     # 취약점만 검사
    python3 memory/red-team-auto-review.py deps <파일경로>     # 의존성 검사
    python3 memory/red-team-auto-review.py risk <파일경로>     # 리스크 평가
"""

import json
import os
import re
import subprocess
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional


class RedTeamReviewer:
    """보안 취약점 분석 및 리스크 평가 클래스"""

    # 취약점 패턴 정의
    VULNERABILITY_PATTERNS = {
        "SQL Injection": [
            r"execute\s*\(\s*[\"'].*%s.*[\"']\s*%\s*\(",  # string formatting in SQL
            r"cursor\.execute\s*\(\s*f[\"']",  # f-string in SQL
            r"\.raw\s*\(\s*[\"'].*\+.*[\"']",  # raw query with concatenation
            r"SELECT.*FROM.*WHERE.*\+",  # SQL concatenation
        ],
        "XSS (Cross-Site Scripting)": [
            r"innerHTML\s*=",  # Direct innerHTML assignment
            r"document\.write\s*\(",  # document.write
            r"\.html\s*\(\s*[^\"']",  # jQuery .html() with variable
            r"render_template_string\s*\(",  # Flask unsafe render
        ],
        "Hardcoded Secret": [
            r"password\s*=\s*[\"'][^\"']+[\"']",  # Hardcoded password
            r"api_key\s*=\s*[\"'][^\"']+[\"']",  # Hardcoded API key
            r"secret\s*=\s*[\"'][^\"']+[\"']",  # Hardcoded secret
            r"token\s*=\s*[\"'][^\"']+[\"']",  # Hardcoded token
            r"private_key\s*=\s*[\"']-----BEGIN",  # Hardcoded private key
        ],
        "Code Injection": [
            r"eval\s*\(",  # eval() usage
            r"exec\s*\(",  # exec() usage
            r"compile\s*\(",  # compile() usage
            r"__import__\s*\(",  # Dynamic import
        ],
        "Path Traversal": [
            r"\.\./",  # Parent directory reference
            r"\.\.\\",  # Windows parent directory
            r"os\.path\.join\s*\([^)]*\+",  # Path concatenation
        ],
        "Command Injection": [
            r"os\.system\s*\(",  # os.system
            r"subprocess\.call\s*\([^)]*shell\s*=\s*True",  # shell=True
            r"subprocess\.Popen\s*\([^)]*shell\s*=\s*True",  # shell=True
            r"eval\s*\(",  # eval for commands
        ],
        "Insecure Dependencies": [],  # Will be checked via npm audit/pip audit
    }

    # 위험도 레벨 정의
    RISK_LEVELS = {"low": 0, "medium": 1, "high": 2, "critical": 3}

    def __init__(self, file_path: str):
        """초기화"""
        self.file_path = Path(file_path)
        self.content = ""
        self.vulnerabilities = []
        self.dependency_issues = []
        self.risk_level = "low"

    def load_file(self) -> bool:
        """파일 로드"""
        try:
            if not self.file_path.exists():
                print(json.dumps({"error": f"File not found: {self.file_path}", "risk_level": "unknown"}))
                return False

            with open(self.file_path, "r", encoding="utf-8") as f:
                self.content = f.read()
            return True
        except Exception as e:
            print(json.dumps({"error": f"Failed to read file: {str(e)}", "risk_level": "unknown"}))
            return False

    def scan_vulnerabilities(self) -> Dict[str, Any]:
        """코드 취약점 스캔"""
        if not self.load_file():
            return {"vulnerabilities": [], "risk_level": "unknown"}

        found_vulnerabilities = []

        for vuln_type, patterns in self.VULNERABILITY_PATTERNS.items():
            if vuln_type == "Insecure Dependencies":
                continue  # 별도 메서드에서 처리

            for pattern in patterns:
                matches = re.finditer(pattern, self.content, re.IGNORECASE | re.MULTILINE)
                for match in matches:
                    # 실제 취약점인지 확인 (주석 내 제외)
                    line_num = self.content[: match.start()].count("\n") + 1
                    line = self.content.split("\n")[line_num - 1]

                    # 주석 라인이면 스킵
                    stripped = line.strip()
                    if stripped.startswith("#") or stripped.startswith("//"):
                        continue

                    found_vulnerabilities.append(
                        {
                            "type": vuln_type,
                            "line": line_num,
                            "snippet": line.strip()[:100],
                            "severity": self._get_severity(vuln_type),
                        }
                    )

        self.vulnerabilities = found_vulnerabilities
        return {"vulnerabilities": found_vulnerabilities, "count": len(found_vulnerabilities)}

    def _get_severity(self, vuln_type: str) -> str:
        """취약점 심각도 반환"""
        severity_map = {
            "SQL Injection": "high",
            "XSS (Cross-Site Scripting)": "medium",
            "Hardcoded Secret": "high",
            "Code Injection": "critical",
            "Path Traversal": "medium",
            "Command Injection": "critical",
            "Insecure Dependencies": "medium",
        }
        return severity_map.get(vuln_type, "low")

    def check_dependencies(self) -> Dict[str, Any]:
        """의존성 취약점 검사"""
        results = {"vulnerable_deps": 0, "dependencies": [], "tool_used": None}

        file_ext = self.file_path.suffix.lower()

        # Python requirements.txt
        if "requirements" in self.file_path.name.lower() or file_ext == ".txt":
            results["tool_used"] = "pip-audit (simulated)"
            # 실제 pip-audit이 있으면 실행, 없으면 시뮬레이션
            if self._check_tool_available("pip-audit"):
                try:
                    output = subprocess.run(
                        ["pip-audit", "-r", str(self.file_path), "--format", "json"],
                        capture_output=True,
                        text=True,
                        timeout=30,
                    )
                    if output.returncode != 0 and output.stdout:
                        audit_results = json.loads(output.stdout)
                        results["vulnerable_deps"] = len(audit_results.get("vulnerabilities", []))
                        results["dependencies"] = audit_results.get("vulnerabilities", [])
                except Exception:
                    pass
            else:
                # 시뮬레이션: requirements.txt 파싱
                if self.load_file():
                    deps = [
                        line.strip() for line in self.content.split("\n") if line.strip() and not line.startswith("#")
                    ]
                    results["dependencies"] = [{"name": dep, "status": "unknown"} for dep in deps[:5]]

        # package.json or npm
        elif file_ext == ".json" and "package" in self.file_path.name.lower():
            results["tool_used"] = "npm audit (simulated)"
            if self._check_tool_available("npm"):
                try:
                    output = subprocess.run(
                        ["npm", "audit", "--json"],
                        capture_output=True,
                        text=True,
                        timeout=30,
                        cwd=str(self.file_path.parent),
                    )
                    if output.stdout:
                        audit_results = json.loads(output.stdout)
                        results["vulnerable_deps"] = (
                            audit_results.get("metadata", {}).get("vulnerabilities", {}).get("total", 0)
                        )
                except Exception:
                    pass

        self.dependency_issues = results
        return results

    def _check_tool_available(self, tool: str) -> bool:
        """외부 도구 사용 가능 여부 확인"""
        try:
            subprocess.run(["which", tool], capture_output=True, timeout=5)
            return True
        except Exception:
            return False

    def assess_risk(self) -> Dict[str, Any]:
        """전체 리스크 평가"""
        # 취약점 기반 리스크 계산
        max_severity = "low"
        severity_scores = {"low": 0, "medium": 1, "high": 2, "critical": 3}

        for vuln in self.vulnerabilities:
            vuln_severity = vuln.get("severity", "low")
            if severity_scores.get(vuln_severity, 0) > severity_scores.get(max_severity, 0):
                max_severity = vuln_severity

        # 의존성 이슈 추가 고려
        if self.dependency_issues.get("vulnerable_deps", 0) > 0:
            if max_severity == "low":
                max_severity = "medium"

        # 취약점 개수 기반 조정
        vuln_count = len(self.vulnerabilities)
        if vuln_count > 5 and max_severity == "medium":
            max_severity = "high"
        elif vuln_count > 10 and max_severity == "high":
            max_severity = "critical"

        self.risk_level = max_severity

        return {
            "risk_level": max_severity,
            "vulnerability_count": vuln_count,
            "dependency_issues": self.dependency_issues.get("vulnerable_deps", 0),
            "recommendation": self._get_recommendation(max_severity),
        }

    def _get_recommendation(self, risk_level: str) -> str:
        """리스크 레벨별 권장사항"""
        recommendations = {
            "low": "낮은 위험 - 현재 수준 유지",
            "medium": "중간 위험 - 수정 권장",
            "high": "높은 위험 - 즉시 수정 필요",
            "critical": "심각한 위험 - 즉시 중단 및 수정 필요",
        }
        return recommendations.get(risk_level, "알 수 없음")

    def scan_security(self) -> Dict[str, Any]:
        """전체 보안 검사"""
        # 1. 취약점 스캔
        vuln_result = self.scan_vulnerabilities()

        # 2. 의존성 검사
        deps_result = self.check_dependencies()

        # 3. 리스크 평가
        risk_result = self.assess_risk()

        return {
            "file": str(self.file_path),
            "risk_level": risk_result["risk_level"],
            "vulnerabilities": vuln_result["vulnerabilities"],
            "vulnerability_count": vuln_result["count"],
            "dependency_issues": deps_result["vulnerable_deps"],
            "recommendation": risk_result["recommendation"],
            "passed": risk_result["risk_level"] in ["low", "medium"],
        }


def main():
    """메인 함수"""
    if len(sys.argv) < 3:
        print(
            json.dumps(
                {
                    "error": "Usage: python3 red-team-auto-review.py <command> <file>",
                    "commands": ["scan", "vuln", "deps", "risk"],
                }
            )
        )
        sys.exit(1)

    command = sys.argv[1]
    file_path = sys.argv[2]

    reviewer = RedTeamReviewer(file_path)

    if command == "scan":
        result = reviewer.scan_security()
    elif command == "vuln":
        result = reviewer.scan_vulnerabilities()
        result["risk_level"] = reviewer.assess_risk()["risk_level"]
    elif command == "deps":
        result = reviewer.check_dependencies()
        result["risk_level"] = "low" if result["vulnerable_deps"] == 0 else "medium"
    elif command == "risk":
        reviewer.scan_vulnerabilities()
        reviewer.check_dependencies()
        result = reviewer.assess_risk()
    else:
        print(json.dumps({"error": f"Unknown command: {command}", "commands": ["scan", "vuln", "deps", "risk"]}))
        sys.exit(1)

    print(json.dumps(result, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    main()
