fix: P0-2 OSS 凭证启动验证 + 诊断日志
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 16s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1630h4m17s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1630h4m19s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1630h4m19s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1630h4m19s
CI/CD Pipeline / Build Production Runtime Images (pull_request) Failing after 1630h4m25s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Failing after 1630h4m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 16s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1630h4m17s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1630h4m19s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1630h4m19s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1630h4m19s
CI/CD Pipeline / Build Production Runtime Images (pull_request) Failing after 1630h4m25s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Failing after 1630h4m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
- config.py: 非开发环境 OSS_ACCESS_KEY_ID/SECRET 为空时启动失败(fail-fast) - storage.py: 新增 diagnose() 方法,启动时输出 OSS 配置状态 - 新增 7 个单元测试覆盖凭证验证和诊断逻辑 注意:staging 实际已有 OSS 凭证配置,预签名 URL 可正常生成。 真正问题是 sign_url 返回 HTTP 而非 HTTPS,后续修复。
This commit is contained in:
@@ -79,6 +79,27 @@ class Settings(BaseSettings):
|
||||
OSS_ACCESS_KEY_ID: str = ""
|
||||
OSS_ACCESS_KEY_SECRET: str = ""
|
||||
OSS_BUCKET_NAME: str = "xiaoxia-autocut"
|
||||
|
||||
@field_validator("OSS_ACCESS_KEY_ID", mode="before")
|
||||
@classmethod
|
||||
def validate_oss_access_key_id(cls, v):
|
||||
if (v is None or v == "") and os.getenv("APP_ENV", "development") != "development":
|
||||
raise ValueError(
|
||||
"OSS_ACCESS_KEY_ID must be set via environment variable in non-development environments. "
|
||||
"Check the server .env file (e.g. /var/lib/xiaoxia-saas-staging/.env)."
|
||||
)
|
||||
return v or ""
|
||||
|
||||
@field_validator("OSS_ACCESS_KEY_SECRET", mode="before")
|
||||
@classmethod
|
||||
def validate_oss_access_key_secret(cls, v):
|
||||
if (v is None or v == "") and os.getenv("APP_ENV", "development") != "development":
|
||||
raise ValueError(
|
||||
"OSS_ACCESS_KEY_SECRET must be set via environment variable in non-development environments. "
|
||||
"Check the server .env file (e.g. /var/lib/xiaoxia-saas-staging/.env)."
|
||||
)
|
||||
return v or ""
|
||||
|
||||
OSS_DIRECT_UPLOAD_MAX_MB: int = Field(
|
||||
default=2000,
|
||||
validation_alias=AliasChoices("OSS_DIRECT_UPLOAD_MAX_MB", "MAX_UPLOAD_SIZE_MB"),
|
||||
|
||||
@@ -64,6 +64,26 @@ class OSSStorageService:
|
||||
self.access_key_secret = settings.OSS_ACCESS_KEY_SECRET
|
||||
self.endpoint = settings.OSS_ENDPOINT
|
||||
|
||||
def diagnose(self) -> None:
|
||||
"""启动诊断:输出 OSS 配置状态,帮助排查预签名 URL 问题。"""
|
||||
key_id_display = (
|
||||
f"{self.access_key_id[:4]}...{self.access_key_id[-4:]}" if len(self.access_key_id) > 8 else "(empty)"
|
||||
)
|
||||
logger.info(
|
||||
"[OSS诊断] endpoint=%s bucket_name=%s access_key_id=%s",
|
||||
self.endpoint,
|
||||
self.bucket_name,
|
||||
key_id_display,
|
||||
)
|
||||
if self.bucket is None:
|
||||
logger.error(
|
||||
"[OSS诊断] ❌ bucket=None — 预签名URL不可用!"
|
||||
"原因: OSS_ACCESS_KEY_ID/OSS_ACCESS_KEY_SECRET 未配置或 oss2 未安装。"
|
||||
"请检查服务器 .env 文件(如 /var/lib/xiaoxia-saas-staging/.env)"
|
||||
)
|
||||
else:
|
||||
logger.info("[OSS诊断] ✅ bucket 已配置,预签名URL可用")
|
||||
|
||||
def _is_local_generated_url(self, storage_key_or_url: str) -> bool:
|
||||
parsed = urlparse(storage_key_or_url)
|
||||
path = parsed.path if parsed.scheme else storage_key_or_url
|
||||
@@ -167,8 +187,7 @@ class OSSStorageService:
|
||||
if self._is_local_generated_url(storage_key_or_url):
|
||||
return storage_key_or_url
|
||||
logger.warning(
|
||||
"get_download_url: OSS bucket not configured, returning raw URL. "
|
||||
"storage_key_or_url=%s",
|
||||
"get_download_url: OSS bucket not configured, returning raw URL. " "storage_key_or_url=%s",
|
||||
storage_key_or_url[:200],
|
||||
)
|
||||
return self.get_url(self._normalize_storage_key(storage_key_or_url))
|
||||
@@ -184,8 +203,7 @@ class OSSStorageService:
|
||||
return signed
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"get_download_url: sign_url failed, falling back to raw URL. "
|
||||
"storage_key=%s",
|
||||
"get_download_url: sign_url failed, falling back to raw URL. " "storage_key=%s",
|
||||
storage_key[:200],
|
||||
)
|
||||
return self.get_url(storage_key)
|
||||
@@ -256,4 +274,5 @@ def get_storage_service() -> OSSStorageService:
|
||||
global _storage_service
|
||||
if _storage_service is None:
|
||||
_storage_service = OSSStorageService()
|
||||
_storage_service.diagnose()
|
||||
return _storage_service
|
||||
|
||||
Reference in New Issue
Block a user