fix: P0+P1+P2 安全/并发/健壮性/运维修复 + 模型解耦以支持测试 - #16
Open
lugondev wants to merge 3 commits into
Open
Conversation
安全: - 令牌校验改用 secrets.compare_digest 常量时间比较,避免定时攻击 (app/core/security.py, app/api/v1/health.py) - 不再将令牌/密钥内容写入日志,防止密钥泄露 并发/性能: - 数据库改用 DBUtils 连接池,惰性创建,每次请求借用独立连接, 避免全局单连接在并发下被共享 (app/database/connection.py) - 接口层将阻塞型推理调用放入线程池 (run_in_threadpool), 避免阻塞事件循环 (app/api/v1/voiceprint.py) 可测试性: - 模型改为惰性加载 (pipeline 属性 + 双重检查锁),导入模块不再加载模型; 预热改为显式 warmup(),由应用 lifespan 启动时调用 (VOICEPRINT_SKIP_WARMUP=1 可跳过,便于测试) - 引入依赖注入 get_voiceprint_service,便于测试替身注入 - 新增 pytest 测试套件 (15 用例,覆盖连接层/服务层/令牌校验/接口) 清理: - pydantic v1 Config 迁移到 v2 model_config,Query example -> examples - 新增依赖 DBUtils==3.1.2 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CORS (1.5): - 来源与凭证改由配置决定 (server.cors_origins / cors_allow_credentials) - 新增 build_cors_config 强制修正不安全组合:通配来源 "*" 与 allow_credentials=True 不兼容时自动关闭凭证 (app/application.py) 音频校验 (1.6): - 注册/识别在推理前统一校验音频:最小/最大字节数 + 时长/采样率 (VoiceprintService._audio_bytes_valid),不合法直接拒绝,避免无谓推理与 超大文件的内存/DoS 风险 - 新增配置 voiceprint.max_audio_bytes(默认10MB) 相似度阈值 (1.4): - 默认阈值 0.2 -> 0.5(更保守,降低误接受风险);生产需结合真实数据标定 - voiceprint.yaml 补充 voiceprint 段与 CORS 说明 测试: - 新增 test_cors / test_audio_validation / test_config,共 9 用例 - 全套 24 用例通过(无需真实 MySQL / 模型) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
临时文件: - 新增 AudioProcessor.cleanup_stale_temp_files,清理进程被强杀时遗留的 过期临时文件;在应用启动时调用 生命周期: - 关闭时释放数据库连接池 (db_connection.close()),替代原 __del__ 清理 - 启动时清理残留临时文件 + 预热模型,统一在 lifespan 管理 Docker 模型缓存: - MODELSCOPE_CACHE 指向持久化的 data 卷 (/app/data/modelscope_cache), 模型只需下载一次,容器重建后复用,避免每次重新下载 测试: - 新增 test_audio_cleanup / test_lifecycle,全套 27 用例通过 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述 / Summary
本 PR 修复一组 P0/P1/P2 级安全、并发、健壮性与运维问题,并将模型加载解耦以支持单元测试。改动保持对外 API 行为不变,新增 27 个测试用例(无需真实 MySQL / 模型即可运行)。
This PR fixes P0/P1/P2 security, concurrency, robustness & ops issues and decouples model loading to make the service testable. Public API behavior is unchanged; adds 27 tests that run without a real MySQL or the model.
P0
🔒 安全 / Security
security.py与health.py使用secrets.compare_digest,避免定时攻击。authorization[:20]或完整key,存在密钥泄露风险,现已移除。⚡ 并发 / Concurrency
connection.py改用DBUtils.PooledDB,惰性创建、每次请求借用独立连接,解决全局单连接在并发下被共享的问题。run_in_threadpool调用阻塞型服务方法,避免阻塞 async 事件循环。🧪 可测试性 / Testability
VoiceprintService构造时不再加载模型;pipeline属性首次访问时加载。导入模块不再触发模型下载。warmup()由lifespan启动时调用;VOICEPRINT_SKIP_WARMUP=1可跳过(测试用)。get_voiceprint_service便于测试替身注入。P1
🌐 CORS (1.5)
server.cors_origins/server.cors_allow_credentials)。build_cors_config:检测到通配来源"*"与allow_credentials=True的不安全组合时自动关闭凭证。🎧 音频校验 / Audio validation (1.6)
voiceprint.max_audio_bytes(默认 10MB)。🎚️ 相似度阈值 / Threshold (1.4)
0.2 → 0.5(更保守,降低误接受风险)。生产环境仍应结合真实数据标定(如按 EER 调整)。P2
🧹 残留临时文件 / Stale temp files
AudioProcessor.cleanup_stale_temp_files,清理进程被强杀时遗留的过期临时文件;应用启动时调用。♻️ 生命周期 / Lifecycle
db_connection.close(),替代原__del__清理;启动/关闭统一在lifespan管理。📦 Docker 模型缓存 / Model cache
MODELSCOPE_CACHE指向持久化的data卷(/app/data/modelscope_cache),模型只需下载一次,容器重建后复用,避免每次重新下载。验证 / Verification
依赖 / Dependencies
DBUtils==3.1.2。🤖 Generated with Claude Code