feat: 强化打包配置与服务安全

This commit is contained in:
shen
2026-07-18 13:30:56 +08:00
parent d1f070b251
commit a48909f3bc
26 changed files with 779 additions and 203 deletions
+38 -4
View File
@@ -47,10 +47,11 @@ SKINS_DIR = DATA_DIR / "skins"
# 打包基础目录
BUILD_BASE_DIR = _resolve_server_path(os.getenv("BUILD_BASE_DIR", str(SERVER_ROOT / "build")))
# Git 分支源码目录
# GIT_SOURCE_BASE: 分支源码的根目录,每个分支一个子目录
# GIT_REMOTE_URL: 远程仓库地址,分支目录不存在时自动 clone
# Git 源码目录
# 配置 GIT_REMOTE_URL 时,所有分支共用 GIT_SOURCE_DIR;构建前会串行切换分支并复制快照。
# 未配置远程仓库时,继续兼容 GIT_SOURCE_BASE/<branch> 的人工维护目录。
GIT_SOURCE_BASE = _resolve_server_path(os.getenv("GIT_SOURCE_BASE", str(SERVER_ROOT / "ReadoorBranches")))
GIT_SOURCE_DIR = _resolve_server_path(os.getenv("GIT_SOURCE_DIR", str(GIT_SOURCE_BASE / "workspace")))
GIT_REMOTE_URL = os.getenv("GIT_REMOTE_URL", "")
GIT_USERNAME = os.getenv("GIT_USERNAME", "")
GIT_PASSWORD = os.getenv("GIT_PASSWORD", "")
@@ -89,10 +90,15 @@ def mask_git_remote_url(url: str) -> str:
def get_source_dir(branch: str) -> Path:
"""获取指定分支的源码目录"""
"""获取人工维护模式下指定分支的源码目录"""
return GIT_SOURCE_BASE / branch
def get_shared_source_dir() -> Path:
"""获取配置远程仓库时使用的唯一共享源码工作目录。"""
return GIT_SOURCE_DIR
# 需要拷贝的目录和文件
COPY_ITEMS = [
"readoor",
@@ -108,6 +114,14 @@ COPY_ITEMS = [
# 服务端口
BACKEND_PORT = int(os.getenv("BACKEND_PORT", "8000"))
# 公网部署安全配置。开发环境保持低门槛,生产环境会在启动时强制校验关键项。
APP_ENV = os.getenv("APP_ENV", "development").lower()
CORS_ALLOWED_ORIGINS = [origin.strip() for origin in os.getenv("CORS_ALLOWED_ORIGINS", "").split(",") if origin.strip()]
TRUSTED_HOSTS = [host.strip() for host in os.getenv("TRUSTED_HOSTS", "localhost,127.0.0.1,testserver").split(",") if host.strip()]
LOGIN_RATE_LIMIT_MAX_ATTEMPTS = int(os.getenv("LOGIN_RATE_LIMIT_MAX_ATTEMPTS", "5"))
LOGIN_RATE_LIMIT_WINDOW_SECONDS = int(os.getenv("LOGIN_RATE_LIMIT_WINDOW_SECONDS", "300"))
LOGIN_RATE_LIMIT_LOCKOUT_SECONDS = int(os.getenv("LOGIN_RATE_LIMIT_LOCKOUT_SECONDS", "900"))
# 数据库路径。测试可通过 DATABASE_URL 注入临时 SQLite,避免影响运行库。
DATABASE_URL = os.getenv("DATABASE_URL", f"sqlite:///{Path(__file__).parent / 'build_server.db'}")
@@ -131,3 +145,23 @@ ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "admin123")
JWT_SECRET = os.getenv("JWT_SECRET", "ios-build-server-secret-key-change-in-production")
JWT_ALGORITHM = "HS256"
JWT_EXPIRE_HOURS = 24
def validate_production_security() -> None:
"""阻止带默认凭据或无访问边界的生产服务启动。"""
if APP_ENV != "production":
return
errors = []
if (JWT_SECRET == "ios-build-server-secret-key-change-in-production"
or JWT_SECRET.startswith("replace-") or len(JWT_SECRET) < 32):
errors.append("JWT_SECRET 必须设置为至少 32 位的随机字符串")
if (ADMIN_PASSWORD == "admin123" or ADMIN_PASSWORD.startswith("change-")
or len(ADMIN_PASSWORD) < 12):
errors.append("ADMIN_PASSWORD 必须设置为至少 12 位的强密码")
if not CORS_ALLOWED_ORIGINS or "*" in CORS_ALLOWED_ORIGINS:
errors.append("CORS_ALLOWED_ORIGINS 必须设置为实际 HTTPS 前端域名,且不能为 *")
if not os.getenv("TRUSTED_HOSTS") or "*" in TRUSTED_HOSTS:
errors.append("TRUSTED_HOSTS 必须设置为实际服务域名")
if errors:
raise RuntimeError("生产环境安全配置不完整: " + "; ".join(errors))