Files
Fu-Jie_openwebui-extensions/plugins/debug/openwebui-skills-manager/TEST_GUIDE.md
fujie d29c24ba4a feat(openwebui-skills-manager): enhance auto-discovery and structural refactoring
- Enable default overwrite installation policy for overlapping skills
- Support deep recursive GitHub trees discovery mechanism to resolve #58
- Refactor internal architecture to fully decouple stateless helper logic
- READMEs and docs synced (v0.3.0)
2026-03-08 18:21:21 +08:00

6.9 KiB
Raw Blame History

OpenWebUI Skills Manager 安全修复测试指南

快速开始

无需 OpenWebUI 依赖的独立测试

已创建完全独立的测试脚本,不需要任何 OpenWebUI 依赖,可以直接运行:

python3 plugins/debug/openwebui-skills-manager/test_security_fixes.py

测试输出示例

🔒 OpenWebUI Skills Manager 安全修复测试
版本: 0.2.2
============================================================

✓ 所有测试通过!

修复验证:
  ✓ SSRF 防护:阻止指向内部 IP 的请求
  ✓ TAR/ZIP 安全提取:防止路径遍历攻击
  ✓ 名称冲突检查:防止技能名称重复
  ✓ URL 验证:仅接受安全的 HTTP(S) URL

五个测试用例详解

1. SSRF 防护测试

文件: test_security_fixes.py - test_ssrf_protection()

测试 _is_safe_url() 方法能否正确识别并拒绝危险的 URL

被拒绝的 URL (10 种)
✗ http://localhost/skill
✗ http://127.0.0.1:8000/skill              # 127.0.0.1 环回地址
✗ http://[::1]/skill                       # IPv6 环回
✗ http://0.0.0.0/skill                     # 全零 IP
✗ http://192.168.1.1/skill                 # RFC 1918 私有范围
✗ http://10.0.0.1/skill                    # RFC 1918 私有范围
✗ http://172.16.0.1/skill                  # RFC 1918 私有范围
✗ http://169.254.1.1/skill                 # Link-local
✗ file:///etc/passwd                       # file:// 协议
✗ gopher://example.com/skill                # 非 http(s)
被接受的 URL (3 种)
✓ https://github.com/Fu-Jie/openwebui-extensions/raw/main/SKILL.md
✓ https://raw.githubusercontent.com/user/repo/main/skill.md
✓ https://example.com/public/skill.zip

防护机制:

  • 检查 hostname 是否在 localhost 变体列表中
  • 使用 ipaddress 库检测私有、回环、链接本地和保留 IP
  • 仅允许 httphttps 协议

2. TAR 提取安全性测试

文件: test_security_fixes.py - test_tar_extraction_safety()

测试 _safe_extract_tar() 方法能否防止路径遍历攻击

被测试的攻击:

TAR 文件包含: ../../etc/passwd
↓
提取时被拦截,日志输出:
  WARNING - Skipping unsafe TAR member: ../../etc/passwd
↓
结果: /etc/passwd 文件 NOT 创建 ✓

防护机制:

# 验证解析后的路径是否在提取目录内
member_path.resolve().relative_to(extract_dir.resolve())
# 如果抛出 ValueError说明有遍历尝试跳过该成员

3. ZIP 提取安全性测试

文件: test_security_fixes.py - test_zip_extraction_safety()

与 TAR 测试相同,但针对 ZIP 文件的路径遍历防护:

ZIP 文件包含: ../../etc/passwd
↓
提取时被拦截
↓
结果: /etc/passwd 文件 NOT 创建 ✓

4. 技能名称冲突检查测试

文件: test_security_fixes.py - test_skill_name_collision()

测试 update_skill() 方法中的名称碰撞检查:

场景 1: 尝试将技能2改名为 "MySkill" (已被技能1占用)
↓
检查逻辑触发,检测到冲突
返回错误: Another skill already has the name "MySkill" ✓

场景 2: 尝试将技能2改名为 "UniqueSkill" (不存在)
↓
检查通过,允许改名 ✓

5. URL 标准化测试

文件: test_security_fixes.py - test_url_normalization()

测试 URL 验证对各种无效格式的处理:

被拒绝的无效 URL:
✗ not-a-url             # 不是有效 URL
✗ ftp://example.com     # 非 http/https 协议
✗ ""                    # 空字符串
✗ "   "                 # 纯空白

如何修改和扩展测试

添加自己的测试用例

编辑 plugins/debug/openwebui-skills-manager/test_security_fixes.py

def test_my_custom_case():
    """我的自定义测试"""
    print("\n" + "="*60)
    print("测试 X: 我的自定义测试")
    print("="*60)
    
    tester = SecurityTester()
    
    # 你的测试代码
    assert condition, "错误消息"
    
    print("\n✓ 自定义测试通过!")

# 在 main() 中添加
def main():
    # ...
    test_my_custom_case()  # 新增
    # ...

测试特定的 URL

直接在 unsafe_urlssafe_urls 列表中添加:

unsafe_urls = [
    # 现有项
    "http://internal-server.local/api",  # 新增: 本地局域网
]

safe_urls = [
    # 现有项
    "https://api.github.com/repos/Fu-Jie/openwebui-extensions",  # 新增
]

与 OpenWebUI 集成测试

如果需要在完整的 OpenWebUI 环境中测试,可以:

1. 单元测试方式

创建 tests/test_skills_manager.py(需要 OpenWebUI 环境):

import pytest
from plugins.tools.openwebui_skills_manager.openwebui_skills_manager import Tool

@pytest.fixture
def skills_tool():
    return Tool()

def test_safe_url_in_tool(skills_tool):
    """在实际工具对象中测试"""
    assert not skills_tool._is_safe_url("http://localhost/skill")
    assert skills_tool._is_safe_url("https://github.com/user/repo")

运行方式:

pytest tests/test_skills_manager.py -v

2. 集成测试方式

在 OpenWebUI 中手动测试:

  1. 安装插件:

    OpenWebUI → Admin → Tools → 添加 openwebui-skills-manager 工具
    
  2. 测试 SSRF 防护:

    调用: install_skill(url="http://localhost:8000/skill.md")
    预期: 返回错误 "Unsafe URL: points to internal or reserved destination"
    
  3. 测试名称冲突:

    1. create_skill(name="MySkill", ...)
    2. create_skill(name="AnotherSkill", ...)
    3. update_skill(name="AnotherSkill", new_name="MySkill")
    预期: 返回错误 "Another skill already has the name..."
    
  4. 测试文件提取:

    上传包含 ../../etc/passwd 的恶意 TAR/ZIP
    预期: 提取成功但恶意文件被跳过
    

故障排除

问题: ModuleNotFoundError: No module named 'ipaddress'

解决: ipaddress 是内置模块,无需安装。检查 Python 版本 >= 3.3

python3 --version  # 应该 >= 3.3

问题: 测试卡住

解决: TAR/ZIP 提取涉及文件 I/O可能在某些系统上较慢。检查磁盘空间

df -h  # 检查是否有足够空间

问题: 权限错误

解决: 确认脚本可执行:

chmod +x plugins/debug/openwebui-skills-manager/test_security_fixes.py

修复验证清单

  • SSRF 防护 - 阻止内部 IP 请求
  • TAR 提取安全 - 防止路径遍历
  • ZIP 提取安全 - 防止路径遍历
  • 名称冲突检查 - 防止重名技能
  • 注释更正 - 移除误导性文档
  • 版本更新 - 0.2.2

相关链接