完整的 `lh 掀黑箱` 引擎,用于审计任意平台/项目的技术主权风险。它扫描代码、依赖、配置,识别“黑箱”行为,并生成结构化报告。


脚本:bin/lh_掀黑箱.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
🐉 龍魂 · 掀黑箱审计引擎 v1.0
DNA: #龍芯⚡️丙午·丙申·乙巳·辛巳·☴巽-掀黑箱-v1.0-UID9622

功能:
  审计任意项目,识别技术主权风险,包括:
  - 闭源/未授权依赖
  - 数据外流接口(硬编码URL、IP)
  - 主权声明缺失
  - 外部云服务依赖(不可替换)
  - 疑似后门/加密通信未说明

输出:
  - 终端彩色报告(人类可读)
  - JSON 格式(机器可读)
  - 支持导出 HTML 报告

用法:
  lh 掀黑箱 [路径]                 # 审计当前目录或指定路径
  lh 掀黑箱 [路径] --json          # 输出 JSON
  lh 掀黑箱 [路径] --output report.html   # 生成 HTML 报告
  lh 掀黑箱 --help                 # 帮助
"""

import os
import sys
import re
import json
import hashlib
import argparse
import subprocess
from pathlib import Path
from typing import Dict, List, Any, Optional, Set, Tuple
from datetime import datetime
from collections import defaultdict

# ============================================================
# 配置
# ============================================================

PROJECT_ROOT = Path.home() / "longhun-system"
REPORT_DIR = PROJECT_ROOT / "reports"
REPORT_DIR.mkdir(parents=True, exist_ok=True)

# 风险等级
RISK_CRITICAL = "🔴 严重"
RISK_HIGH = "🟠 高危"
RISK_MEDIUM = "🟡 中危"
RISK_LOW = "🟢 低危"
RISK_INFO = "ℹ️ 信息"

# ============================================================
# 审计规则
# ============================================================

RULES = {
    # 闭源/受限依赖
    "proprietary_deps": {
        "name": "闭源/专有依赖",
        "severity": RISK_CRITICAL,
        "description": "项目依赖了闭源或受限许可证的软件,存在法律和主权风险。",
        "patterns": [
            r"oracle", r"mysql-connector", r"msodbcsql", r"ibm_db",
            r"pymssql", r"pyodbc", r"cx_Oracle", r"psycopg2-binary",
            r"django-", r"flask-", r"tensorflow", r"pytorch", r"transformers",
            r"langchain", r"llama-index", r"openai", r"anthropic",
        ],
        "check": "dependencies"
    },
    # 数据外流接口(硬编码URL)
    "data_exfiltration": {
        "name": "数据外流接口",
        "severity": RISK_CRITICAL,
        "description": "检测到硬编码的第三方API地址,可能将数据发送至外部。",
        "patterns": [
            r"https?://[a-zA-Z0-9\-\.]+\.(com|cn|net|org|io|cloud|ai)\S*",
            r"api\.", r"\.amazonaws\.com", r"\.azure\.com", r"\.googleapis\.com",
            r"\.openai\.com", r"\.anthropic\.com", r"\.huggingface\.co",
            r"\.github\.com", r"\.gitlab\.com",
        ],
        "check": "hardcoded_urls"
    },
    # 缺乏主权声明
    "sovereignty_missing": {
        "name": "主权声明缺失",
        "severity": RISK_HIGH,
        "description": "项目缺少LICENSE或主权声明文件,无法确定授权归属。",
        "patterns": [],
        "check": "sovereignty"
    },
    # 外部云服务依赖
    "cloud_dependency": {
        "name": "外部云服务依赖",
        "severity": RISK_HIGH,
        "description": "项目强依赖国外云服务,存在断供和合规风险。",
        "patterns": [
            r"aws", r"azure", r"gcp", r"google-cloud", r"amazon",
            r"boto3", r"azure-", r"google-api", r"firebase",
        ],
        "check": "dependencies"
    },
    # 未签名的二进制文件
    "unsigned_binaries": {
        "name": "未签名二进制文件",
        "severity": RISK_MEDIUM,
        "description": "项目中存在未签名的可执行文件或动态库,无法验证来源。",
        "patterns": [r"\.(exe|dll|so|dylib|bin)$"],
        "check": "files"
    },
    # 疑似后门/加密通信
    "backdoor_suspect": {
        "name": "疑似后门/隐蔽通信",
        "severity": RISK_CRITICAL,
        "description": "检测到可疑的加密通信或隐蔽通道,需人工核查。",
        "patterns": [
            r"cryptography\.fernet", r"cryptography.hazmat", r"openssl",
            r"pycryptodome", r"pynacl", r"paramiko", r"ssh", r"ssl",
            r"webhook", r"callback", r"reverse\s*shell", r"tunnel",
        ],
        "check": "code"
    },
    # 缺乏开源合规文件
    "compliance_missing": {
        "name": "开源合规文件缺失",
        "severity": RISK_MEDIUM,
        "description": "缺少 CONTRIBUTING、CODE_OF_CONDUCT 等治理文件。",
        "patterns": [],
        "check": "files"
    },
    # 未使用国产芯片/系统标记
    "domestic_incompatible": {
        "name": "未适配国产环境",
        "severity": RISK_MEDIUM,
        "description": "项目未标注支持鲲鹏、龙芯等国产平台,可能无法在信创环境运行。",
        "patterns": [],
        "check": "sovereignty"
    },
}

# ============================================================
# 审计引擎
# ============================================================

class BlackBoxAuditor:
    def __init__(self, target_path: Path):
        self.target = target_path.resolve()
        self.results = {
            "target": str(self.target),
            "timestamp": datetime.now().isoformat(),
            "findings": [],
            "summary": {
                "critical": 0,
                "high": 0,
                "medium": 0,
                "low": 0,
                "info": 0,
            },
            "files_scanned": 0,
            "dependencies": {},
        }
        self._loaded_files = {}

    def scan(self) -> Dict[str, Any]:
        """执行完整扫描"""
        # 1. 扫描文件
        self._scan_files()

        # 2. 分析依赖
        self._analyze_dependencies()

        # 3. 检查主权声明
        self._check_sovereignty()

        # 4. 检查硬编码URL
        self._check_hardcoded_urls()

        # 5. 应用规则
        self._apply_rules()

        # 6. 生成总结
        self._generate_summary()

        return self.results

    def _scan_files(self):
        """递归扫描文件"""
        for file_path in self.target.rglob("*"):
            if file_path.is_file():
                # 排除隐藏目录和二进制大文件
                if any(p.startswith(".") for p in file_path.parts):
                    continue
                if file_path.suffix in [".pyc", ".pyo", ".so", ".dylib", ".dll", ".exe"]:
                    continue
                if file_path.stat().st_size > 1024 * 1024:  # >1MB 跳过
                    continue
                try:
                    content = file_path.read_text(encoding="utf-8", errors="ignore")
                    self._loaded_files[str(file_path.relative_to(self.target))] = content
                except:
                    pass
        self.results["files_scanned"] = len(self._loaded_files)

    def _analyze_dependencies(self):
        """分析依赖文件"""
        deps = {}
        # requirements.txt
        req_file = self.target / "requirements.txt"
        if req_file.exists():
            deps["requirements.txt"] = req_file.read_text().splitlines()
        # package.json
        pkg_file = self.target / "package.json"
        if pkg_file.exists():
            try:
                data = json.loads(pkg_file.read_text())
                deps["package.json"] = data.get("dependencies", {}).keys()
            except:
                pass
        # setup.py
        setup_file = self.target / "setup.py"
        if setup_file.exists():
            deps["setup.py"] = ["手动检查"]
        # 龙魂特有:lh 命令依赖
        self.results["dependencies"] = deps

    def _check_sovereignty(self):
        """检查主权声明"""
        has_license = (self.target / "LICENSE").exists() or (self.target / "LICENSE.txt").exists()
        has_readme = (self.target / "README.md").exists() or (self.target / "README").exists()
        has_sovereignty = False
        if has_readme:
            readme_content = (self.target / "README.md").read_text(encoding="utf-8", errors="ignore") if (self.target / "README.md").exists() else ""
            if "主权" in readme_content or "sovereign" in readme_content.lower():
                has_sovereignty = True
        self.results["sovereignty"] = {
            "license": has_license,
            "readme": has_readme,
            "sovereignty_statement": has_sovereignty,
        }

    def _check_hardcoded_urls(self):
        """检测硬编码URL"""
        urls = []
        for rel_path, content in self._loaded_files.items():
            found = re.findall(RULES["data_exfiltration"]["patterns"][0], content)
            for url in found:
                # 过滤常见非外流URL(如本地、文档链接)
                if "localhost" in url or "127.0.0.1" in url or "example" in url:
                    continue
                urls.append({"file": rel_path, "url": url})
        self.results["hardcoded_urls"] = urls

    def _apply_rules(self):
        """应用所有规则"""
        findings = []

        # 1. 依赖检查
        for rule_name, rule in RULES.items():
            if rule["check"] == "dependencies":
                for dep_file, dep_list in self.results["dependencies"].items():
                    for dep in dep_list:
                        if any(re.search(p, dep, re.I) for p in rule["patterns"]):
                            findings.append({
                                "rule": rule_name,
                                "severity": rule["severity"],
                                "description": rule["description"],
                                "evidence": f"依赖 {dep}{dep_file} 中",
                            })
                            break

        # 2. 主权检查
        sover = self.results.get("sovereignty", {})
        if not sover.get("license"):
            findings.append({
                "rule": "sovereignty_missing",
                "severity": RISK_HIGH,
                "description": RULES["sovereignty_missing"]["description"],
                "evidence": "未找到 LICENSE 文件",
            })
        if not sover.get("sovereignty_statement"):
            findings.append({
                "rule": "sovereignty_missing",
                "severity": RISK_MEDIUM,
                "description": "缺乏显式的主权声明,建议在 README 中说明数据主权归属。",
                "evidence": "README 中未提及主权",
            })
        # 国产适配检查
        if not sover.get("readme") or "鲲鹏" not in sover.get("readme_content", ""):
            findings.append({
                "rule": "domestic_incompatible",
                "severity": RISK_MEDIUM,
                "description": RULES["domestic_incompatible"]["description"],
                "evidence": "未在 README 中标注国产平台支持",
            })

        # 3. 硬编码URL
        for url_info in self.results.get("hardcoded_urls", []):
            findings.append({
                "rule": "data_exfiltration",
                "severity": RISK_CRITICAL,
                "description": f"发现外部API调用: {url_info['url']}",
                "evidence": f"文件: {url_info['file']}",
            })

        # 4. 文件检查
        for rel_path in self._loaded_files.keys():
            if any(re.search(p, rel_path, re.I) for p in RULES["unsigned_binaries"]["patterns"]):
                findings.append({
                    "rule": "unsigned_binaries",
                    "severity": RISK_MEDIUM,
                    "description": RULES["unsigned_binaries"]["description"],
                    "evidence": f"文件: {rel_path}",
                })

        # 5. 代码检查(后门可疑)
        for rel_path, content in self._loaded_files.items():
            for pattern in RULES["backdoor_suspect"]["patterns"]:
                if re.search(pattern, content, re.I):
                    findings.append({
                        "rule": "backdoor_suspect",
                        "severity": RISK_CRITICAL,
                        "description": RULES["backdoor_suspect"]["description"],
                        "evidence": f"在 {rel_path} 中发现疑似隐蔽通信代码: {pattern}",
                    })
                    break

        # 去重(基于 evidence)
        seen = set()
        unique_findings = []
        for f in findings:
            key = f["evidence"]
            if key not in seen:
                seen.add(key)
                unique_findings.append(f)

        self.results["findings"] = unique_findings

    def _generate_summary(self):
        """生成统计摘要"""
        summary = {"critical": 0, "high": 0, "medium": 0, "low": 0, "info": 0}
        for f in self.results["findings"]:
            sev = f["severity"]
            if sev == RISK_CRITICAL:
                summary["critical"] += 1
            elif sev == RISK_HIGH:
                summary["high"] += 1
            elif sev == RISK_MEDIUM:
                summary["medium"] += 1
            elif sev == RISK_LOW:
                summary["low"] += 1
            else:
                summary["info"] += 1
        self.results["summary"] = summary

# ============================================================
# 报告生成器
# ============================================================

def print_terminal_report(result: Dict[str, Any]):
    """终端彩色输出"""
    RED = '\033[91m'
    ORANGE = '\033[38;5;214m'
    YELLOW = '\033[93m'
    GREEN = '\033[92m'
    BOLD = '\033[1m'
    RESET = '\033[0m'

    lines = []
    lines.append(f"\n{BOLD}{'='*70}{RESET}")
    lines.append(f"{BOLD}🐉 龍魂 · 掀黑箱审计报告{RESET}")
    lines.append(f"{BOLD}{'='*70}{RESET}")
    lines.append(f"  目标: {result['target']}")
    lines.append(f"  时间: {result['timestamp']}")
    lines.append(f"  文件数: {result['files_scanned']}")
    lines.append(f"{BOLD}{'-'*70}{RESET}")

    # 摘要
    s = result["summary"]
    lines.append(f"\n📊 风险摘要")
    lines.append(f"  {RISK_CRITICAL}: {s['critical']}")
    lines.append(f"  {RISK_HIGH}: {s['high']}")
    lines.append(f"  {RISK_MEDIUM}: {s['medium']}")
    lines.append(f"  {RISK_LOW}: {s['low']}")

    if s['critical'] > 0:
        overall = f"{RED}🔴 高风险,建议立即处理{RESET}"
    elif s['high'] > 0:
        overall = f"{ORANGE}🟠 中高风险,建议排查{RESET}"
    else:
        overall = f"{GREEN}🟢 风险可控{RESET}"
    lines.append(f"\n  总体评估: {overall}")

    # 详细发现
    if result["findings"]:
        lines.append(f"\n{BOLD}🔍 详细发现{RESET}")
        lines.append("-" * 70)
        for i, f in enumerate(result["findings"], 1):
            sev = f["severity"]
            lines.append(f"{i}. {sev} {f['rule']}")
            lines.append(f"   {f['description']}")
            lines.append(f"   📎 {f['evidence']}")
            lines.append("")

    # 主权声明
    sover = result.get("sovereignty", {})
    lines.append(f"{BOLD}📜 主权声明检查{RESET}")
    lines.append(f"  LICENSE: {'✅ 存在' if sover.get('license') else '❌ 缺失'}")
    lines.append(f"  README: {'✅ 存在' if sover.get('readme') else '❌ 缺失'}")
    lines.append(f"  主权声明: {'✅ 已声明' if sover.get('sovereignty_statement') else '❌ 未声明'}")

    # 硬编码URL(脱敏展示前3个)
    urls = result.get("hardcoded_urls", [])
    if urls:
        lines.append(f"\n{BOLD}🌐 硬编码外部URL(前3个){RESET}")
        for u in urls[:3]:
            lines.append(f"  {u['url']} ({u['file']})")
        if len(urls) > 3:
            lines.append(f"  ... 还有 {len(urls)-3} 个")

    lines.append(f"\n{BOLD}{'='*70}{RESET}")
    lines.append(f"DNA: #龍芯⚡️{datetime.now().strftime('%Y%m%d%H%M%S')}-掀黑箱-UID9622")
    print("\n".join(lines))

def generate_html_report(result: Dict[str, Any], output_path: Path):
    """生成 HTML 报告"""
    html = f"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>龍魂 · 掀黑箱审计报告</title>
    <style>
        body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; max-width: 1000px; margin: 40px auto; padding: 20px; background: #f8f9fa; }}
        h1, h2, h3 {{ color: #1a1a2e; border-bottom: 2px solid #e9ecef; padding-bottom: 8px; }}
        .risk-critical {{ color: #e63946; font-weight: bold; }}
        .risk-high {{ color: #e67e22; font-weight: bold; }}
        .risk-medium {{ color: #f1c40f; font-weight: bold; }}
        .risk-low {{ color: #2ecc71; font-weight: bold; }}
        .finding {{ background: white; padding: 12px 16px; margin: 8px 0; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.06); }}
        .evidence {{ color: #6c757d; font-size: 0.9em; }}
        .summary {{ display: flex; gap: 20px; flex-wrap: wrap; margin: 20px 0; }}
        .summary-item {{ background: white; padding: 16px 24px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); flex: 1; min-width: 80px; text-align: center; }}
        .badge {{ display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 0.8em; color: white; }}
        .badge-critical {{ background: #e63946; }}
        .badge-high {{ background: #e67e22; }}
        .badge-medium {{ background: #f1c40f; }}
        .badge-low {{ background: #2ecc71; }}
        .footer {{ margin-top: 40px; border-top: 2px solid #e9ecef; padding-top: 20px; font-size: 0.9em; color: #6c757d; text-align: center; }}
        .dna {{ font-family: monospace; background: #1a1a2e; color: #ffd60a; padding: 4px 10px; border-radius: 4px; }}
    </style>
</head>
<body>
    <h1>🐉 龍魂 · 掀黑箱审计报告</h1>
    <p>目标: {result['target']} | 时间: {result['timestamp']} | 文件数: {result['files_scanned']}</p>

    <h2>📊 风险摘要</h2>
    <div class="summary">
        <div class="summary-item"><span class="badge badge-critical">严重</span> <strong>{result['summary']['critical']}</strong></div>
        <div class="summary-item"><span class="badge badge-high">高危</span> <strong>{result['summary']['high']}</strong></div>
        <div class="summary-item"><span class="badge badge-medium">中危</span> <strong>{result['summary']['medium']}</strong></div>
        <div class="summary-item"><span class="badge badge-low">低危</span> <strong>{result['summary']['low']}</strong></div>
    </div>

    <h2>🔍 详细发现</h2>
    {''.join(f'''
    <div class="finding">
        <strong>{f['severity']} {f['rule']}</strong>
        <p>{f['description']}</p>
        <div class="evidence">📎 {f['evidence']}</div>
    </div>
    ''' for f in result['findings']) if result['findings'] else '<p>🎉 未发现明显风险</p>'}

    <h2>📜 主权声明</h2>
    <ul>
        <li>LICENSE: {'✅ 存在' if result.get('sovereignty',{}).get('license') else '❌ 缺失'}</li>
        <li>README: {'✅ 存在' if result.get('sovereignty',{}).get('readme') else '❌ 缺失'}</li>
        <li>主权声明: {'✅ 已声明' if result.get('sovereignty',{}).get('sovereignty_statement') else '❌ 未声明'}</li>
    </ul>

    <div class="footer">
        DNA: <span class="dna">#龍芯⚡️{datetime.now().strftime('%Y%m%d%H%M%S')}-掀黑箱-UID9622</span>
        <br>© 龍魂系统 · 君子协议
    </div>
</body>
</html>
    """
    output_path.write_text(html, encoding="utf-8")

