fix: P0-2 OSS 凭证启动验证 + 诊断日志 #209

Merged
xiaoxia merged 2 commits from fix/p02-oss-credential-validation into develop 2026-07-10 18:15:42 +08:00
Owner

改动

1. config.py — OSS 凭证启动验证(fail-fast)

  • 新增 @field_validatorOSS_ACCESS_KEY_IDOSS_ACCESS_KEY_SECRET
  • 非开发环境(APP_ENV != development)凭证为空时,启动直接报错,防止静默降级
  • 开发环境仍允许空凭证(本地调试友好)

2. storage.py — 启动诊断

  • 新增 OSSStorageService.diagnose() 方法
  • get_storage_service() 首次创建实例时自动调用
  • 输出 endpoint、bucket_name、access_key_id(脱敏)
  • bucket=None 时输出 ERROR 级别告警,指引检查 .env 文件

3. 单元测试

  • 7 个测试覆盖:凭证验证(staging 拒绝空凭证 / dev 允许 / 有效凭证通过)+ diagnose 日志输出

注意

⚠️ 此 PR 不是 P0-2 的最终修复。 staging 实际已有 OSS 凭证配置,预签名 URL 可正常生成。

真正根因是 oss2.Bucket.sign_url() 返回 HTTP URL 而非 HTTPS,后续 PR 修复。

本 PR 是防御性改进:防止未来部署时漏配 OSS 凭证导致预签名 URL 静默降级为裸链接。

## 改动 ### 1. config.py — OSS 凭证启动验证(fail-fast) - 新增 `@field_validator` 对 `OSS_ACCESS_KEY_ID` 和 `OSS_ACCESS_KEY_SECRET` - 非开发环境(`APP_ENV != development`)凭证为空时,启动直接报错,防止静默降级 - 开发环境仍允许空凭证(本地调试友好) ### 2. storage.py — 启动诊断 - 新增 `OSSStorageService.diagnose()` 方法 - `get_storage_service()` 首次创建实例时自动调用 - 输出 endpoint、bucket_name、access_key_id(脱敏) - bucket=None 时输出 ERROR 级别告警,指引检查 .env 文件 ### 3. 单元测试 - 7 个测试覆盖:凭证验证(staging 拒绝空凭证 / dev 允许 / 有效凭证通过)+ diagnose 日志输出 ## 注意 ⚠️ **此 PR 不是 P0-2 的最终修复。** staging 实际已有 OSS 凭证配置,预签名 URL 可正常生成。 真正根因是 `oss2.Bucket.sign_url()` 返回 **HTTP** URL 而非 HTTPS,后续 PR 修复。 本 PR 是防御性改进:防止未来部署时漏配 OSS 凭证导致预签名 URL 静默降级为裸链接。
xiaoxia added 1 commit 2026-07-10 17:24:23 +08:00
fix: P0-2 OSS 凭证启动验证 + 诊断日志
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 16s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m38s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
6efac8de4b
- config.py: 非开发环境 OSS_ACCESS_KEY_ID/SECRET 为空时启动失败(fail-fast)
- storage.py: 新增 diagnose() 方法,启动时输出 OSS 配置状态
- 新增 7 个单元测试覆盖凭证验证和诊断逻辑

