"""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()