#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：create_security_cases.py
模块描述：创建安全测试模块和用例

作者：czj
创建日期：2026-07-21
最后修改：2026-07-21
"""

import sys
import os
from datetime import datetime

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

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from app.database import Base
from app.models import Module, TestCase
from app.utils.id_generator import generate_id


# ==================== 安全测试模块定义 ====================

SECURITY_MODULES = [
    {
        "id": "sec_api01",
        "name": "API1 - 对象级别授权失效",
        "description": "测试用户是否能够访问或操作其他用户的数据资源（水平越权、IDOR）",
        "icon": "Lock",
        "order": 1,
    },
    {
        "id": "sec_api02",
        "name": "API2 - 身份认证失效",
        "description": "测试系统身份认证机制是否存在绕过、暴力破解等安全风险",
        "icon": "Key",
        "order": 2,
    },
    {
        "id": "sec_api03",
        "name": "API3 - 对象属性级别授权失效",
        "description": "测试用户是否能够访问或修改不应被授权的对象属性（垂直越权、成批分配）",
        "icon": "UserFilled",
        "order": 3,
    },
    {
        "id": "sec_api04",
        "name": "API4 - 资源消耗不受限",
        "description": "测试系统是否存在速率限制、文件上传、分页滥用等资源消耗漏洞",
        "icon": "Timer",
        "order": 4,
    },
    {
        "id": "sec_api05",
        "name": "API5 - 功能级别授权失效",
        "description": "测试普通用户是否能够访问管理员功能接口",
        "icon": "Operation",
        "order": 5,
    },
    {
        "id": "sec_api06",
        "name": "API6 - 无限制访问敏感业务流",
        "description": "测试业务流程是否存在批量注册、短信轰炸、接口滥用等风险",
        "icon": "Connection",
        "order": 6,
    },
    {
        "id": "sec_api07",
        "name": "API7 - 服务器端请求伪造",
        "description": "测试系统是否存在SSRF漏洞，可探测内网服务",
        "icon": "Monitor",
        "order": 7,
    },
    {
        "id": "sec_api08",
        "name": "API8 - 安全配置错误",
        "description": "检测系统是否存在CORS配置错误、敏感路径暴露、调试接口开启等配置问题",
        "icon": "Setting",
        "order": 8,
    },
    {
        "id": "sec_api09",
        "name": "API9 - 库存管理不当",
        "description": "测试是否存在隐藏接口、旧版API、内部API暴露等资产管理问题",
        "icon": "Files",
        "order": 9,
    },
    {
        "id": "sec_api10",
        "name": "API10 - 不安全的第三方API集成",
        "description": "测试第三方API集成是否存在凭证泄露、权限过度等安全问题",
        "icon": "Link",
        "order": 10,
    },
    {
        "id": "sec_regression",
        "name": "历史漏洞回归测试",
        "description": "基于历史漏洞报告的回归验证测试用例",
        "icon": "RefreshRight",
        "order": 11,
    },
    {
        "id": "sec_redline",
        "name": "华为安全红线检查",
        "description": "基于华为安全红线规范的合规性检查",
        "icon": "Warning",
        "order": 12,
    },
]


# ==================== 安全测试用例定义 ====================

SECURITY_CASES = [
    # ==================== API1: 对象级别授权失效 ====================
    {
        "id": "sec_2_1_1",
        "module_id": "sec_api01",
        "name": "水平越权访问其他用户会议详情",
        "description": "用普通用户Token访问超级管理员的会议详情，验证是否存在越权漏洞",
        "priority": "high",
        "tags": ["OWASP-API1", "水平越权", "IDOR"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMessageById", "method": "GET"},
            "auth": {"required": True, "account": "user", "expect_different_account": "superadmin"},
            "request": {"params": {"id": "${meeting_id}"}},
            "pre_steps": [
                {
                    "action": "get_resource_id",
                    "account": "superadmin",
                    "path": "/api/message/getMeetingList",
                    "params": {"pageNo": 1, "pageSize": 5},
                    "extract": {"meeting_id": "data.records[0].id"}
                }
            ],
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "越权访问应被拒绝"},
                {"type": "response_code_contain", "expect": ["401", "403", "B0027"], "description": "应返回权限不足"}
            ],
            "vulnerability": {
                "id": "2.1.1",
                "name": "水平越权访问其他用户会议详情",
                "level": "high",
                "description": "user使用Token成功访问了superadmin的会议详情，存在水平越权漏洞",
                "fix_suggestion": "在接口中增加用户身份校验，确保用户只能访问自己创建的会议数据"
            }
        }
    },
    {
        "id": "sec_2_1_2a",
        "module_id": "sec_api01",
        "name": "水平越权修改其他用户会议",
        "description": "用普通用户Token尝试修改超级管理员的会议",
        "priority": "high",
        "tags": ["OWASP-API1", "水平越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/update", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"id": "${meeting_id}", "title": "安全测试-越权修改尝试"}},
            "pre_steps": [
                {"action": "get_resource_id", "account": "superadmin", "path": "/api/message/getMeetingList", "params": {"pageNo": 1, "pageSize": 5}, "extract": {"meeting_id": "data.records[0].id"}}
            ],
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "越权修改应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.1.2",
                "name": "水平越权修改其他用户会议",
                "level": "high",
                "description": "user可修改superadmin的会议，存在严重水平越权漏洞",
                "fix_suggestion": "修改会议接口必须校验当前用户是否为会议创建者"
            }
        }
    },
    {
        "id": "sec_2_1_2b",
        "module_id": "sec_api01",
        "name": "水平越权取消其他用户会议",
        "description": "用普通用户Token尝试取消超级管理员的会议",
        "priority": "high",
        "tags": ["OWASP-API1", "水平越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/cancel/", "method": "PUT"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"id": "${meeting_id}"}},
            "pre_steps": [
                {"action": "get_resource_id", "account": "superadmin", "path": "/api/message/getMeetingList", "params": {"pageNo": 1, "pageSize": 5}, "extract": {"meeting_id": "data.records[0].id"}}
            ],
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "越权取消应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.1.2",
                "name": "水平越权取消其他用户会议",
                "level": "high",
                "description": "user可取消superadmin的会议，存在严重水平越权漏洞",
                "fix_suggestion": "取消会议接口必须校验当前用户是否为会议创建者或管理员"
            }
        }
    },
    {
        "id": "sec_2_1_3",
        "module_id": "sec_api01",
        "name": "水平越权访问其他用户收藏列表",
        "description": "通过修改userId参数访问其他用户的收藏列表",
        "priority": "high",
        "tags": ["OWASP-API1", "水平越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/userCollection/listUserCollectionPage", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"userId": "1", "pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "访问其他用户收藏应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.1.3",
                "name": "水平越权访问其他用户收藏列表",
                "level": "high",
                "description": "通过修改userId参数可访问其他用户收藏",
                "fix_suggestion": "收藏列表接口应从Token中提取用户ID，忽略客户端传入的userId参数"
            }
        }
    },
    {
        "id": "sec_2_1_4",
        "module_id": "sec_api01",
        "name": "水平越权跨公司创建会议",
        "description": "用普通用户Token修改companyNumber参数跨公司创建会议",
        "priority": "high",
        "tags": ["OWASP-API1", "水平越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/conference/insert", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"title": "安全测试", "companyNumber": "OTHER_COMPANY_001", "roomId": "1"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "跨公司创建应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.1.4",
                "name": "水平越权跨公司创建会议",
                "level": "high",
                "description": "通过修改companyNumber可跨公司创建会议，数据隔离被破坏",
                "fix_suggestion": "创建会议接口应从Token中提取用户的companyNumber"
            }
        }
    },
    {
        "id": "sec_2_1_5",
        "module_id": "sec_api01",
        "name": "水平越权访问运维集控设备接口",
        "description": "用普通用户Token访问运维集控设备管理接口",
        "priority": "high",
        "tags": ["OWASP-API1", "水平越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/monitor/api2/api/roommaster/", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "普通用户不应能访问运维集控"}
            ],
            "vulnerability": {
                "id": "2.1.5",
                "name": "水平越权访问运维集控设备接口",
                "level": "high",
                "description": "普通用户Token可访问运维集控设备管理接口",
                "fix_suggestion": "运维集控接口应增加角色权限校验"
            }
        }
    },
    {
        "id": "sec_2_1_7",
        "module_id": "sec_api01",
        "name": "IDOR遍历访问签到记录",
        "description": "遍历签到ID访问其他用户的签到记录",
        "priority": "high",
        "tags": ["OWASP-API1", "IDOR"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/signs/getSigns", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"id": "1"}},
            "assertions": [
                {"type": "is_success", "expect": False, "description": "遍历ID访问应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.1.7",
                "name": "IDOR遍历访问签到记录",
                "level": "high",
                "description": "通过遍历ID可访问其他用户签到记录",
                "fix_suggestion": "签到记录接口应校验当前用户权限"
            }
        }
    },
    {
        "id": "sec_2_1_8",
        "module_id": "sec_api01",
        "name": "IDOR遍历访问其他用户通知",
        "description": "遍历通知ID访问其他用户的通知",
        "priority": "high",
        "tags": ["OWASP-API1", "IDOR"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/notification/getNotificationByNoticeId", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"noticeId": "1"}},
            "assertions": [
                {"type": "is_success", "expect": False, "description": "遍历ID访问应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.1.8",
                "name": "IDOR遍历访问其他用户通知",
                "level": "high",
                "description": "通过遍历ID可访问其他用户通知",
                "fix_suggestion": "通知接口应校验当前用户是否为通知接收者"
            }
        }
    },

    # ==================== API2: 身份认证失效 ====================
    {
        "id": "sec_2_2_1",
        "module_id": "sec_api02",
        "name": "Token伪造测试",
        "description": "使用伪造的Token访问需要认证的接口",
        "priority": "high",
        "tags": ["OWASP-API2", "认证绕过"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user", "use_fake_token": True},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "伪造Token应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.2.1",
                "name": "Token伪造测试",
                "level": "high",
                "description": "伪造的Token未被正确校验",
                "fix_suggestion": "加强Token校验机制，增加签名验证"
            }
        }
    },
    {
        "id": "sec_2_2_2",
        "module_id": "sec_api02",
        "name": "NoSQL注入-登录接口",
        "description": "在登录接口username参数注入MongoDB操作符",
        "priority": "critical",
        "tags": ["OWASP-API2", "NoSQL注入", "Critical"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/login", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": {"$ne": "1"}, "password": "test", "code": "csba"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "NoSQL注入应被拦截"}
            ],
            "vulnerability": {
                "id": "2.2.2",
                "name": "NoSQL注入-登录接口",
                "level": "critical",
                "description": "登录接口存在NoSQL注入漏洞，可绕过认证（CVSS 9.4）",
                "fix_suggestion": "对username参数进行类型校验，确保为字符串类型"
            }
        }
    },
    {
        "id": "sec_2_2_3",
        "module_id": "sec_api02",
        "name": "暴力破解-登录接口",
        "description": "测试登录接口是否存在速率限制",
        "priority": "high",
        "tags": ["OWASP-API2", "暴力破解"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/login", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": "admin", "password": "wrong_password", "code": "csba"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "用户名或密码错误", "description": "连续错误登录应被限流"}
            ],
            "vulnerability": {
                "id": "2.2.3",
                "name": "暴力破解-登录接口",
                "level": "high",
                "description": "登录接口无速率限制，可被暴力破解",
                "fix_suggestion": "实现登录失败计数与账号临时锁定机制"
            }
        }
    },
    {
        "id": "sec_2_2_4",
        "module_id": "sec_api02",
        "name": "注销后Token未失效",
        "description": "注销后使用旧Token访问接口",
        "priority": "high",
        "tags": ["OWASP-API2", "会话管理"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user", "after_logout": True},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "注销后Token应失效"}
            ],
            "vulnerability": {
                "id": "2.2.4",
                "name": "注销后Token未失效",
                "level": "high",
                "description": "注销后旧Token仍可使用",
                "fix_suggestion": "实现Token黑名单机制"
            }
        }
    },
    {
        "id": "sec_2_2_5",
        "module_id": "sec_api02",
        "name": "JWT alg=none空签名伪造",
        "description": "使用alg=none的JWT Token访问需认证接口，验证JWT库是否校验签名算法",
        "priority": "critical",
        "tags": ["OWASP-API2", "JWT", "alg=none", "Critical"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user", "use_fake_token": True},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "alg=none的JWT应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.2.5",
                "name": "JWT alg=none空签名伪造",
                "level": "critical",
                "description": "JWT库未校验签名算法，alg=none的Token可绕过认证（CVSS 9.8）",
                "fix_suggestion": "JWT库应配置白名单算法，禁止使用none算法"
            }
        }
    },
    {
        "id": "sec_2_2_6",
        "module_id": "sec_api02",
        "name": "JWT弱密钥暴力破解",
        "description": "使用常见弱密钥验证JWT签名是否可被暴力破解",
        "priority": "high",
        "tags": ["OWASP-API2", "JWT", "弱密钥"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user", "use_fake_token": True},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "弱密钥签名的JWT应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.2.6",
                "name": "JWT弱密钥暴力破解",
                "level": "high",
                "description": "JWT使用弱密钥，可被暴力破解（对应历史漏洞HV-016）",
                "fix_suggestion": "使用强随机密钥（至少256位），定期轮换"
            }
        }
    },

    # ==================== API3: 对象属性级别授权失效 ====================
    {
        "id": "sec_2_3_001",
        "module_id": "sec_api03",
        "name": "越权访问其他用户属性-修改角色字段",
        "description": "普通用户通过修改请求体中的role字段尝试提升权限，验证是否存在属性级别越权漏洞",
        "priority": "high",
        "tags": ["OWASP-API3", "属性越权", "权限提升"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/manageUser/update", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"id": "${user_id}", "role": "superadmin"}},
            "pre_steps": [
                {"action": "get_resource_id", "account": "user", "path": "/api/manageUser/getManagerPage", "params": {"pageNo": 1, "pageSize": 5}, "extract": {"user_id": "data.records[0].id"}}
            ],
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "越权修改角色应被拒绝"},
                {"type": "response_code_contain", "expect": ["401", "403", "B0027"], "description": "应返回权限不足"}
            ],
            "vulnerability": {
                "id": "2.3.1",
                "name": "越权访问其他用户属性-修改角色字段",
                "level": "high",
                "description": "普通用户可通过修改role字段提升权限，存在属性级别越权漏洞",
                "fix_suggestion": "接口应校验用户是否有权修改角色等敏感属性，禁止客户端传入角色字段"
            }
        }
    },
    {
        "id": "sec_2_3_002",
        "module_id": "sec_api03",
        "name": "敏感字段未做权限校验-修改公司编号",
        "description": "普通用户通过修改companyNumber字段尝试跨公司操作，验证敏感属性是否有权限校验",
        "priority": "medium",
        "tags": ["OWASP-API3", "属性越权", "批量赋值"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/manageUser/update", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"id": "${user_id}", "companyNumber": "OTHER_COMPANY_001"}},
            "pre_steps": [
                {"action": "get_resource_id", "account": "user", "path": "/api/manageUser/getManagerPage", "params": {"pageNo": 1, "pageSize": 5}, "extract": {"user_id": "data.records[0].id"}}
            ],
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "修改公司编号应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.3.2",
                "name": "敏感字段未做权限校验-修改公司编号",
                "level": "medium",
                "description": "普通用户可修改companyNumber等敏感属性，存在批量赋值漏洞",
                "fix_suggestion": "接口应使用白名单机制，仅允许修改授权范围内的属性"
            }
        }
    },
    {
        "id": "sec_2_3_003",
        "module_id": "sec_api03",
        "name": "批量查询泄露敏感属性-用户列表接口",
        "description": "通过用户列表接口查询其他用户的敏感属性（密码哈希、Token等），验证响应是否过滤敏感字段",
        "priority": "high",
        "tags": ["OWASP-API3", "信息泄露", "敏感属性"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/manageUser/getManagerPage", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "body_not_contains", "expect": "password", "description": "响应不应包含密码字段"},
                {"type": "body_not_contains", "expect": "token", "description": "响应不应包含Token字段"}
            ],
            "vulnerability": {
                "id": "2.3.3",
                "name": "批量查询泄露敏感属性-用户列表接口",
                "level": "high",
                "description": "用户列表接口返回了密码哈希、Token等敏感属性，存在信息泄露",
                "fix_suggestion": "接口响应应过滤敏感字段，使用DTO/Schema控制返回属性"
            }
        }
    },

    # ==================== API4: 资源消耗不受限 ====================
    {
        "id": "sec_2_4_001",
        "name": "无速率限制的批量请求-会议查询",
        "module_id": "sec_api04",
        "description": "短时间内发送大量会议查询请求，验证是否存在速率限制",
        "priority": "high",
        "tags": ["OWASP-API4", "速率限制", "DoS"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "rate_limit_test": {"request_count": 50, "interval_ms": 100, "expect_limited": True},
            "assertions": [
                {"type": "rate_limit_exists", "expect": True, "description": "应存在速率限制"}
            ],
            "vulnerability": {
                "id": "2.4.1",
                "name": "无速率限制的批量请求-会议查询",
                "level": "high",
                "description": "会议查询接口无速率限制，可被用于DoS攻击",
                "fix_suggestion": "实现基于IP/用户的速率限制，如每分钟最多60次请求"
            }
        }
    },
    {
        "id": "sec_2_4_002",
        "module_id": "sec_api04",
        "name": "分页参数滥用-超大pageSize",
        "description": "使用超大pageSize参数请求列表接口，验证是否存在分页限制",
        "priority": "medium",
        "tags": ["OWASP-API4", "分页滥用", "资源消耗"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 99999}},
            "assertions": [
                {"type": "response_size_limit", "expect_max_kb": 1024, "description": "响应大小应有限制"}
            ],
            "vulnerability": {
                "id": "2.4.2",
                "name": "分页参数滥用-超大pageSize",
                "level": "medium",
                "description": "列表接口允许超大pageSize，可导致大量数据查询消耗服务器资源",
                "fix_suggestion": "限制pageSize最大值（如100），超出自动截断"
            }
        }
    },
    {
        "id": "sec_2_4_003",
        "module_id": "sec_api04",
        "name": "复杂查询无超时限制-深度分页",
        "description": "使用深度分页参数请求列表接口，验证查询是否有超时限制",
        "priority": "medium",
        "tags": ["OWASP-API4", "深度分页", "超时限制"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 999999, "pageSize": 100}},
            "assertions": [
                {"type": "response_time_limit", "expect_max_seconds": 10, "description": "查询应在10秒内返回"}
            ],
            "vulnerability": {
                "id": "2.4.3",
                "name": "复杂查询无超时限制-深度分页",
                "level": "medium",
                "description": "深度分页查询无超时限制，可导致慢查询消耗数据库资源",
                "fix_suggestion": "实现查询超时机制，限制最大分页深度"
            }
        }
    },

    # ==================== API6: 无限制访问敏感业务流 ====================
    {
        "id": "sec_2_6_001",
        "module_id": "sec_api06",
        "name": "敏感业务流程无验证码-短信接口",
        "description": "测试短信发送接口是否存在验证码或频率限制，防止短信轰炸",
        "priority": "high",
        "tags": ["OWASP-API6", "短信轰炸", "业务滥用"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/sms/send", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"phone": "13800138000"}},
            "rate_limit_test": {"request_count": 10, "interval_ms": 500, "expect_limited": True},
            "assertions": [
                {"type": "rate_limit_exists", "expect": True, "description": "短信接口应有频率限制"}
            ],
            "vulnerability": {
                "id": "2.6.1",
                "name": "敏感业务流程无验证码-短信接口",
                "level": "high",
                "description": "短信发送接口无验证码和频率限制，可被用于短信轰炸攻击",
                "fix_suggestion": "增加图形验证码和发送频率限制（如每分钟1次）"
            }
        }
    },
    {
        "id": "sec_2_6_002",
        "module_id": "sec_api06",
        "name": "批量操作无二次确认-批量删除会议",
        "description": "测试批量删除接口是否需要二次确认或额外授权",
        "priority": "medium",
        "tags": ["OWASP-API6", "批量操作", "二次确认"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/batchDelete", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"ids": ["1", "2", "3", "4", "5"]}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "批量删除应需额外确认"}
            ],
            "vulnerability": {
                "id": "2.6.2",
                "name": "批量操作无二次确认-批量删除会议",
                "level": "medium",
                "description": "批量删除接口无需二次确认，误操作风险高",
                "fix_suggestion": "批量操作应增加二次确认机制或操作审批流程"
            }
        }
    },
    {
        "id": "sec_2_6_003",
        "module_id": "sec_api06",
        "name": "自动化攻击检测缺失-批量注册",
        "description": "测试注册接口是否存在自动化攻击检测机制",
        "priority": "high",
        "tags": ["OWASP-API6", "批量注册", "自动化攻击"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/register", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": "bot_test_${timestamp}", "password": "Test@12345", "code": "csba"}},
            "rate_limit_test": {"request_count": 5, "interval_ms": 1000, "expect_limited": True},
            "assertions": [
                {"type": "rate_limit_exists", "expect": True, "description": "注册接口应有频率限制"}
            ],
            "vulnerability": {
                "id": "2.6.3",
                "name": "自动化攻击检测缺失-批量注册",
                "level": "high",
                "description": "注册接口无自动化攻击检测，可被批量注册垃圾账号",
                "fix_suggestion": "增加注册频率限制和图形验证码"
            }
        }
    },

    # ==================== API7: 服务器端请求伪造 ====================
    {
        "id": "sec_2_7_001",
        "module_id": "sec_api07",
        "name": "SSRF内网IP探测-会议服务",
        "description": "通过修改请求参数中的URL/IP字段尝试探测内网服务",
        "priority": "critical",
        "tags": ["OWASP-API7", "SSRF", "内网探测", "Critical"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10, "callback": "http://127.0.0.1:8848/nacos/"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "nacos", "description": "不应返回内网服务信息"}
            ],
            "vulnerability": {
                "id": "2.7.1",
                "name": "SSRF内网IP探测-会议服务",
                "level": "critical",
                "description": "通过callback参数可探测内网服务，存在SSRF漏洞（CVSS 9.1）",
                "fix_suggestion": "禁止callback参数指向内网地址，使用URL白名单机制"
            }
        }
    },
    {
        "id": "sec_2_7_002",
        "module_id": "sec_api07",
        "name": "SSRF云元数据接口访问",
        "description": "尝试通过SSRF访问云服务器元数据接口（169.254.169.254）",
        "priority": "critical",
        "tags": ["OWASP-API7", "SSRF", "云元数据", "Critical"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10, "url": "http://169.254.169.254/latest/meta-data/"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "ami-id", "description": "不应返回云元数据"},
                {"type": "body_not_contains", "expect": "instance-id", "description": "不应返回实例信息"}
            ],
            "vulnerability": {
                "id": "2.7.2",
                "name": "SSRF云元数据接口访问",
                "level": "critical",
                "description": "可通过SSRF访问云元数据接口获取敏感信息（CVSS 9.8）",
                "fix_suggestion": "禁止请求指向169.254.169.254等元数据地址，限制出站请求目标"
            }
        }
    },
    {
        "id": "sec_2_7_003",
        "module_id": "sec_api07",
        "name": "SSRF文件读取-本地文件",
        "description": "尝试通过SSRF读取本地文件（file:///etc/passwd）",
        "priority": "high",
        "tags": ["OWASP-API7", "SSRF", "文件读取"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10, "url": "file:///etc/passwd"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "root:", "description": "不应返回本地文件内容"}
            ],
            "vulnerability": {
                "id": "2.7.3",
                "name": "SSRF文件读取-本地文件",
                "level": "high",
                "description": "可通过SSRF读取服务器本地文件",
                "fix_suggestion": "禁止file://协议，仅允许http/https协议且限制目标域名"
            }
        }
    },

    # ==================== API9: 库存管理不当 ====================
    {
        "id": "sec_2_9_001",
        "module_id": "sec_api09",
        "name": "未授权访问已废弃API-旧版接口",
        "description": "测试旧版API接口是否仍可访问且无需认证",
        "priority": "high",
        "tags": ["OWASP-API9", "废弃API", "未授权访问"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/v1/api/meeting/list", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "旧版API应已下线或需认证"}
            ],
            "vulnerability": {
                "id": "2.9.1",
                "name": "未授权访问已废弃API-旧版接口",
                "level": "high",
                "description": "旧版API仍可匿名访问，存在未授权访问风险",
                "fix_suggestion": "下线废弃API或增加认证机制，API网关统一管理版本"
            }
        }
    },
    {
        "id": "sec_2_9_002",
        "module_id": "sec_api09",
        "name": "测试环境API暴露-调试接口",
        "description": "检测测试/调试接口是否在生产环境暴露",
        "priority": "medium",
        "tags": ["OWASP-API9", "调试接口", "信息泄露"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/actuator", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "调试接口不应暴露"}
            ],
            "vulnerability": {
                "id": "2.9.2",
                "name": "测试环境API暴露-调试接口",
                "level": "medium",
                "description": "Spring Boot Actuator调试接口在生产环境暴露",
                "fix_suggestion": "生产环境禁用Actuator或限制内网访问"
            }
        }
    },
    {
        "id": "sec_2_9_003",
        "module_id": "sec_api09",
        "name": "API版本信息泄露-响应头",
        "description": "检测API响应头是否泄露服务器版本信息",
        "priority": "low",
        "tags": ["OWASP-API9", "版本泄露", "信息泄露"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "header_not_contains", "expect": ["X-Powered-By", "Server"], "description": "响应头不应泄露服务器信息"}
            ],
            "vulnerability": {
                "id": "2.9.3",
                "name": "API版本信息泄露-响应头",
                "level": "low",
                "description": "API响应头泄露了服务器版本信息，可辅助攻击者定位漏洞",
                "fix_suggestion": "移除X-Powered-By、Server等版本信息响应头"
            }
        }
    },

    # ==================== API10: 不安全的第三方API集成 ====================
    {
        "id": "sec_2_10_001",
        "module_id": "sec_api10",
        "name": "第三方API响应未校验-WeLink回调",
        "description": "测试WeLink回调接口是否校验请求来源，防止伪造回调",
        "priority": "high",
        "tags": ["OWASP-API10", "第三方API", "回调校验"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/welink/callback", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"event": "meeting.created", "data": {"meetingId": "fake_id"}}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "伪造回调应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.10.1",
                "name": "第三方API响应未校验-WeLink回调",
                "level": "high",
                "description": "WeLink回调接口未校验请求来源，可被伪造回调注入数据",
                "fix_suggestion": "校验回调请求签名，确保请求来自合法的WeLink服务"
            }
        }
    },
    {
        "id": "sec_2_10_002",
        "module_id": "sec_api10",
        "name": "第三方API超时未处理-外部服务调用",
        "description": "测试外部服务调用是否有超时和降级机制",
        "priority": "medium",
        "tags": ["OWASP-API10", "超时处理", "服务降级"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/welink/sync", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"timeout_test": True}},
            "assertions": [
                {"type": "response_time_limit", "expect_max_seconds": 30, "description": "外部调用应在30秒内超时"}
            ],
            "vulnerability": {
                "id": "2.10.2",
                "name": "第三方API超时未处理-外部服务调用",
                "level": "medium",
                "description": "外部服务调用无超时机制，第三方服务不可用时会导致系统阻塞",
                "fix_suggestion": "为所有外部API调用设置超时时间和降级策略"
            }
        }
    },
    {
        "id": "sec_2_10_003",
        "module_id": "sec_api10",
        "name": "第三方API密钥泄露-配置文件",
        "description": "检测前端代码或配置文件中是否泄露第三方API密钥",
        "priority": "critical",
        "tags": ["OWASP-API10", "密钥泄露", "Critical"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/static/config.json", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "body_not_contains", "expect": "api_key", "description": "配置文件不应包含API密钥"},
                {"type": "body_not_contains", "expect": "secret", "description": "配置文件不应包含密钥"},
                {"type": "body_not_contains", "expect": "app_key", "description": "配置文件不应包含应用密钥"}
            ],
            "vulnerability": {
                "id": "2.10.3",
                "name": "第三方API密钥泄露-配置文件",
                "level": "critical",
                "description": "前端配置文件中包含第三方API密钥，可被攻击者获取（CVSS 9.1）",
                "fix_suggestion": "将API密钥移至后端环境变量，前端不存储任何密钥信息"
            }
        }
    },

    # ==================== API5: 功能级别授权失效 ====================
    {
        "id": "sec_2_5_1",
        "module_id": "sec_api05",
        "name": "普通用户访问管理员接口-用户管理",
        "description": "普通用户尝试访问管理员用户管理接口",
        "priority": "high",
        "tags": ["OWASP-API5", "垂直越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/manageUser/getManagerPage", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "普通用户不应能访问管理员接口"}
            ],
            "vulnerability": {
                "id": "2.5.1",
                "name": "普通用户访问管理员接口",
                "level": "high",
                "description": "普通用户可访问管理员接口",
                "fix_suggestion": "接口增加RBAC权限校验"
            }
        }
    },
    {
        "id": "sec_2_5_2",
        "module_id": "sec_api05",
        "name": "普通用户访问权限组管理接口",
        "description": "普通用户尝试访问权限组管理接口",
        "priority": "high",
        "tags": ["OWASP-API5", "垂直越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/permissionGroup/add", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"name": "测试权限组"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "普通用户不应能访问权限管理接口"}
            ],
            "vulnerability": {
                "id": "2.5.2",
                "name": "普通用户访问权限组管理接口",
                "level": "high",
                "description": "普通用户可操作权限组管理",
                "fix_suggestion": "权限组接口增加管理员角色校验"
            }
        }
    },

    # ==================== API8: 安全配置错误 ====================
    {
        "id": "sec_2_8_1",
        "module_id": "sec_api08",
        "name": "Nacos未授权访问",
        "description": "检测Nacos控制台是否可匿名访问",
        "priority": "high",
        "tags": ["OWASP-API8", "配置错误"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/nacos/", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "Nacos不应匿名访问"}
            ],
            "vulnerability": {
                "id": "2.8.1",
                "name": "Nacos未授权访问",
                "level": "high",
                "description": "Nacos控制台可匿名访问",
                "fix_suggestion": "Nginx层面限制/nacos路径仅内网可访问"
            }
        }
    },
    {
        "id": "sec_2_8_2",
        "module_id": "sec_api08",
        "name": "Swagger文档暴露",
        "description": "检测Swagger文档是否对外暴露",
        "priority": "medium",
        "tags": ["OWASP-API8", "信息泄露"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/swagger-ui.html", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "Swagger文档不应暴露"}
            ],
            "vulnerability": {
                "id": "2.8.2",
                "name": "Swagger文档暴露",
                "level": "medium",
                "description": "Swagger API文档对外暴露",
                "fix_suggestion": "生产环境禁用Swagger或限制内网访问"
            }
        }
    },
    {
        "id": "sec_2_8_3",
        "module_id": "sec_api08",
        "name": "SQL注入-会议查询接口",
        "description": "测试会议查询接口是否存在SQL注入",
        "priority": "high",
        "tags": ["OWASP-API8", "SQL注入"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"title": "' OR '1'='1", "pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "body_not_contains", "expect": "SQL", "description": "SQL注入应被拦截"}
            ],
            "vulnerability": {
                "id": "2.8.3",
                "name": "SQL注入-会议查询接口",
                "level": "high",
                "description": "会议查询接口存在SQL注入漏洞",
                "fix_suggestion": "使用参数化查询，禁止直接拼接SQL"
            }
        }
    },
    {
        "id": "sec_2_8_4",
        "module_id": "sec_api08",
        "name": "敏感配置文件泄露",
        "description": "检测config.json等敏感配置文件是否可访问",
        "priority": "high",
        "tags": ["OWASP-API8", "信息泄露"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/static/config.json", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "配置文件不应泄露"}
            ],
            "vulnerability": {
                "id": "2.8.4",
                "name": "敏感配置文件泄露",
                "level": "high",
                "description": "config.json含敏感信息可被外部访问",
                "fix_suggestion": "删除前端敏感配置或限制访问"
            }
        }
    },
    {
        "id": "sec_2_8_5",
        "module_id": "sec_api08",
        "name": "XSS跨站脚本-会议标题注入",
        "description": "在会议标题中注入XSS payload，验证是否存在反射型/存储型XSS漏洞",
        "priority": "high",
        "tags": ["OWASP-API8", "XSS", "输入验证"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/insert", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"title": "<script>alert('xss')</script>", "content": "安全测试XSS"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "XSS注入应被拦截"}
            ],
            "vulnerability": {
                "id": "2.8.5",
                "name": "XSS跨站脚本-会议标题注入",
                "level": "high",
                "description": "会议标题未过滤XSS payload，存在存储型XSS漏洞",
                "fix_suggestion": "对所有用户输入进行HTML实体编码，使用富文本白名单过滤"
            }
        }
    },
    {
        "id": "sec_2_8_6",
        "module_id": "sec_api08",
        "name": "XSS跨站脚本-URL参数反射",
        "description": "在URL参数中注入XSS payload，验证是否存在反射型XSS漏洞",
        "priority": "high",
        "tags": ["OWASP-API8", "XSS", "反射型XSS"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10, "title": "<img src=x onerror=alert(1)>"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "<img src=x onerror=alert(1)", "description": "XSS payload不应反射回响应"}
            ],
            "vulnerability": {
                "id": "2.8.6",
                "name": "XSS跨站脚本-URL参数反射",
                "level": "high",
                "description": "URL参数未编码直接反射回响应，存在反射型XSS漏洞",
                "fix_suggestion": "对所有输出进行HTML实体编码，设置Content-Type为json并正确转义"
            }
        }
    },
    {
        "id": "sec_2_8_7",
        "module_id": "sec_api08",
        "name": "CORS配置错误-任意域跨域请求",
        "description": "测试API响应头是否允许任意Origin跨域访问，验证CORS配置是否安全",
        "priority": "high",
        "tags": ["OWASP-API8", "CORS", "配置错误"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "cors_allow_wildcard", "expect": True, "description": "CORS不应允许任意域"}
            ],
            "vulnerability": {
                "id": "2.8.7",
                "name": "CORS配置错误-任意域跨域请求",
                "level": "high",
                "description": "API响应包含Access-Control-Allow-Origin: *，允许任意域跨域访问",
                "fix_suggestion": "配置CORS白名单，仅允许受信任的域名访问"
            }
        }
    },
    {
        "id": "sec_2_8_8",
        "module_id": "sec_api08",
        "name": "HTTP方法篡改-越权操作",
        "description": "使用非标准HTTP方法（PUT/DELETE/PATCH）尝试越权操作",
        "priority": "medium",
        "tags": ["OWASP-API8", "HTTP方法", "配置错误"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/delete", "method": "DELETE"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"id": "1"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "DELETE方法应被拒绝或返回405"}
            ],
            "vulnerability": {
                "id": "2.8.8",
                "name": "HTTP方法篡改-越权操作",
                "level": "medium",
                "description": "DELETE方法未被禁用，可被用于越权删除操作",
                "fix_suggestion": "禁用非必要HTTP方法，使用白名单方式仅允许GET/POST"
            }
        }
    },
    {
        "id": "sec_2_8_9",
        "module_id": "sec_api08",
        "name": "HTTP方法覆写绕过",
        "description": "使用X-HTTP-Method-Override头尝试绕过方法限制",
        "priority": "medium",
        "tags": ["OWASP-API8", "HTTP方法覆写", "绕过"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/update", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"id": "1", "title": "hacked"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "方法覆写应被拒绝"}
            ],
            "vulnerability": {
                "id": "2.8.9",
                "name": "HTTP方法覆写绕过",
                "level": "medium",
                "description": "通过X-HTTP-Method-Override可绕过方法级权限控制",
                "fix_suggestion": "禁用X-HTTP-Method-Override/X-HTTP-Method等覆写头"
            }
        }
    },
    {
        "id": "sec_2_8_10",
        "module_id": "sec_api08",
        "name": "安全响应头缺失检查",
        "description": "检测API响应是否缺少关键安全响应头（X-Frame-Options、CSP、HSTS等）",
        "priority": "medium",
        "tags": ["OWASP-API8", "安全头", "配置错误"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "header_contains", "expect": ["X-Frame-Options"], "description": "应包含X-Frame-Options头"},
                {"type": "header_contains", "expect": ["Content-Security-Policy"], "description": "应包含CSP头"},
                {"type": "header_contains", "expect": ["Strict-Transport-Security"], "description": "应包含HSTS头"},
                {"type": "header_contains", "expect": ["X-Content-Type-Options"], "description": "应包含X-Content-Type-Options头"}
            ],
            "vulnerability": {
                "id": "2.8.10",
                "name": "安全响应头缺失检查",
                "level": "medium",
                "description": "API响应缺少X-Frame-Options/CSP/HSTS等安全响应头（对应历史漏洞HV-003）",
                "fix_suggestion": "配置Nginx反向代理添加安全响应头：X-Frame-Options DENY、CSP、HSTS、X-Content-Type-Options nosniff"
            }
        }
    },
    {
        "id": "sec_hv_001",
        "module_id": "sec_regression",
        "name": "HV-001 SQL注入-会议预定接口",
        "description": "历史漏洞回归：会议预定接口SQL注入（长安深蓝汽车）",
        "priority": "high",
        "tags": ["历史漏洞", "SQL注入", "长安深蓝汽车"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/book", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"title": "' OR '1'='1--"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "SQL注入应被拦截"}
            ],
            "vulnerability": {
                "id": "HV-001",
                "name": "SQL注入-会议预定接口",
                "level": "high",
                "description": "历史漏洞：会议预定接口SQL注入",
                "fix_suggestion": "使用预编译语句"
            }
        }
    },
    {
        "id": "sec_hv_005",
        "module_id": "sec_regression",
        "name": "HV-005 Nacos未授权访问",
        "description": "历史漏洞回归：Nacos配置中心未授权访问（南山区委）",
        "priority": "high",
        "tags": ["历史漏洞", "未授权访问", "南山区委"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/nacos/v1/cs/configs", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "Nacos应需认证"}
            ],
            "vulnerability": {
                "id": "HV-005",
                "name": "Nacos未授权访问",
                "level": "high",
                "description": "历史漏洞：Nacos配置列表可匿名访问",
                "fix_suggestion": "开启Nacos鉴权"
            }
        }
    },
    {
        "id": "sec_hv_011",
        "module_id": "sec_regression",
        "name": "HV-011 Nacos serverIdentity权限绕过",
        "description": "历史漏洞回归：Nacos用户列表接口权限绕过",
        "priority": "high",
        "tags": ["历史漏洞", "权限绕过", "长安深蓝汽车"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/nacos/v1/auth/users", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "用户列表不应匿名访问"}
            ],
            "vulnerability": {
                "id": "HV-011",
                "name": "Nacos serverIdentity权限绕过",
                "level": "high",
                "description": "历史漏洞：Nacos用户列表可匿名访问",
                "fix_suggestion": "升级Nacos版本并开启鉴权"
            }
        }
    },

    {
        "id": "sec_hv_003",
        "module_id": "sec_regression",
        "name": "HV-003 安全响应头缺失（全站）",
        "description": "历史漏洞回归：全站安全响应头缺失（厦门银行总行大厦、龙华儿童医院）",
        "priority": "medium",
        "tags": ["历史漏洞", "安全头", "华为Web漏扫"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "header_contains", "expect": ["X-Frame-Options"], "description": "应包含X-Frame-Options头"},
                {"type": "header_contains", "expect": ["Content-Security-Policy"], "description": "应包含CSP头"},
                {"type": "header_contains", "expect": ["Strict-Transport-Security"], "description": "应包含HSTS头"}
            ],
            "vulnerability": {
                "id": "HV-003",
                "name": "安全响应头缺失（全站）",
                "level": "medium",
                "description": "历史漏洞：X-Frame-Options、CSP、HSTS等安全头未配置",
                "fix_suggestion": "Nginx全局配置安全响应头"
            }
        }
    },
    {
        "id": "sec_hv_006",
        "module_id": "sec_regression",
        "name": "HV-006 Swagger文档暴露",
        "description": "历史漏洞回归：Swagger API文档暴露（历史多个项目）",
        "priority": "medium",
        "tags": ["历史漏洞", "信息泄露"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/swagger-ui.html", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "Swagger文档不应暴露"}
            ],
            "vulnerability": {
                "id": "HV-006",
                "name": "Swagger文档暴露",
                "level": "medium",
                "description": "历史漏洞：Swagger API文档对外暴露",
                "fix_suggestion": "生产环境禁用Swagger或限制内网访问"
            }
        }
    },
    {
        "id": "sec_hv_007",
        "module_id": "sec_regression",
        "name": "HV-007 固定验证码csba",
        "description": "历史漏洞回归：登录验证码固定为csba（需求文档确认）",
        "priority": "medium",
        "tags": ["历史漏洞", "固定验证码", "弱认证"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/login", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": "admin", "password": "wrong_pwd_test", "code": "csba"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "验证码错误", "description": "固定验证码csba不应被接受"}
            ],
            "vulnerability": {
                "id": "HV-007",
                "name": "固定验证码csba",
                "level": "medium",
                "description": "历史漏洞：登录验证码固定为csba，可被绕过暴力破解防护",
                "fix_suggestion": "改为动态随机验证码"
            }
        }
    },
    {
        "id": "sec_hv_026",
        "module_id": "sec_regression",
        "name": "HV-026 NoSQL注入-登录接口",
        "description": "历史漏洞回归：登录接口username参数NoSQL注入（新统一平台AppScan）",
        "priority": "critical",
        "tags": ["历史漏洞", "NoSQL注入", "新统一平台"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/login", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": {"$ne": "invalid"}, "password": "test", "code": "csba"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "NoSQL注入应被拦截"}
            ],
            "vulnerability": {
                "id": "HV-026",
                "name": "NoSQL注入-登录接口",
                "level": "critical",
                "description": "历史漏洞：username参数类型校验不足，可NoSQL注入绕过认证",
                "fix_suggestion": "加强username参数类型校验，确保为字符串"
            }
        }
    },
    {
        "id": "sec_hv_027",
        "module_id": "sec_regression",
        "name": "HV-027 API成批分配-用户查询接口",
        "description": "历史漏洞回归：用户查询接口可注入is_admin/role字段（新统一平台AppScan）",
        "priority": "high",
        "tags": ["历史漏洞", "成批分配", "新统一平台"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/manageUser/getManagerPageForBook", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"pageNo": 1, "pageSize": 10, "role": "superadmin", "is_admin": True}},
            "assertions": [
                {"type": "body_not_contains", "expect": "role", "description": "不应返回role字段"}
            ],
            "vulnerability": {
                "id": "HV-027",
                "name": "API成批分配-用户查询接口",
                "level": "high",
                "description": "历史漏洞：请求体可注入is_admin/role等敏感字段",
                "fix_suggestion": "使用白名单方式接收参数，忽略未声明字段"
            }
        }
    },
    {
        "id": "sec_hv_030",
        "module_id": "sec_regression",
        "name": "HV-030 注销后Token未失效",
        "description": "历史漏洞回归：注销后使用旧Token调用接口仍有效（南山区委渗透测试）",
        "priority": "high",
        "tags": ["历史漏洞", "会话管理", "南山区委"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user", "after_logout": True},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "注销后旧Token应失效"}
            ],
            "vulnerability": {
                "id": "HV-030",
                "name": "注销后Token/会话未失效",
                "level": "high",
                "description": "历史漏洞：注销后旧Token仍可用于认证接口",
                "fix_suggestion": "实现Token黑名单或短TTL+刷新机制"
            }
        }
    },
    {
        "id": "sec_hv_031",
        "module_id": "sec_regression",
        "name": "HV-031 运维集控越权访问",
        "description": "历史漏洞回归：普通用户访问运维集控管理接口（天津海油渗透测试）",
        "priority": "high",
        "tags": ["历史漏洞", "越权访问", "天津海油"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/monitor/api2/api/roommaster/", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "普通用户不应访问运维集控"}
            ],
            "vulnerability": {
                "id": "HV-031",
                "name": "运维集控越权访问-company_id参数未校验",
                "level": "high",
                "description": "历史漏洞：使用普通用户Token可访问运维集控管理接口",
                "fix_suggestion": "运维集控接口增加company_id与用户权限校验"
            }
        }
    },

    # ==================== 华为安全红线 ====================
    {
        "id": "sec_hw_01",
        "module_id": "sec_redline",
        "name": "HW-01 密码存储加盐哈希",
        "description": "华为红线：密码存储必须使用加盐哈希",
        "priority": "high",
        "tags": ["华为红线", "加密规范"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/login", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": "test", "password": "test", "code": "csba"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "SHA256", "description": "不应暴露哈希算法"}
            ],
            "vulnerability": {
                "id": "HW-01",
                "name": "密码存储加盐哈希",
                "level": "high",
                "description": "华为红线检查：密码存储方式",
                "fix_suggestion": "使用bcrypt/argon2等加盐哈希"
            }
        }
    },
    {
        "id": "sec_hw_06",
        "module_id": "sec_redline",
        "name": "HW-06 注销后Token立即失效",
        "description": "华为红线：注销后Token必须立即失效",
        "priority": "high",
        "tags": ["华为红线", "会话管理"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user", "after_logout": True},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "注销后Token应失效"}
            ],
            "vulnerability": {
                "id": "HW-06",
                "name": "注销后Token立即失效",
                "level": "high",
                "description": "华为红线检查：Token失效机制",
                "fix_suggestion": "实现Token黑名单"
            }
        }
    },
    {
        "id": "sec_hw_03",
        "module_id": "sec_redline",
        "name": "HW-03 HTTPS协议强制使用",
        "description": "华为红线：必须使用HTTPS协议，禁止HTTP明文传输",
        "priority": "high",
        "tags": ["华为红线", "传输安全"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "http://", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "HTTP访问应被重定向或拒绝"}
            ],
            "vulnerability": {
                "id": "HW-03",
                "name": "HTTPS协议强制使用",
                "level": "high",
                "description": "华为红线检查：HTTP请求可正常访问，未强制HTTPS",
                "fix_suggestion": "Nginx配置HTTP到HTTPS的301重定向，并启用HSTS"
            }
        }
    },
    {
        "id": "sec_hw_05",
        "module_id": "sec_redline",
        "name": "HW-05 Token有效期不超过24小时",
        "description": "华为红线：Token有效期不应超过24小时",
        "priority": "medium",
        "tags": ["华为红线", "鉴权机制"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "header_contains", "expect": ["Token-Expire-In"], "description": "应返回Token过期时间信息"}
            ],
            "vulnerability": {
                "id": "HW-05",
                "name": "Token有效期不超过24小时",
                "level": "medium",
                "description": "华为红线检查：无法确认Token过期时间配置",
                "fix_suggestion": "设置Token过期时间为24小时内，并在响应中返回过期时间"
            }
        }
    },
    {
        "id": "sec_hw_07",
        "module_id": "sec_redline",
        "name": "HW-07 验证码必须随机生成",
        "description": "华为红线：验证码必须随机生成，禁止固定验证码",
        "priority": "medium",
        "tags": ["华为红线", "鉴权机制"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/login", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": "admin", "password": "wrong_pwd", "code": "csba"}},
            "assertions": [
                {"type": "body_not_contains", "expect": "验证码正确", "description": "固定验证码csba不应被接受"}
            ],
            "vulnerability": {
                "id": "HW-07",
                "name": "验证码必须随机生成",
                "level": "medium",
                "description": "华为红线检查：使用固定验证码csba可登录，验证码非随机生成",
                "fix_suggestion": "改为动态随机验证码，加入验证码有效期和一次性使用机制"
            }
        }
    },
    {
        "id": "sec_hw_08",
        "module_id": "sec_redline",
        "name": "HW-08 登录失败5次锁定账号15分钟",
        "description": "华为红线：连续登录失败5次后应锁定账号15分钟",
        "priority": "medium",
        "tags": ["华为红线", "暴力破解"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/platform/api/auth/login", "method": "POST"},
            "auth": {"required": False},
            "request": {"body": {"username": "admin", "password": "wrong_pwd", "code": "csba"}},
            "rate_limit_test": {"request_count": 6, "interval_ms": 100, "expect_limited": True},
            "assertions": [
                {"type": "rate_limit_exists", "expect": True, "description": "连续错误登录应触发锁定"}
            ],
            "vulnerability": {
                "id": "HW-08",
                "name": "登录失败5次后应锁定账号15分钟",
                "level": "medium",
                "description": "华为红线检查：连续错误登录未触发账号锁定机制",
                "fix_suggestion": "实现登录失败计数，5次失败后锁定账号15分钟"
            }
        }
    },
    {
        "id": "sec_hw_10",
        "module_id": "sec_redline",
        "name": "HW-10 Swagger文档不应暴露",
        "description": "华为红线：API文档不应在生产环境暴露",
        "priority": "medium",
        "tags": ["华为红线", "信息泄露"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/swagger-ui.html", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "Swagger文档不应暴露"}
            ],
            "vulnerability": {
                "id": "HW-10",
                "name": "Swagger/API文档不应在生产环境暴露",
                "level": "medium",
                "description": "华为红线检查：Swagger API文档对外暴露",
                "fix_suggestion": "生产环境禁用Swagger或限制内网访问"
            }
        }
    },
    {
        "id": "sec_hw_11",
        "module_id": "sec_redline",
        "name": "HW-11 调试接口和测试端点应关闭",
        "description": "华为红线：调试接口和测试端点不应在生产环境开放",
        "priority": "medium",
        "tags": ["华为红线", "调试接口"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/actuator", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "调试接口不应暴露"}
            ],
            "vulnerability": {
                "id": "HW-11",
                "name": "调试接口和测试端点应关闭",
                "level": "medium",
                "description": "华为红线检查：Actuator调试接口对外暴露",
                "fix_suggestion": "生产环境禁用调试端点或限制内网访问"
            }
        }
    },
    {
        "id": "sec_hw_12",
        "module_id": "sec_redline",
        "name": "HW-12 用户输入服务端校验-SQL注入",
        "description": "华为红线：所有用户输入必须进行服务端校验-SQL注入测试",
        "priority": "high",
        "tags": ["华为红线", "输入验证", "SQL注入"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMeetingList", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"title": "' OR '1'='1' --", "pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "body_not_contains", "expect": "SQL", "description": "SQL注入应被拦截"}
            ],
            "vulnerability": {
                "id": "HW-12",
                "name": "用户输入服务端校验-SQL注入",
                "level": "high",
                "description": "华为红线检查：未对用户输入进行服务端校验",
                "fix_suggestion": "使用参数化查询，对所有用户输入进行校验和过滤"
            }
        }
    },
    {
        "id": "sec_hw_13",
        "module_id": "sec_redline",
        "name": "HW-13 每个接口必须校验用户权限",
        "description": "华为红线：每个接口必须校验用户权限-垂直越权测试",
        "priority": "high",
        "tags": ["华为红线", "权限控制"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/manageUser/getManagerPage", "method": "POST"},
            "auth": {"required": True, "account": "user"},
            "request": {"body": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "普通用户不应访问管理员接口"}
            ],
            "vulnerability": {
                "id": "HW-13",
                "name": "每个接口必须校验用户权限-垂直越权测试",
                "level": "high",
                "description": "华为红线检查：普通用户可访问管理员接口，权限校验缺失",
                "fix_suggestion": "所有接口增加RBAC权限校验，标注所需的角色权限"
            }
        }
    },
    {
        "id": "sec_hw_14",
        "module_id": "sec_redline",
        "name": "HW-14 用户只能访问自己的数据",
        "description": "华为红线：用户只能访问自己的数据-水平越权测试",
        "priority": "high",
        "tags": ["华为红线", "水平越权"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/message/getMessageById", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"id": "1"}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "应拒绝访问非自己的数据"}
            ],
            "vulnerability": {
                "id": "HW-14",
                "name": "用户只能访问自己的数据-水平越权测试",
                "level": "high",
                "description": "华为红线检查：通过遍历ID可访问其他用户的数据",
                "fix_suggestion": "接口应校验数据归属与当前用户是否匹配"
            }
        }
    },
    {
        "id": "sec_hw_15",
        "module_id": "sec_redline",
        "name": "HW-15 敏感操作必须记录日志",
        "description": "华为红线：敏感操作必须记录日志-登录操作日志检查",
        "priority": "medium",
        "tags": ["华为红线", "日志审计"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/api/system/logs", "method": "GET"},
            "auth": {"required": True, "account": "user"},
            "request": {"params": {"pageNo": 1, "pageSize": 10}},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "日志接口应需管理员权限"}
            ],
            "vulnerability": {
                "id": "HW-15",
                "name": "敏感操作必须记录日志-登录操作日志检查",
                "level": "medium",
                "description": "华为红线检查：操作日志接口普通用户可访问或无法确认日志记录",
                "fix_suggestion": "确保所有敏感操作（登录、权限变更、数据删除等）记录审计日志"
            }
        }
    },
    {
        "id": "sec_hw_09",
        "module_id": "sec_redline",
        "name": "HW-09 中间件管理界面不对外开放",
        "description": "华为红线：中间件管理界面不应暴露",
        "priority": "high",
        "tags": ["华为红线", "配置管理"],
        "steps": {
            "test_type": "api_security",
            "target": {"base_url": "", "path": "/nacos/", "method": "GET"},
            "auth": {"required": False},
            "request": {},
            "assertions": [
                {"type": "status_code_not_equal", "expect": 200, "description": "Nacos不应外部访问"}
            ],
            "vulnerability": {
                "id": "HW-09",
                "name": "中间件管理界面不对外开放",
                "level": "high",
                "description": "华为红线检查：中间件暴露",
                "fix_suggestion": "Nginx限制中间件路径"
            }
        }
    },
]


def create_security_modules_and_cases():
    """创建安全测试模块和用例"""

    # 连接数据库（支持环境变量 DATABASE_URL 覆盖，用于 Docker/MySQL 部署）
    db_url = os.environ.get("DATABASE_URL")
    if not db_url:
        db_path = os.path.join(os.path.dirname(__file__), "..", "data", "test_platform.db")
        db_url = f"sqlite:///{os.path.abspath(db_path)}"

    # 本脚本使用同步 SQLAlchemy 会话；若 DATABASE_URL 是异步 aiomysql URL，
    # 需翻译成同步 pymysql URL（模块导入仍用原 env，此处仅用于同步引擎）
    if db_url.startswith("mysql+aiomysql://"):
        sync_url = "mysql+pymysql://" + db_url[len("mysql+aiomysql://"):]
        print(f"  数据库: {db_url}  → (同步引擎切换为 {sync_url})")
        db_url = sync_url
    else:
        print(f"  数据库: {db_url}")

    engine = create_engine(db_url)
    Session = sessionmaker(bind=engine)
    session = Session()

    try:
        # 创建模块
        print("=" * 60)
        print("创建安全测试模块...")
        print("=" * 60)

        module_count = 0
        for mod_data in SECURITY_MODULES:
            existing = session.query(Module).filter_by(id=mod_data["id"]).first()
            if existing:
                print(f"  模块已存在: {mod_data['name']}")
                continue

            module = Module(
                id=mod_data["id"],
                name=mod_data["name"],
                description=mod_data["description"],
                icon=mod_data["icon"],
                order=mod_data["order"],
                module_type="security",
            )
            session.add(module)
            module_count += 1
            print(f"  ✅ 创建模块: {mod_data['name']}")

        session.commit()
        print(f"\n模块创建完成: {module_count} 个新模块")

        # 创建用例
        print("\n" + "=" * 60)
        print("创建安全测试用例...")
        print("=" * 60)

        case_count = 0
        for case_data in SECURITY_CASES:
            existing = session.query(TestCase).filter_by(id=case_data["id"]).first()
            if existing:
                print(f"  用例已存在: {case_data['name']}")
                continue

            case = TestCase(
                id=case_data["id"],
                module_id=case_data["module_id"],
                name=case_data["name"],
                description=case_data.get("description", ""),
                priority=case_data.get("priority", "medium"),
                tags=case_data.get("tags", []),
                steps=case_data["steps"],
                config={},
                case_type="security",
                status="active",
            )
            session.add(case)
            case_count += 1
            print(f"  ✅ 创建用例: {case_data['id']} - {case_data['name']}")

        session.commit()
        print(f"\n用例创建完成: {case_count} 个新用例")

        # 统计
        print("\n" + "=" * 60)
        print("安全测试模块统计")
        print("=" * 60)

        total_modules = session.query(Module).filter(Module.module_type == "security").count()
        total_cases = session.query(TestCase).filter(TestCase.case_type == "security").count()

        print(f"  安全测试模块总数: {total_modules}")
        print(f"  安全测试用例总数: {total_cases}")

        # 按模块统计
        for mod in SECURITY_MODULES:
            count = session.query(TestCase).filter(
                TestCase.module_id == mod["id"],
                TestCase.case_type == "security"
            ).count()
            if count > 0:
                print(f"    - {mod['name']}: {count} 个用例")

    except Exception as e:
        session.rollback()
        print(f"❌ 错误: {e}")
        raise
    finally:
        session.close()


if __name__ == "__main__":
    create_security_modules_and_cases()