注意:staging 实际已有 OSS 凭证配置,预签名 URL 可正常生成。
真正问题是 sign_url 返回 HTTP 而非 HTTPS,后续修复。
xiaoxia added 1 commit 2026-07-10 17:28:02 +08:00
fix: P0-2 sign_url 返回 HTTPS URL(endpoint 加 https:// 前缀)
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 10s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m20s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
6feb541127
根因:oss2.Bucket 的 endpoint 参数不带 scheme 时,sign_url() 默认生成
HTTP URL(如 http://bucket.oss-cn-hangzhou.aliyuncs.com/...),
前端/浏览器视为不安全请求拒绝加载。

修复:初始化 oss2.Bucket 前检查 endpoint 是否带 http(s):// 前缀,
不带则自动补 https://,确保 sign_url 输出 HTTPS URL。

新增 2 个测试验证 endpoint scheme 处理逻辑。
Author
Owner

PR #209 代码审计通过(P0-2 HTTPS 根因修复)

评级:0P0 / 0P1 / 0P2 / 3P3


🔧 核心修复验证(P0-2 根因)

endpoint 补 https:// 前缀

  • 逻辑:if not startswith(("http://", "https://")): bucket_endpoint = f"https://{bucket_endpoint}"
  • 根因准确:oss2.Bucket 的 endpoint 无 scheme 时,sign_url() 默认生成 HTTP URL,前端拒绝加载混合内容
  • 修复方式正确:在 Bucket 初始化前统一补全 https:// 前缀
  • 已有 scheme 时不会重复添加

🛡️ 凭证验证器(防呆设计)

非开发环境强制 OSS 凭证

  • field_validator 校验 OSS_ACCESS_KEY_ID / OSS_ACCESS_KEY_SECRET
  • staging/production 为空时启动报错,避免部署后才发现问题
  • 错误信息清晰,给出 .env 文件路径提示
  • development 环境允许空凭证,不影响本地开发

📋 启动诊断日志

diagnose() 方法

  • 首次调用 get_storage_service() 时自动执行
  • access_key_id 脱敏显示(前4后4),无敏感信息泄露
  • bucket=None 时输出 ERROR 日志 + 排查指引
  • bucket 正常时输出 INFO 确认日志

🧪 测试覆盖(9/9 通过)

测试类 用例数 覆盖点
TestOSSCredentialValidation 5 凭证验证器各场景
TestOSSDiagnose 2 bucket=None / bucket正常
TestOSSHTTPSEndpoint 2 无scheme补https / 已有https不重复
  • 相关回归测试 test_generation_presigned_url.py(2/2)也全部通过

💡 P3 建议(非阻塞,后续优化)

P3-1:大小写兼容

  • startswith(("http://", "https://")) 是大小写敏感的
  • 如果配置了 HTTP://xxx 这类异常值,会被重复加 https://
  • 建议:bucket_endpoint.lower().startswith(...) 或先统一转小写

P3-2:http:// 场景缺测试

  • 只有 https:// 已有 scheme 的测试,缺少 http:// 场景
  • 虽然不推荐 http,但逻辑上应该验证不会重复添加

P3-3:sign_url 返回值端到端验证

  • 当前只验证了传给 Bucket 的 endpoint 参数
  • 可以 mock sign_url 返回 "http://...",验证经过包装后输出 "https://..."
    (不过 oss2 库的行为是确定性的,endpoint 是 https 就会生成 https URL,所以这个建议优先级低)

结论

P0-2 根因修复正确,代码质量良好,测试覆盖充分,可以合并。

建议与 P0-3 fps/setpts 顺序修复一起合并部署到 staging,然后跑第五轮端到端验证。

## ✅ PR #209 代码审计通过(P0-2 HTTPS 根因修复) **评级:0P0 / 0P1 / 0P2 / 3P3** --- ### 🔧 核心修复验证(P0-2 根因) **endpoint 补 https:// 前缀** ✅ - 逻辑:`if not startswith(("http://", "https://")): bucket_endpoint = f"https://{bucket_endpoint}"` - 根因准确:oss2.Bucket 的 endpoint 无 scheme 时,`sign_url()` 默认生成 HTTP URL,前端拒绝加载混合内容 - 修复方式正确:在 Bucket 初始化前统一补全 https:// 前缀 - 已有 scheme 时不会重复添加 --- ### 🛡️ 凭证验证器(防呆设计) **非开发环境强制 OSS 凭证** ✅ - `field_validator` 校验 `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET` - staging/production 为空时启动报错,避免部署后才发现问题 - 错误信息清晰,给出 .env 文件路径提示 - development 环境允许空凭证,不影响本地开发 --- ### 📋 启动诊断日志 **`diagnose()` 方法** ✅ - 首次调用 `get_storage_service()` 时自动执行 - access_key_id 脱敏显示(前4后4),无敏感信息泄露 - bucket=None 时输出 ERROR 日志 + 排查指引 - bucket 正常时输出 INFO 确认日志 --- ### 🧪 测试覆盖(9/9 通过) | 测试类 | 用例数 | 覆盖点 | |--------|--------|--------| | TestOSSCredentialValidation | 5 | 凭证验证器各场景 | | TestOSSDiagnose | 2 | bucket=None / bucket正常 | | TestOSSHTTPSEndpoint | 2 | 无scheme补https / 已有https不重复 | - 相关回归测试 `test_generation_presigned_url.py`(2/2)也全部通过 ✅ --- ### 💡 P3 建议(非阻塞,后续优化) **P3-1:大小写兼容** - `startswith(("http://", "https://"))` 是大小写敏感的 - 如果配置了 `HTTP://xxx` 这类异常值,会被重复加 https:// - 建议:`bucket_endpoint.lower().startswith(...)` 或先统一转小写 **P3-2:http:// 场景缺测试** - 只有 https:// 已有 scheme 的测试,缺少 http:// 场景 - 虽然不推荐 http,但逻辑上应该验证不会重复添加 **P3-3:sign_url 返回值端到端验证** - 当前只验证了传给 Bucket 的 endpoint 参数 - 可以 mock `sign_url` 返回 `"http://..."`,验证经过包装后输出 `"https://..."` (不过 oss2 库的行为是确定性的,endpoint 是 https 就会生成 https URL,所以这个建议优先级低) --- ### ✅ 结论 **P0-2 根因修复正确,代码质量良好,测试覆盖充分,可以合并。** 建议与 P0-3 fps/setpts 顺序修复一起合并部署到 staging,然后跑第五轮端到端验证。
xiaoxia merged commit f5d3482fa9 into develop 2026-07-10 18:15:42 +08:00
Sign in to join this conversation.