feat(chv): 安全审计修复 High/Medium/Low(堆叠于 #239)
审计报告 ~/workspace/chv-security-audit/REPORT.md(No-Go, Critical 0 / High 7 / Medium 8 / Low 5)代码层修复,mock 测试覆盖,真机动态验证一律未做、只列清单(见 docs/chv-production-readiness.md §11)。 High: - H1 egress 代码门:代理地址校验、直连显式允许+审计、 每 VM 独立 tap/mac/ip 校验、net 字段白名单;宿主防火墙 列为部署清单,代码门+防火墙缺一不可。 - H2 网关 key 移出 argv:provisioned seed 盘客内文件 /etc/chv/guest-env(0600)投递,传输层密钥进 argv 直接 ValueError;keyscan 模式密钥投递 fail-closed。 - H3 任务盘删除:stop/recycle/cleanup 删 disk.raw(保留期 0)+ 残留盘 GC,删失败审计+脏标记。 - H4 默认值改 provisioned:keyscan 只作显式 opt-in。 - H5 seed.iso 生成即 0600;宿主私钥 seed 盘建好后即删; 崩溃残留扫描 cleanup_stale_secrets。 - H6 state_dir 默认出 /tmp(~/.local/share/.../chv-vms, preflight 保 0700);api-socket 组/其它可写即 fail-fast。 - H7 tap 隔离校验:net.json 登记+stop 释放,共享即拒绝审计。 Medium:M1 shlex 远程转义;M2 清理失败即拒起(脏标记); M3 配额默认 50GB + 快照数/总量/保留期上限;M4 SHA256 必填 + BUILDINFO versions 实测记录(事前 lockfile 列清单); M5 host key/ preflight/失败审计补齐;M6 reuse 须声明单租户 项目;M7 容量计数只认连通 socket;M8 sshd 加固进 build.sh 断言。Low:L1 链接不跟随;L2 路径白名单;L3 失败审计; L4 双变量警告+字段白名单;L5 预热盘/任务盘对应关系定义。 旧测试:实验室默认值与生产默认值区分标注;行为已变的旧 测试按新语义更新(容量死 socket、快照白名单、磁盘路径 白名单、网关 argv、reuse 租户声明)。 测试:新 test_chv_secfix 39 项;旧 117 项 + 2 项新增断言 = 158 项;worker 相关 129 项;前端 vitest 9 项;cloud 全量 1588 项(skipped 4)。
This commit is contained in:
1 parent
003ea357f9
commit
baf26beb78
16 files changed
+2106
-132
No files matched your search
@@ -101,6 +101,11 @@ class ChvCase(unittest.TestCase):
|
||||
env = {"CHV_EGRESS_PROXY": "http://10.0.0.1:8888",
|
||||
# 实验室宣称:mock runner 假装回环端口已转发到客机
|
||||
#(feat-chv-fix 起,执行器不再无条件假设回环能通)。
|
||||
# 实验室显式 opt-in keyscan:生产默认已是
|
||||
# provisioned;本套件旧 fake 不实现 ssh-keygen/
|
||||
# genisoimage,测的不是 host key 模式,故显式
|
||||
# 声明实验室路径,绝不把它写成生产默认。
|
||||
"CHV_HOST_KEY_MODE": "keyscan",
|
||||
"CHV_SSH_FORWARD": "1"}
|
||||
if env_extra:
|
||||
env.update(env_extra)
|
||||
@@ -232,12 +237,14 @@ class PreflightTest(ChvCase):
|
||||
class ConfigCommandTest(ChvCase):
|
||||
def test_vm_config_shape_and_memory_bytes(self):
|
||||
ex = self.make_exec()
|
||||
cfg = ex.build_vm_config("/tmp/x/disk.raw")
|
||||
# feat-chv-secfix(L2):磁盘须在 state_dir 内。
|
||||
disk = os.path.join(self.state_dir, "x", "disk.raw")
|
||||
cfg = ex.build_vm_config(disk)
|
||||
self.assertEqual(cfg["cpus"], {"boot_vcpus": 2,
|
||||
"max_vcpus": 2})
|
||||
self.assertEqual(cfg["memory"]["size"], 2 * 1024 ** 3)
|
||||
self.assertEqual(cfg["kernel"]["path"], self.kernel)
|
||||
self.assertEqual(cfg["disks"], [{"path": "/tmp/x/disk.raw"}])
|
||||
self.assertEqual(cfg["disks"], [{"path": disk}])
|
||||
self.assertEqual(cfg["cmdline"]["args"],
|
||||
"console=hvc0 root=/dev/vda1 rw")
|
||||
|
||||
@@ -391,7 +398,10 @@ class LifecycleTest(ChvCase):
|
||||
self.assertEqual(kinds, ["pause", "resume"])
|
||||
|
||||
def test_restore_then_explicit_resume_order(self):
|
||||
ex = self.make_exec()
|
||||
# feat-chv-secfix(L2/H4):本测试走实验室 keyscan
|
||||
# 路径 + 声明快照目录(生产默认 provisioned + 白名单
|
||||
# 目录,旧 file:///snap/1 不再直通)。
|
||||
ex = self.make_exec(env_extra={"CHV_SNAPSHOT_DIR": "/snap"})
|
||||
out = ex.restore_vm(self._task(), "file:///snap/1")
|
||||
self.assertEqual(out["mode"], "restored")
|
||||
self.assertTrue(out["ready"])
|
||||
@@ -416,7 +426,10 @@ class LifecycleTest(ChvCase):
|
||||
ex = self.make_exec()
|
||||
# feat-chv-fix(P1-7):file:// 快照须真实存在且非空,
|
||||
# 否则 hibernate 不 shutdown;用临时文件作快照目标。
|
||||
snap = os.path.join(self.dir, "h1.snap")
|
||||
# feat-chv-secfix(L2):快照须在白名单目录内,放在
|
||||
# state_dir 下。
|
||||
snap = os.path.join(self.state_dir, "h1.snap")
|
||||
os.makedirs(self.state_dir, exist_ok=True)
|
||||
with open(snap, "wb") as fh:
|
||||
fh.write(b"S" * 64)
|
||||
snap_url = "file://" + snap
|
||||
|
||||
Reference in new issue
Block a user