第一步
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""全局配置:pydantic-settings,全部来自环境变量 / .env。
|
||||
|
||||
规则(docs/technical-review.md §1.3):
|
||||
- 密钥不得硬编码;SECRET_KEY 缺失或仍为模板值时,生产环境拒绝启动。
|
||||
- DATABASE_URL 可切换 PostgreSQL(扩展接口 1)。
|
||||
"""
|
||||
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
_TEMPLATE_MARKERS = ("change-me",)
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
|
||||
|
||||
# --- 基础 ---
|
||||
environment: str = "local" # local / production
|
||||
secret_key: str = Field(min_length=16)
|
||||
|
||||
# --- 数据库 ---
|
||||
database_url: str = "sqlite:///./data/app.db"
|
||||
|
||||
# --- 文件存储 ---
|
||||
storage_root: str = "./data"
|
||||
|
||||
# --- 套餐 ---
|
||||
default_storage_quota: int = 104_857_600 # 100 MB
|
||||
default_max_file_size: int = 20_971_520 # 20 MB
|
||||
|
||||
# --- 限流 ---
|
||||
rate_limit_per_token_per_min: int = 60
|
||||
rate_limit_per_ip_per_min: int = 30
|
||||
|
||||
# --- CORS ---
|
||||
frontend_origin: str = "http://localhost:5173"
|
||||
|
||||
@property
|
||||
def is_production(self) -> bool:
|
||||
return self.environment == "production"
|
||||
|
||||
@property
|
||||
def storage_root_path(self) -> Path:
|
||||
return Path(self.storage_root).resolve()
|
||||
|
||||
def validate_secrets(self) -> None:
|
||||
"""生产环境禁止携带模板密钥启动。"""
|
||||
if not self.is_production:
|
||||
return
|
||||
for field_name in ("secret_key",):
|
||||
value = getattr(self, field_name).lower()
|
||||
if any(marker in value for marker in _TEMPLATE_MARKERS):
|
||||
raise RuntimeError(
|
||||
f"配置错误:{field_name} 仍为模板值,生产环境禁止启动。"
|
||||
"请运行: python -c \"import secrets; print(secrets.token_urlsafe(48))\""
|
||||
)
|
||||
|
||||
|
||||
@lru_cache
|
||||
def get_settings() -> Settings:
|
||||
s = Settings() # type: ignore[call-arg]
|
||||
s.validate_secrets()
|
||||
return s
|
||||
Reference in New Issue
Block a user