fix: improve config module with lazy init and validation

Fixes from code review:

Critical:
- Replace module-level `settings = Settings()` with lazy initialization
  via `get_settings()` function to avoid import failures when env vars
  not set

Important:
- Remove unused `import os` from test_config.py
- Add tests for computed properties (db_path, ssh_keys_dir, repos_dir)
- Add field validation for encrypt_key:
  * Validates base64 format
  * Ensures decoded key is at least 32 bytes for AES-256
- Fix Python 3.8 compatibility (use Optional[Settings] instead of | union)

All tests pass (6/6).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
panw
2026-03-30 15:13:10 +08:00
parent cd6bf9bb13
commit b1060314a2
2 changed files with 96 additions and 4 deletions

View File

@@ -1,6 +1,7 @@
import os
import base64
from pathlib import Path
from typing import Literal
from typing import Optional
from pydantic import field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -24,6 +25,22 @@ class Settings(BaseSettings):
env_file_encoding='utf-8',
)
@field_validator('encrypt_key')
@classmethod
def validate_encrypt_key(cls, v: str) -> str:
"""验证 encrypt_key 是否为有效的 base64 格式且长度足够."""
# Check if valid base64
try:
decoded = base64.b64decode(v, validate=True)
except Exception:
raise ValueError('encrypt_key must be valid base64 string')
# Check length (AES-256 requires 32 bytes)
if len(decoded) < 32:
raise ValueError('encrypt_key must decode to at least 32 bytes for AES-256')
return v
@property
def db_path(self) -> Path:
"""SQLite 数据库路径."""
@@ -40,4 +57,13 @@ class Settings(BaseSettings):
return self.data_dir / 'repos'
settings = Settings()
# Lazy initialization - settings is loaded on first access
_settings: Optional[Settings] = None
def get_settings() -> Settings:
"""获取全局配置实例(懒加载)."""
global _settings
if _settings is None:
_settings = Settings()
return _settings