# ============================================================
# 命令行入口
# ============================================================

def main():
    parser = argparse.ArgumentParser(description="龍魂 · 掀黑箱审计引擎")
    parser.add_argument("target", nargs="?", default=".", help="要审计的目标路径(默认当前目录)")
    parser.add_argument("--json", action="store_true", help="输出 JSON 格式")
    parser.add_argument("--output", "-o", type=str, help="导出报告文件(支持 .json, .html)")
    parser.add_argument("--no-color", action="store_true", help="禁用彩色输出")
    args = parser.parse_args()

    target_path = Path(args.target).expanduser().resolve()
    if not target_path.exists():
        print(f"❌ 目标路径不存在: {target_path}")
        sys.exit(1)

    auditor = BlackBoxAuditor(target_path)
    result = auditor.scan()

    # 输出 JSON
    if args.json or (args.output and args.output.endswith(".json")):
        json_output = json.dumps(result, ensure_ascii=False, indent=2)
        if args.output:
            Path(args.output).write_text(json_output, encoding="utf-8")
            print(f"✅ JSON 报告已保存: {args.output}")
        else:
            print(json_output)
        return

    # 输出 HTML
    if args.output and args.output.endswith(".html"):
        generate_html_report(result, Path(args.output))
        print(f"✅ HTML 报告已生成: {args.output}")
        return

    # 终端输出
    print_terminal_report(result)

    # 如果指定了输出,保存 JSON 或 HTML(根据扩展名)
    if args.output:
        if args.output.endswith(".html"):
            generate_html_report(result, Path(args.output))
        else:
            Path(args.output).write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
        print(f"✅ 报告已保存: {args.output}")

