chore: 忽略离线部署包,提交安全加固、数据库初始化与文档
- .gitignore: 忽略 docker/offline 离线部署包(镜像/运行时等大文件) - 安全加固: 新增 compute/api/security.py 及各端安全测试,补充 docs/security-hardening.md - 数据库: 新增完整初始化 SQL 与 docs/database-config.md - 数据转换与评测: 修复类型检查、增强校验并补充测试 - Docker 配置与环境变量更新 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,12 +15,13 @@ from fastapi import FastAPI, File, Form, HTTPException, Query, Request, UploadFi
|
||||
from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
|
||||
|
||||
from compute.agent.process_manager import ProcessManager
|
||||
from compute.api.security import docs_kwargs
|
||||
from compute.engines.llama_factory.adapter import build_command, parse_log_line, prepare_runtime_files
|
||||
from compute.engines.llama_factory.inference import get_inference_session
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI(title="YG Fine-Tune Compute API")
|
||||
app = FastAPI(title="YG Fine-Tune Compute API", **docs_kwargs())
|
||||
jobs: dict[str, dict[str, Any]] = {}
|
||||
route_prefix = os.getenv("MODELTF_ROUTE_PREFIX", "/modelTF").rstrip("/") or "/modelTF"
|
||||
process_manager = ProcessManager(os.getenv("TRAINING_LOG_ROOT", "/opt/yg-ft/logs/training"))
|
||||
@@ -860,10 +861,17 @@ def create_app() -> FastAPI:
|
||||
@app.get(f"{route_prefix}/compute/files/{{file_id}}/download")
|
||||
async def download_file(file_id: str) -> FileResponse:
|
||||
upload_root = Path(os.getenv("YG_FT_DATA_ROOT", "/data/yg-ft")) / "uploads"
|
||||
# file_id 仅允许普通标识符,拒绝 ../、/、\ 等路径穿越字符。
|
||||
if not file_id or not all(character.isalnum() or character in {"_", "-"} for character in file_id):
|
||||
raise HTTPException(status_code=400, detail="invalid file id")
|
||||
matches = list(upload_root.glob(f"{file_id}_*"))
|
||||
if not matches:
|
||||
raise HTTPException(status_code=404, detail="file not found")
|
||||
return FileResponse(matches[0])
|
||||
# 解析符号链接后仍必须位于 upload 根目录内,防止符号链接指向目录外文件。
|
||||
resolved = matches[0].resolve()
|
||||
if not _path_inside(upload_root, resolved):
|
||||
raise HTTPException(status_code=404, detail="file not found")
|
||||
return FileResponse(resolved)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
29
compute/api/security.py
Normal file
29
compute/api/security.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""计算节点 API 安全配置:Swagger / ReDoc / OpenAPI 文档路由开关。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
|
||||
def docs_enabled() -> bool:
|
||||
"""判断 FastAPI 文档路由(/docs、/redoc、/openapi.json)是否开放。
|
||||
|
||||
显式配置 ENABLE_DOCS 时以之为准;否则仅在关闭 token 鉴权
|
||||
(COMPUTE_AUTH_ENABLED=false,本地开发)时开放,生产环境默认关闭,
|
||||
避免未授权访问泄露 API 结构。
|
||||
"""
|
||||
raw = os.getenv("ENABLE_DOCS", "").strip().lower()
|
||||
if raw in {"true", "false"}:
|
||||
return raw == "true"
|
||||
auth_enabled = os.getenv("COMPUTE_AUTH_ENABLED", "true").lower() == "true"
|
||||
return not auth_enabled
|
||||
|
||||
|
||||
def docs_kwargs() -> dict[str, Any]:
|
||||
"""返回传入 FastAPI 的文档路由参数。
|
||||
|
||||
关闭时 FastAPI 不注册 /docs、/redoc、/openapi.json,访问一律返回 404。
|
||||
"""
|
||||
if docs_enabled():
|
||||
return {}
|
||||
return {"docs_url": None, "redoc_url": None, "openapi_url": None}
|
||||
Reference in New Issue
Block a user