feat: deploy 无密码时走密钥直连(收进 main,替代丢失的工作区补丁)
背景:2026-10-27 另一条线给 deploy.py 打的密钥补丁只放在 env-console 工作区未提交,切分支后丢失;部署一度只能靠它 + --allow-dirty。本批把逻辑收进 main,并加一处加固。 分发:有 SSH_PASSWORD 时走 helper(pty 喂密码,实测最稳的一 路);无密码时 helper 不可用(会卡在密码提示),改走密钥直连: ProxyCommand 显式环境变量优先、其次 helper 目录的 proxy_tunnel.py(存在才用),密钥按 CODEX_DEPLOY_KEY → /root/.ssh/id_codex_deploy → ~/.ssh/id_codex_deploy 顺序显式传 -i——不能只依赖 /root/.ssh/config 的 Host 条目,那个目录会在 VM 回收时被清空(2026-10-27 05:04 实测),而 ~/.ssh 的那份 持久。两处都没有时不硬编造,靠 ssh 配置或 agent。 测试:deploy/tests 新增 TestSshScpCmd 5 个(有密码走 helper、 无密码绝不用 helper、无 helper 无代理时直连、显式代理优先、 显式密钥优先);全量 deploy 19、host 62、cloud 598 全过。
This commit is contained in:
1 parent
5ba4d35839
commit
420a7fecfd
2 files changed
+112
-8
No files matched your search
+45
-8
@@ -156,30 +156,67 @@ def helper_path(name):
|
||||
return path if os.path.isfile(path) else None
|
||||
|
||||
|
||||
def ssh_cmd(host, user, remote_cmd):
|
||||
"""返回一条 ssh 命令。优先用已验证稳定的 helper,否则用
|
||||
SSH_PROXY_CMD 环境变量,否则直连。绝不把密码拼进命令。"""
|
||||
helper = helper_path("ssh_run.py")
|
||||
if helper:
|
||||
return ["python3", helper, "ssh", host, user, remote_cmd]
|
||||
def _deploy_key():
|
||||
"""无密码时的部署密钥路径:显式环境变量优先,其次两处惯常
|
||||
位置。/root/.ssh 的那份会在 VM 回收时被清空,~/.ssh 的那份
|
||||
持久;两处都没有时返回 None(此时靠 ssh 配置或 agent,不
|
||||
硬编造路径)。这里只返回路径,不读密钥内容。"""
|
||||
env_key = os.environ.get("CODEX_DEPLOY_KEY")
|
||||
if env_key:
|
||||
return env_key
|
||||
for cand in ("/root/.ssh/id_codex_deploy",
|
||||
os.path.expanduser("~/.ssh/id_codex_deploy")):
|
||||
if os.path.isfile(cand):
|
||||
return cand
|
||||
return None
|
||||
|
||||
|
||||
def _proxy_cmd():
|
||||
"""无密码时的 ProxyCommand:显式环境变量优先,其次 helper
|
||||
目录的 proxy_tunnel.py(存在才用);都没有时返回 None(直
|
||||
连,不把不存在的脚本写进命令)。"""
|
||||
proxy = os.environ.get("SSH_PROXY_CMD")
|
||||
if proxy:
|
||||
return proxy
|
||||
default_proxy = os.path.join(HELPER_DIR, "proxy_tunnel.py")
|
||||
if os.path.isfile(default_proxy):
|
||||
return "python3 %s %%h %%p" % default_proxy
|
||||
return None
|
||||
|
||||
|
||||
def ssh_cmd(host, user, remote_cmd):
|
||||
"""返回一条 ssh 命令。有 SSH_PASSWORD 时优先用已验证稳定的
|
||||
helper(pty 喂密码);无密码时走密钥直连:ProxyCommand 按
|
||||
_proxy_cmd(),密钥按 _deploy_key() 显式传 -i(不能只依赖
|
||||
/root/.ssh/config 的 Host 条目,那个目录会在 VM 回收时被
|
||||
清空)。绝不把密码拼进命令。"""
|
||||
helper = helper_path("ssh_run.py")
|
||||
if helper and os.environ.get("SSH_PASSWORD"):
|
||||
return ["python3", helper, "ssh", host, user, remote_cmd]
|
||||
base = ["ssh", "-o", "StrictHostKeyChecking=no",
|
||||
"-o", "UserKnownHostsFile=/dev/null"]
|
||||
proxy = _proxy_cmd()
|
||||
if proxy:
|
||||
base += ["-o", "ProxyCommand %s" % proxy]
|
||||
key = _deploy_key()
|
||||
if key:
|
||||
base += ["-i", key]
|
||||
return base + ["%s@%s" % (user, host), remote_cmd]
|
||||
|
||||
|
||||
def scp_cmd(host, user, local, remote):
|
||||
helper = helper_path("scp_run.py")
|
||||
if helper:
|
||||
if helper and os.environ.get("SSH_PASSWORD"):
|
||||
# helper 自带 egress proxy + 密码 pty,是此前实测最稳的一路。
|
||||
return ["python3", helper, "scp", host, user, local, remote]
|
||||
proxy = os.environ.get("SSH_PROXY_CMD")
|
||||
base = ["scp", "-o", "StrictHostKeyChecking=no",
|
||||
"-o", "UserKnownHostsFile=/dev/null"]
|
||||
proxy = _proxy_cmd()
|
||||
if proxy:
|
||||
base += ["-o", "ProxyCommand %s" % proxy]
|
||||
key = _deploy_key()
|
||||
if key:
|
||||
base += ["-i", key]
|
||||
return base + [local, "%s@%s:%s" % (user, host, remote)]
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user