新增 run_tests.py:三套件统一入口,只加仓库根(deploy 套件 再加 deploy/ 目录在根之前),各套件走独立子进程;verify 作 业改走运行器,coverage 作业因子进程测不到覆盖率保持原 discover 命令。tests/ 13 个文件的 sys.path 前置 import 全部 改回正常 import(含 test_host_trace 的 try/except 回落); deploy 的 deploy 目录插入与 verify-multiuser 的 spec 加载按 陷阱 2 如实保留(仅删 verify-multiuser 冗余的根插入)。 .coveragerc omit 加 */run_tests.py,使新运行器文件不计入 生产覆盖率。门槛未动(仍 75%),未补新测试。
48 lines
1.9 KiB
Python
48 lines
1.9 KiB
Python
"""host.run_verify / goal verify 的 shell 语义证据(CI 第二阶段
|
||
bandit High triage,第 3 项白名单轨范围外、本轨只做 triage)。
|
||
|
||
背景:bandit High 4 项全是 host.py 的 shell=True:
|
||
run_verify(1319)、notify(1497)、goal verify 两处
|
||
(2099/2103)。本轨不改它们,理由须有测试证据:
|
||
|
||
- run_verify 的命令是整串 shell 字符串(配置/默认验测命令),
|
||
管道与复合命令必须经 shell 解释:列表式 exec 形跑不通。
|
||
本文件断言管道与 && 真实生效——改 shell=False 会立刻失败。
|
||
- notify 的插值已全部 shlex.quote:证据在 tests/test_host.py
|
||
的 test_notify_failure_quotes_shell_metacharacters(`; touch`
|
||
与 `$(touch )` 不执行、只落日志原文),本文件不再重复。
|
||
"""
|
||
|
||
import tempfile
|
||
import unittest
|
||
import host
|
||
|
||
|
||
class RunVerifyShellTest(unittest.TestCase):
|
||
def test_pipe_requires_shell(self):
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
rc, out = host.run_verify("echo hello | tr a-z A-Z", tmp)
|
||
self.assertEqual(rc, 0)
|
||
self.assertEqual(out, "HELLO")
|
||
|
||
def test_compound_command_requires_shell(self):
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
rc, out = host.run_verify("echo a && echo b", tmp)
|
||
self.assertEqual(rc, 0)
|
||
self.assertEqual(out, "a\nb")
|
||
|
||
def test_empty_command_is_noop(self):
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
self.assertEqual(host.run_verify("", tmp), (0, ""))
|
||
self.assertEqual(host.run_verify(None, tmp), (0, ""))
|
||
|
||
def test_failing_command_returns_rc_and_output(self):
|
||
with tempfile.TemporaryDirectory() as tmp:
|
||
rc, out = host.run_verify("echo oops; exit 3", tmp)
|
||
self.assertEqual(rc, 3)
|
||
self.assertEqual(out, "oops")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|