feat(chv-guest): Gitea 同步变量经 seed 进 guest-env(执行器集成)

- 新增 cloud/chv/gitea_sync.py:6 键白名单,三源合并
  (宿主 CHV_GITEA_* < 任务 gitea_sync < extra_env),
  必填 4 键缺失即 fail-closed,空即不同步
- ssh_transport:GITEA_TOKEN 进密钥集(argv 拒绝),其余
  5 键进 guest-env 集(split_guest_env)
- hostkeys.write_seed:guest_env 与 secret_env 合并写同一
  条目,仍无 runcmd、0600
- config:_gitea_fragment 产 gitea_sync_env(函数内 import,
  叶子模块顶层只许标准库)
- executor.wake_vm:起 VMM 前合并+校验(gitea_sync_incomplete),
  guest-env 随 seed 投递;provision_host_key 透传 guest_env
- worker:_run_attempt 仅对 CHV 执行器把同步变量并进 gateway_env
- 测试:cloud/tests/test_chv_gitea_sync.py 20 项
- 边界:tasks 表无 JSON 列,DB 往返丢任务 gitea_sync;
  生产主来源是宿主 CHV_GITEA_* 环境变量
This commit is contained in:
host committed 2026-11-06 16:55:32 +00:00
1 parent 67ca0b86cd
commit e7f699c62b
7 files changed
+785 -37

No files matched your search

+31 -1
View File
@@ -44,12 +44,25 @@ StrictHostKeyChecking=no + UserKnownHostsFile=/dev/null):
import os
import shlex
from cloud.chv.gitea_sync import (
GITEA_SYNC_PLAIN_KEYS,
GITEA_SYNC_SECRET_KEYS,
)
# CHV 密钥类环境变量名:值绝不进 ssh argv。Docker 线是
# “-e 只传名、值由 CLI 子进程环境提供”(值仍在宿主进程
# 环境里,/proc/<pid>/environ 对同用户可见);CHV 线是
# “值只进 seed 盘客内文件”(宿主进程表与宿主进程环境里
# 都没有值),比 Docker 线更严——差异见执行器文档。
_CHV_SECRET_ENV_NAMES = frozenset({"SUB2API_API_KEY"})
_CHV_SECRET_ENV_NAMES = frozenset({"SUB2API_API_KEY"}) \
| GITEA_SYNC_SECRET_KEYS
# CHV guest-env 类非密钥变量名:值可进 SSH env 前缀(按定义
# 不是密钥),但 chv-sync boot 在 cloud-init 时运行、SSH 之
# 前,只能读 seed 投递的 /etc/chv/guest-env,所以这些键也
# 必须随 seed 写进 guest-env(见 split_guest_env 与执行器
# wake_vm),只走 SSH 前缀是不够的。
_CHV_GUEST_ENV_NAMES = frozenset(GITEA_SYNC_PLAIN_KEYS)
def split_secret_env(extra_env: dict | None) -> tuple[dict, dict]:
@@ -63,6 +76,23 @@ def split_secret_env(extra_env: dict | None) -> tuple[dict, dict]:
return secrets, plain
def split_guest_env(extra_env: dict | None) -> tuple[dict, dict]:
"""把 extra_env 拆成(须写进 seed guest-env 的子集,
非密钥子集)。
guest-env 子集 = 密钥子集 + _CHV_GUEST_ENV_NAMES 命中的
非密钥同步变量(GITEA_URL 等 boot 时就要用的键);第二
个返回仍是全部非密钥子集(含 guest-env 命中键——它们
任务期也要经 SSH env 前缀进客机环境,seed 只解决
boot 时可见性,不替代任务期前缀)。"""
secrets, plain = split_secret_env(extra_env)
guest_env = dict(secrets)
for key, value in plain.items():
if key in _CHV_GUEST_ENV_NAMES:
guest_env[key] = value
return guest_env, plain
def remote_command(inner_cmd: list, egress_proxy: str | None = None,
extra_env: dict | None = None,
guest_env_file: str | None = None) -> list: