Add hub AI config tab with sync to instances and deploy secret bootstrap.

Wire bootstrap_deploy_secrets into setup_env.sh (one-time HUB_BRIDGE_TOKEN, FLASK_SECRET_KEY, HUB_SESSION_SECRET). Remove AI section from instance env UI; hub saves OPENAI settings to all four .env files. SSO unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-08 22:50:58 +08:00
parent 886f7740f2
commit 823aeda42a
17 changed files with 653 additions and 54 deletions
+19 -8
View File
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
"""首次部署:自动生成中控通信密钥、登录会话密钥,并写入初始登录账号。
- HUB_BRIDGE_TOKEN:中控 + 三实例(相同)
- HUB_BRIDGE_TOKEN:中控 + 三实例(相同,仅空/占位时写入,不覆盖已有
- FLASK_SECRET_KEY:三实例(相同)
- APP_USERNAME=admin、APP_PASSWORD=admin123:仅当 .env 中尚未设置密码时写入
- HUB_SESSION_SECRET:仅中控
- APP_USERNAME=admin、APP_PASSWORD=admin123:实例(仅空时)
- HUB_USERNAME=admin、HUB_PASSWORD=admin123:中控(仅空时)
已有非空且非占位符的值不会被覆盖。
已有非空且非占位符的值不会被覆盖(长期密钥一次生成、不轮换)
"""
from __future__ import annotations
@@ -31,6 +33,7 @@ FLASK_PLACEHOLDERS = frozenset(
{"", "CHANGE_TO_LONG_RANDOM_SECRET", "crypto_monitor_2026_secret_key"}
)
HUB_PLACEHOLDERS = frozenset({"", "your-long-random-token"})
SESSION_PLACEHOLDERS = frozenset({"", "another-long-random-string", "hub-dev-insecure"})
def _env_path(base: str) -> str:
@@ -49,16 +52,24 @@ def main() -> int:
hub_token = secrets.token_urlsafe(32)
flask_secret = secrets.token_urlsafe(48)
session_secret = secrets.token_urlsafe(48)
planned: list[tuple[str, dict[str, str]]] = []
# 中控 HUB_BRIDGE_TOKEN
hub_env = _env_path(HUB_DIR)
if os.path.isfile(hub_env):
hub_lines = read_env_lines(hub_env)
hub_updates: dict[str, str] = {}
if _should_set(env_get(hub_lines, "HUB_BRIDGE_TOKEN"), HUB_PLACEHOLDERS):
planned.append((hub_env, {"HUB_BRIDGE_TOKEN": hub_token}))
hub_updates["HUB_BRIDGE_TOKEN"] = hub_token
if _should_set(env_get(hub_lines, "HUB_SESSION_SECRET"), SESSION_PLACEHOLDERS):
hub_updates["HUB_SESSION_SECRET"] = session_secret
if not (env_get(hub_lines, "HUB_USERNAME") or "").strip():
hub_updates["HUB_USERNAME"] = "admin"
if _should_set(env_get(hub_lines, "HUB_PASSWORD"), frozenset({""})):
hub_updates["HUB_PASSWORD"] = "admin123"
if hub_updates:
planned.append((hub_env, hub_updates))
# 三实例
for _name, inst_dir in INSTANCE_DIRS:
path = _env_path(inst_dir)
if not os.path.isfile(path):
@@ -90,8 +101,8 @@ def main() -> int:
print(f"已写入 {rel}: {keys}")
if not args.dry_run:
print("完成。初始登录:admin / admin123(若本次写入了 APP_PASSWORD)。")
print("请 pm2 restart 中控与三实例使 FLASK_SECRET_KEY / HUB_BRIDGE_TOKEN 生效。")
print("完成。初始登录:admin / admin123(若本次写入了密码项)。")
print("请 pm2 restart 中控与三实例使密钥生效。")
return 0