fix(chv): 阶段 3 live 根因——浏览器 socket 与数据盘 profile 的两处权限

- /run/chv 0755 root:root 时 chv-browser 建 browser.sock 报
  PermissionError、服务无限 crash-loop(P2 遗留,阶段 2 从未验
  过 browser.sock):tmpfiles 改 0775 root:chv-browser。
- /home/chv 默认 0750,chv-browser 穿不过家目录,ismount 判假、
  profile 静默回落本机盘:chv-data-mount 挂载成功后 chmod 0751
  /home/chv(只放行穿过,不放行列表)。
- 驱动:等 cloud-init done + 四服务 active 再验浏览器。
- 回归 97 项全过(新增 2 项接线断言)。
This commit is contained in:
host committed 2026-11-08 09:45:00 +00:00
1 parent 1188e4b000
commit eb495892e1
3 files changed
+28 -1

No files matched your search

+8 -1
View File
@@ -334,7 +334,14 @@ VC_ARGS=(-a "$OUT/disk.raw"
# 启动再按 pid 认领(登记落盘 /run/chv/execd-tasks.json)。
--run-command 'printf "[Unit]\nDescription=CHV guest exec daemon (stage 2: shell/files/codex hosting)\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=/usr/bin/python3 /usr/local/bin/chv-execd\nRestart=always\nRestartSec=2\nKillMode=process\n\n[Install]\nWantedBy=multi-user.target\n" > /etc/systemd/system/chv-execd.service'
--run-command 'printf "[Unit]\nDescription=CHV Gitea sync daemon (stage 2: resident pull/push loop)\nAfter=network.target\n\n[Service]\nType=simple\nUser=chv\nGroup=chv\nRuntimeDirectory=chv-syncd\nRuntimeDirectoryMode=0755\nExecStart=/usr/bin/python3 /usr/local/bin/chv-syncd\nRestart=always\nRestartSec=2\n\n[Install]\nWantedBy=multi-user.target\n" > /etc/systemd/system/chv-syncd.service'
--run-command 'printf "d /run/chv 0755 root root -\nd /run/chv/shots 0755 chv-browser chv-browser -\nd /run/chv/tasks 0755 root root -\n" > /etc/tmpfiles.d/chv.conf && systemctl enable chv-broker chv-browser chv-daemon chv-execd chv-syncd || true')
# 阶段 3 live 实证(2026-11-08,构建 #8 驱动):chv-browser 以
# chv-browser 身份跑,要在 /run/chv 里建 browser.sock;0755
# root:root 时 bind 报 PermissionError、服务无限 crash-loop,
# 阶段 2 从未验过 browser.sock 故一直没暴露。改 0775
# root:chv-browser(组在镜像构建时已建,tmpfiles-setup 启动时
# 能解析——与 syncd 那行因 chv 用户尚不存在被跳过不同);
# socket 本身仍由服务 chmod 0600,broker 以 root 连,不受影响。
--run-command 'printf "d /run/chv 0775 root chv-browser -\nd /run/chv/shots 0755 chv-browser chv-browser -\nd /run/chv/tasks 0755 root root -\n" > /etc/tmpfiles.d/chv.conf && systemctl enable chv-broker chv-browser chv-daemon chv-execd chv-syncd || true')
# P1 交接(Muse P1 的 vsock_notify.py):文件在仓库里存在时拷入
# 镜像(P1 分支才有,本分支尚无);不存在时只警告、不失败——
# 合并后自动生效,P2 不改该脚本内容。
+6
View File
@@ -52,5 +52,11 @@ chown chv:chv "$MOUNT" || true
mkdir -p "$MOUNT/.chv-browser-profile" || true
chown chv-browser:chv-browser "$MOUNT/.chv-browser-profile" 2>/dev/null || true
chmod 0700 "$MOUNT/.chv-browser-profile" 2>/dev/null || true
# 阶段 3 live 实证(2026-11-08,构建 #8 驱动):/home/chv 默认
# 0750 chv:chv,chv-browser 穿不过家目录去够数据盘 profile——
# ismount 判假、profile 静默回落本机盘(服务本身不报错)。
# 放到 0751:只放行穿过(+x),不放行列表(无 r),
# chv-browser 能进已知子目录,看不见家目录内容。
chmod 0751 /home/chv 2>/dev/null || true
log "mounted $DEV -> $MOUNT"
exit 0
+14
View File
@@ -352,6 +352,20 @@ class BuildWiringTest(unittest.TestCase):
self.assertIn("After=network.target cloud-final.service",
block)
def test_tmpfiles_lets_browser_bind_its_socket(self):
# 阶段 3 live 根因:/run/chv 0755 root:root 时 chv-browser
# 建 browser.sock 报 PermissionError、服务无限 crash-loop。
text = (ROOT / "chv-guest" / "build.sh").read_text()
self.assertIn("d /run/chv 0775 root chv-browser -", text)
self.assertNotIn("d /run/chv 0755 root root -", text)
def test_data_mount_lets_browser_traverse_home(self):
# 阶段 3 live 根因 #2:/home/chv 默认 0750,chv-browser
# 穿不过家目录,ismount 判假、profile 静默回落本机盘。
text = (ROOT / "chv-guest" / "chv-data-mount.sh").read_text()
self.assertIn("chmod 0751 /home/chv", text)
self.assertIn(".chv-browser-profile", text)
def test_dry_run_contains_stage3_browser_wiring(self):
with tempfile.TemporaryDirectory() as tmp:
repo = os.path.join(tmp, "repo")