Allow CPA_AUTO_IMPORT_REMOTE from .env

Enable remote CPA import via env flag with priority over config.json, and load project .env when resolving remote settings.
This commit is contained in:
chaos committed 2026-07-11 18:06:17 +08:00
1 parent 0d8265de03
commit 06044551c7
4 files changed
+66 -9

No files matched your search

+6 -4
View File
@@ -29,7 +29,9 @@ GROK2API_APP_KEY=
# ===== CPA 远程自动导入(Management API)===== # ===== CPA 远程自动导入(Management API)=====
# 写出 xai-*.json 后 POST 到 {CPA_REMOTE_BASE}/v0/management/auth-files # 写出 xai-*.json 后 POST 到 {CPA_REMOTE_BASE}/v0/management/auth-files
# 需同时在 config.json 设 cpa_auto_import_remote=true,或仅用环境变量时也要打开该开关 # 1/true/yes/on 开启;0/false/no/off 关闭(优先于 config.json 的 cpa_auto_import_remote)
# CPA_REMOTE_BASE=http://127.0.0.1:8317 CPA_AUTO_IMPORT_REMOTE=0
# CPA_REMOTE_PASSWORD= # 地址只填根,如 http://127.0.0.1:8317
# 兼容别名:CPA_MANAGEMENT_PASSWORD / MANAGEMENT_PASSWORD CPA_REMOTE_BASE=
CPA_REMOTE_PASSWORD=
# 兼容别名:CPA_MANAGEMENT_PASSWORD / MANAGEMENT_PASSWORD / CPA_AUTO_IMPORT
+5 -2
View File
@@ -130,7 +130,8 @@ cp config.example.json config.json
| `GROK2API_APP_KEY` | 远端 grok2api Admin | | `GROK2API_APP_KEY` | 远端 grok2api Admin |
| `API_REVERSE_TOOLS` | 可选:外部 `cpa_xai` 父目录 | | `API_REVERSE_TOOLS` | 可选:外部 `cpa_xai` 父目录 |
| `CPA_EXPORT` | `auto_register` 是否导出 CPA(`0/false` 关) | | `CPA_EXPORT` | `auto_register` 是否导出 CPA(`0/false` 关) |
| `CPA_REMOTE_BASE` | 远程 CPA 根地址(配合 `cpa_auto_import_remote`) | | `CPA_AUTO_IMPORT_REMOTE` | 是否自动导入远程 CPA(`1/true` 开,`0/false` 关;优先于 config) |
| `CPA_REMOTE_BASE` | 远程 CPA 根地址 |
| `CPA_REMOTE_PASSWORD` | 远程 CPA 管理密码 | | `CPA_REMOTE_PASSWORD` | 远程 CPA 管理密码 |
| `https_proxy` / `http_proxy` | 代理回退 | | `https_proxy` / `http_proxy` | 代理回退 |
@@ -243,15 +244,17 @@ cpa_proxy > proxy > 环境变量 https_proxy/http_proxy
} }
``` ```
或写在 `.env`: 或全部写在 `.env`(开关也可用环境变量):
```bash ```bash
CPA_AUTO_IMPORT_REMOTE=1
CPA_REMOTE_BASE=http://127.0.0.1:8317 CPA_REMOTE_BASE=http://127.0.0.1:8317
CPA_REMOTE_PASSWORD=你的管理密码 CPA_REMOTE_PASSWORD=你的管理密码
``` ```
说明: 说明:
- `CPA_AUTO_IMPORT_REMOTE=1/true/yes` 开启,`0/false/no` 关闭;**env 优先于** `config.json`
- **只填根地址**(到端口即可);程序会请求 - **只填根地址**(到端口即可);程序会请求
`POST {base}/v0/management/auth-files?name=xai-email.json` `POST {base}/v0/management/auth-files?name=xai-email.json`
- 认证头:`Authorization: Bearer <管理密码>`(同时附带 `X-Management-Key`) - 认证头:`Authorization: Bearer <管理密码>`(同时附带 `X-Management-Key`)
+1 -1
View File
@@ -131,7 +131,7 @@
"cpa_copy_to_hotload": false, "cpa_copy_to_hotload": false,
"// cpa_hotload_dir": "CPA 容器/进程挂载的 auth-dir(copy_to_hotload=true 时生效)", "// cpa_hotload_dir": "CPA 容器/进程挂载的 auth-dir(copy_to_hotload=true 时生效)",
"cpa_hotload_dir": "", "cpa_hotload_dir": "",
"// cpa_auto_import_remote": "写出 xai-*.json 后是否自动 POST 到 CPA Management API 导入", "// cpa_auto_import_remote": "写出 xai-*.json 后是否自动 POST 到 CPA Management API 导入。也可在 .env 用 CPA_AUTO_IMPORT_REMOTE=1/0(env 优先)",
"cpa_auto_import_remote": false, "cpa_auto_import_remote": false,
"// cpa_remote_base": "CPA 根地址,只填到端口即可,如 http://127.0.0.1:8317(程序自动拼 /v0/management/auth-files)", "// cpa_remote_base": "CPA 根地址,只填到端口即可,如 http://127.0.0.1:8317(程序自动拼 /v0/management/auth-files)",
"cpa_remote_base": "", "cpa_remote_base": "",
+54 -2
View File
@@ -22,6 +22,31 @@ from urllib.parse import quote, urlparse, urlunparse
_REG_DIR = Path(__file__).resolve().parent _REG_DIR = Path(__file__).resolve().parent
_DEFAULT_OUT = _REG_DIR / "cpa_auths" _DEFAULT_OUT = _REG_DIR / "cpa_auths"
_DEFAULT_CPA = Path("") # empty = do not assume a machine-local CPA path _DEFAULT_CPA = Path("") # empty = do not assume a machine-local CPA path
_DOTENV_LOADED = False
def _load_dotenv_once() -> None:
"""Load project .env into os.environ once (does not override existing env)."""
global _DOTENV_LOADED
if _DOTENV_LOADED:
return
_DOTENV_LOADED = True
env_path = _REG_DIR / ".env"
if not env_path.is_file():
return
try:
for raw in env_path.read_text(encoding="utf-8").splitlines():
line = raw.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, _, val = line.partition("=")
key = key.strip()
val = val.strip().strip('"').strip("'")
if key and key not in os.environ:
os.environ[key] = val
except Exception:
pass
def _ensure_cpa_xai_on_path(tools_dir: str | Path | None = None) -> Path: def _ensure_cpa_xai_on_path(tools_dir: str | Path | None = None) -> Path:
@@ -90,10 +115,37 @@ def _normalize_cpa_remote_base(base: str) -> str:
return urlunparse((parsed.scheme, parsed.netloc, "", "", "", "")).rstrip("/") return urlunparse((parsed.scheme, parsed.netloc, "", "", "", "")).rstrip("/")
def _env_flag(name: str) -> bool | None:
"""Parse env truthy/falsey flag. None if unset/empty."""
raw = (os.environ.get(name) or "").strip().lower()
if not raw:
return None
if raw in ("1", "true", "yes", "on", "y"):
return True
if raw in ("0", "false", "no", "off", "n"):
return False
return None
def resolve_cpa_remote_settings(cfg: dict | None = None) -> dict[str, Any]: def resolve_cpa_remote_settings(cfg: dict | None = None) -> dict[str, Any]:
"""Resolve remote CPA import settings from config + env.""" """Resolve remote CPA import settings from config + env.
Enable flag priority:
1) env CPA_AUTO_IMPORT_REMOTE / CPA_AUTO_IMPORT (if set)
2) config cpa_auto_import_remote
3) default false
Base/password: config first, then env fallbacks.
"""
_load_dotenv_once()
cfg = cfg or {} cfg = cfg or {}
enabled = bool(cfg.get("cpa_auto_import_remote", False)) env_enabled = _env_flag("CPA_AUTO_IMPORT_REMOTE")
if env_enabled is None:
env_enabled = _env_flag("CPA_AUTO_IMPORT")
if env_enabled is not None:
enabled = env_enabled
else:
enabled = bool(cfg.get("cpa_auto_import_remote", False))
base = ( base = (
(cfg.get("cpa_remote_base") or "").strip() (cfg.get("cpa_remote_base") or "").strip()
or (os.environ.get("CPA_REMOTE_BASE") or "").strip() or (os.environ.get("CPA_REMOTE_BASE") or "").strip()