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
@@ -118,5 +118,72 @@ class TestBuildRelease(unittest.TestCase):
|
||||
self.assertIn("hello.py", names)
|
||||
|
||||
|
||||
class TestSshScpCmd(unittest.TestCase):
|
||||
"""ssh_cmd/scp_cmd 的三路分发:有密码走 helper、无密码走
|
||||
密钥直连、无 helper 无代理时直连。2026-10-27 密钥补丁曾只
|
||||
放在 env-console 工作区未提交、切分支后丢失,本批把它收进
|
||||
main;测试钉住分发逻辑,不依赖真实主机与真实密钥文件。"""
|
||||
|
||||
def setUp(self):
|
||||
self._env = dict(os.environ)
|
||||
os.environ.pop("SSH_PASSWORD", None)
|
||||
os.environ.pop("SSH_PROXY_CMD", None)
|
||||
os.environ.pop("CODEX_DEPLOY_KEY", None)
|
||||
|
||||
def tearDown(self):
|
||||
os.environ.clear()
|
||||
os.environ.update(self._env)
|
||||
|
||||
def _cmds(self, helper=None, proxy_file=False, key_file=False):
|
||||
with mock.patch.object(deploy_mod, "helper_path",
|
||||
return_value=helper):
|
||||
with mock.patch.object(deploy_mod.os.path, "isfile",
|
||||
return_value=(proxy_file or key_file)):
|
||||
# isfile 对 proxy 与 key 都返回同一值:测试只断言
|
||||
# 分支形状(是否出现 ProxyCommand/-i),不区分两者。
|
||||
ssh = deploy_mod.ssh_cmd("h", "u", "true")
|
||||
scp = deploy_mod.scp_cmd("h", "u", "a", "b")
|
||||
return ssh, scp
|
||||
|
||||
def test_password_uses_helper_even_without_proxy(self):
|
||||
os.environ["SSH_PASSWORD"] = "x"
|
||||
ssh, scp = self._cmds(helper="/helpers/ssh_run.py")
|
||||
self.assertEqual(ssh[:4],
|
||||
["python3", "/helpers/ssh_run.py", "ssh", "h"])
|
||||
self.assertEqual(scp[:4],
|
||||
["python3", "/helpers/ssh_run.py", "scp", "h"])
|
||||
|
||||
def test_no_password_never_uses_helper(self):
|
||||
# 无密码时 helper(pty 喂密码)不可用:即使 helper 文件
|
||||
# 存在也不走它,否则会在密码提示处卡住。
|
||||
ssh, scp = self._cmds(helper="/helpers/ssh_run.py",
|
||||
proxy_file=True, key_file=True)
|
||||
self.assertNotIn("/helpers/ssh_run.py", ssh)
|
||||
self.assertNotIn("/helpers/ssh_run.py", scp)
|
||||
# ProxyCommand 与参数拼在一个元素里,查前缀而不是整元素。
|
||||
self.assertTrue(any(x.startswith("ProxyCommand") for x in ssh))
|
||||
self.assertIn("-i", ssh)
|
||||
self.assertIn("-i", scp)
|
||||
|
||||
def test_no_password_no_helpers_goes_direct(self):
|
||||
ssh, scp = self._cmds(helper=None,
|
||||
proxy_file=False, key_file=False)
|
||||
self.assertEqual(ssh[0], "ssh")
|
||||
self.assertNotIn("ProxyCommand", ssh)
|
||||
self.assertNotIn("-i", ssh)
|
||||
self.assertEqual(scp[0], "scp")
|
||||
|
||||
def test_explicit_proxy_cmd_wins(self):
|
||||
os.environ["SSH_PROXY_CMD"] = "proxy-cmd %h %p"
|
||||
ssh, _ = self._cmds(helper=None, proxy_file=False)
|
||||
self.assertIn("ProxyCommand proxy-cmd %h %p", ssh)
|
||||
|
||||
def test_explicit_key_env_wins(self):
|
||||
os.environ["CODEX_DEPLOY_KEY"] = "/keys/d"
|
||||
ssh, _ = self._cmds(helper=None, proxy_file=False,
|
||||
key_file=False)
|
||||
self.assertIn("/keys/d", ssh)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user