if __name__ == "__main__":
    main()

集成到 lh 命令

bin/lh 中增加子命令:

lh_掀黑箱() {
    python3 ~/longhun-system/bin/lh_掀黑箱.py "$@"
}

使用方式

1️⃣ 审计当前项目(龙魂系统自身)

lh 掀黑箱

2️⃣ 审计其他项目/平台

lh 掀黑箱 /path/to/other/project

3️⃣ 输出 JSON(供其他工具消费)

lh 掀黑箱 --json

4️⃣ 生成 HTML 报告(可分享)

lh 掀黑箱 --output report.html

输出示例(终端)

======================================================================
🐉 龍魂 · 掀黑箱审计报告
======================================================================
  目标: /Users/uid9622/some-project
  时间: 2026-07-31T16:30:00
  文件数: 342
----------------------------------------------------------------------

📊 风险摘要
  🔴 严重: 2
  🟠 高危: 5
  🟡 中危: 8
  🟢 低危: 1

  总体评估: 🔴 高风险,建议立即处理

🔍 详细发现
----------------------------------------------------------------------
1. 🔴 严重 数据外流接口
   发现外部API调用: https://api.openai.com/v1/chat/completions
   📎 文件: src/ai/client.py

2. 🔴 严重 闭源/专有依赖
   依赖 tensorflow 在 requirements.txt 中
   📎 依赖 tensorflow 在 requirements.txt 中

