- backend/db.py:db() 的 DB_PASSWORD 改用 _require_env 强制读取,删除弱默认兜底 - backend/db.py:新增 _convert_placeholders 状态机替换 ? 占位符(跳过字符串字面量),并校验占位符/参数数量,替换原 sql.replace 全局替换脆弱点 - backend/flask_app.py:secret_key 改用 _require_env 强制读取,删除可预测弱默认,防止 session 伪造 - .gitea/workflows/deploy.yml:新增 2.5 步,发布时若线上 shared/.env 缺 DB_PASSWORD/SECRET_KEY 则从 CI secrets 自动补齐(已存在则保留),确保 P0 改动上线后可正常启动
42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
# flask_app.py — 入口:app 创建 + 蓝图注册 + 迁移 + 启动
|
||
# 拆分后仅 ~35 行,所有路由在 routes.py,业务辅助在 helpers.py,基础设施在 db.py
|
||
|
||
import os
|
||
import sys
|
||
|
||
# 确保 backend 目录在 sys.path 中(兼容 gunicorn --preload 模式)
|
||
_backend_dir = os.path.dirname(os.path.abspath(__file__))
|
||
if _backend_dir not in sys.path:
|
||
sys.path.insert(0, _backend_dir)
|
||
|
||
from flask import Flask
|
||
from db import ROOT # 触发 load_dotenv + 建目录
|
||
from routes import bp
|
||
from migrations import run_migrations
|
||
|
||
app = Flask(
|
||
__name__,
|
||
template_folder=str(ROOT / "templates"),
|
||
static_folder=str(ROOT / "static"),
|
||
)
|
||
# secret_key 必须从环境变量注入,禁止硬编码兜底——否则 session 可被伪造。
|
||
_secret_key = os.environ.get("SECRET_KEY")
|
||
if not _secret_key:
|
||
raise RuntimeError(
|
||
"缺少必需的环境变量 SECRET_KEY,请在 .env 中配置(建议: "
|
||
"python3 -c 'import secrets;print(secrets.token_hex(32))')"
|
||
)
|
||
app.secret_key = _secret_key
|
||
app.config["TEMPLATES_AUTO_RELOAD"] = True
|
||
app.register_blueprint(bp)
|
||
|
||
# 模块级执行迁移(保留 gunicorn --preload 行为:导入即触发)
|
||
run_migrations()
|
||
|
||
if __name__ == "__main__":
|
||
app.run(
|
||
host="127.0.0.1",
|
||
port=5177,
|
||
debug=os.environ.get("FLASK_DEBUG", "false").lower() in ("true", "1", "yes"),
|
||
)
|