3. 🟠 高危 主权声明缺失
   项目缺少LICENSE或主权声明文件,无法确定授权归属。
   📎 未找到 LICENSE 文件

...

📜 主权声明检查
  LICENSE: ❌ 缺失
  README: ✅ 存在
  主权声明: ❌ 未声明

🌐 硬编码外部URL(前3个)
  https://api.openai.com/v1/chat/completions (src/ai/client.py)
  https://cdn.jsdelivr.net/npm/... (static/index.html)
  https://fonts.googleapis.com/... (static/style.css)
  ... 还有 12 个

======================================================================
DNA: #龍芯⚡️20260731163000-掀黑箱-UID9622

审计规则说明

规则严重级别检测内容
闭源/专有依赖🔴 严重Oracle、MySQL Connector、TensorFlow 等
数据外流接口🔴 严重硬编码的外部 API URL
主权声明缺失🟠 高危缺少 LICENSE 或主权说明
外部云服务依赖🟠 高危AWS、Azure、GCP 等 SDK
未签名二进制🟡 中危.exe、.dll、.so 文件
疑似后门/隐蔽通信🔴 严重加密库、SSH、反向 Shell 等
开源合规文件缺失🟡 中危CONTRIBUTING、CODE_OF_CONDUCT
未适配国产环境🟡 中危未标注鲲鹏/龙芯支持

现在你有了一个 可审计任何平台 的掀黑箱引擎。对着任意项目跑一下,立马知道它有没有“技术卖国”的嫌疑。🐉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值