From dcb0824f78683c589c86858e0e16e8e4a70851a3 Mon Sep 17 00:00:00 2001 From: host Date: Fri, 6 Nov 2026 10:55:02 +0000 Subject: [PATCH] =?UTF-8?q?fix(chv-guest):=20=E6=B5=8F=E8=A7=88=E5=99=A8?= =?UTF-8?q?=E8=A3=85=E7=B3=BB=E7=BB=9F=E8=B7=AF=E5=BE=84=EF=BC=88B-22?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round 7 构建本身成功,但 BUILDINFO.versions.chromium 为空: virt-customize 的客机 shell 里 HOME=/,Playwright 默认缓存 ~/.cache/ms-playwright 落到根目录 /.cache(实测浏览器在 /.cache/ms-playwright/chromium_headless_shell-1248),而 build.sh 读的是 /root/.cache/ms-playwright(不存在),ls 读回 空文件;buildinfo.py 当时不校验 chromium 非空,静默放过, 事后 check_lockfile / generate --verify 兜底报未覆盖(exit 1)。 改:安装与读回都走 PLAYWRIGHT_BROWSERS_PATH= /usr/local/share/ms-playwright(agent 运行时也须设同一变量, 否则 chv 用户在家目录找不到浏览器);buildinfo.py 加 playwright_browsers_path 字段,并校验 playwright=1 时 versions.chromium 非空;README 同步。 --- chv-guest/README.md | 2 +- chv-guest/build.sh | 14 +++++++++++--- chv-guest/buildinfo.py | 10 ++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/chv-guest/README.md b/chv-guest/README.md index 066daf8..4c09c2d 100644 --- a/chv-guest/README.md +++ b/chv-guest/README.md @@ -30,7 +30,7 @@ | 语言与工具链 | Python 3.12、git、curl、ca-certificates、xz-utils、fontconfig、openssh-client(Node.js 不装:Playwright 驱动是 Python playwright,见 PLAYWRIGHT=1 分支;任务镜像 Dockerfile 里也没有 Node.js,本清单不虚构它) | 构建时钉小版本并记入构建日志;apt 用 --no-install-recommends(B-21:默认装 Recommends 会连带拉入 gcc 全套工具链顶满根分区) | | 文档/图片工具 | 已裁剪:pandoc、poppler-utils、latexmk、texlive-latex-base、python-docx、openpyxl、python-pptx、PyMuPDF、Pillow 不在轻量镜像内 | 全量版曾照抄 `cloud/docker/Dockerfile` 的 apt/pip 清单,轻量版按用户决定砍掉 | | agent 引擎 | codex、codex-code-mode-host、codex-resources/bwrap(成套,约 367M,缺 sibling 直接构建失败) | codex 0.164.0-alpha.9(与生产任务镜像一致);`CODEX_BIN_DIR` 由构建方提供,bin/ 不进仓库 | -| 浏览器 | Playwright + chromium-headless-shell(默认装,不要完整 Chromium) | Python playwright 装当时的 headless-shell,版本以 ms-playwright 缓存目录名记入 BUILDINFO.versions.chromium | +| 浏览器 | Playwright + chromium-headless-shell(默认装,不要完整 Chromium) | Python playwright 装当时的 headless-shell,版本以 ms-playwright 缓存目录名记入 BUILDINFO.versions.chromium;浏览器在系统路径 /usr/local/share/ms-playwright(B-22:virt-customize 里 HOME=/,默认缓存会落到根目录 /.cache),agent 运行时须设 PLAYWRIGHT_BROWSERS_PATH 指向它 | | 客机基础 | openssh-server(SSH 通道用)、cloud-init(qemu-guest-agent 已裁剪,CHV 不用它) | sshd 只允许 key 登录,禁止密码登录——build.sh 写入 /etc/ssh/sshd_config.d/99-chv.conf 并经 sshd -t + grep 断言(feat-chv-secfix,M8,此前只是文档声称) | | Gitea 同步 | gt 1.0.0(官方 install.sh + SHA256 校验)、chv-sync(启动时 clone、显式 pull/push 的同步脚本) | 凭证走 seed 盘 /etc/chv/guest-env(0600)投递,不进镜像;见 §7 | | 任务代码 | codex-app-server 仓库代码置于 `/app`(host.py 入口) | 版本见 §3,不挂载宿主代码目录(VM 与宿主无共享路径) | diff --git a/chv-guest/build.sh b/chv-guest/build.sh index 15fa1a8..1c1bb17 100755 --- a/chv-guest/build.sh +++ b/chv-guest/build.sh @@ -210,6 +210,14 @@ run qemu-img convert -f qcow2 -O raw "$IMG" "$OUT/disk.raw" # (git 的 Recommends,agent 任务可能要 ssh 出站)。 # apt-get clean 只清 .deb 缓存、不动 lists(playwright # --with-deps 稍后还要 apt 装浏览器依赖);lists 在最后一步清。 +# B-22:virt-customize 的客机 shell 里 HOME=/,Playwright 默认 +# 缓存路径 ~/.cache/ms-playwright 会落到根目录 /.cache(round 7 +# 实测:浏览器装在 /.cache/ms-playwright/chromium_headless_shell-1248, +# /root/.cache 根本不存在,ls 读回空文件、BUILDINFO.versions.chromium +# 为空,check_lockfile 兜底报未覆盖)。改走系统路径 +# PLAYWRIGHT_BROWSERS_PATH=/usr/local/share/ms-playwright:构建时 +# 装这里、读回这里;运行时 agent 也须设同一变量,否则 chv 用户 +# 会在自己家目录下找不到浏览器。 # Playwright 默认开启(PLAYWRIGHT=0 可显式关掉),浏览器只装 # chromium-headless-shell(不要完整 Chromium)。单次 # virt-customize:apt 安装、pip、拷入、sshd 加固、git 占位、 @@ -217,7 +225,7 @@ run qemu-img convert -f qcow2 -O raw "$IMG" "$OUT/disk.raw" # Playwright 装在第一次 freeze 之后、最终 freeze 之前(B-08: # 最终 freeze 须在 Playwright 安装之后,否则 # BUILDINFO.versions.pip 里没有 playwright;Chromium 版本以 -# ms-playwright 缓存目录名记录(如 chromium_headless_shell-1181), +# ms-playwright 缓存目录名记录(如 chromium_headless_shell-1248), # 写进 /app/guest-versions-chromium.txt)。 GT_INSTALL_CMD="curl -fsSL -o /tmp/gt-install.sh https://gitea.com/gitea/cli/raw/branch/main/scripts/install.sh && echo \"${GT_INSTALL_SH_SHA256} /tmp/gt-install.sh\" | sha256sum -c - && GITEA_CLI_VERSION=${GT_VERSION} GITEA_CLI_INSTALL_DIR=/usr/local/bin sh /tmp/gt-install.sh && rm -f /tmp/gt-install.sh && /usr/local/bin/gt version" VC_ARGS=(-a "$OUT/disk.raw" @@ -240,9 +248,9 @@ VC_ARGS=(-a "$OUT/disk.raw" --run-command 'dpkg-query -W -f "\${Package} \${Version}\n" > /app/guest-versions-dpkg.txt; pip3 freeze > /app/guest-versions-pip.txt || true') if [ "${PLAYWRIGHT:-1}" = "1" ]; then VC_ARGS+=( - --run-command '(pip3 install --no-cache-dir --break-system-packages playwright || pip3 install --no-cache-dir playwright) && python3 -m playwright install --with-deps chromium-headless-shell' + --run-command '(pip3 install --no-cache-dir --break-system-packages playwright || pip3 install --no-cache-dir playwright) && PLAYWRIGHT_BROWSERS_PATH=/usr/local/share/ms-playwright python3 -m playwright install --with-deps chromium-headless-shell' --run-command 'dpkg-query -W -f "\${Package} \${Version}\n" > /app/guest-versions-dpkg.txt; pip3 freeze > /app/guest-versions-pip.txt || true' - --run-command 'ls /root/.cache/ms-playwright/ > /app/guest-versions-chromium.txt 2>/dev/null || true') + --run-command 'ls /usr/local/share/ms-playwright/ > /app/guest-versions-chromium.txt 2>/dev/null || true') fi # B-21 收尾:清掉两轮 apt 的缓存与 lists(--with-deps 装完后 # 不再有 apt 活动),把空间还给镜像。 diff --git a/chv-guest/buildinfo.py b/chv-guest/buildinfo.py index 652ef33..a093fd6 100644 --- a/chv-guest/buildinfo.py +++ b/chv-guest/buildinfo.py @@ -35,6 +35,10 @@ BASE_CONTENTS = [ # 否则换宿主/换执行器配置时无法复现。 KERNEL_CMDLINE = "console=hvc0 root=/dev/vda1 rw" +# 浏览器装在系统路径(B-22),不是某用户的 ~/.cache:构建时 +# PLAYWRIGHT_BROWSERS_PATH 指这里,agent 运行时也须设同一变量。 +PLAYWRIGHT_BROWSERS_PATH = "/usr/local/share/ms-playwright" + def _read_lines(path): try: @@ -92,6 +96,8 @@ def build(outdir, tag, ubuntu, codex_version, repo_commit, "ubuntu_image_sha256_set": True, "kernel_cmdline": KERNEL_CMDLINE, "playwright": bool(playwright), + "playwright_browsers_path": PLAYWRIGHT_BROWSERS_PATH + if playwright else "", "image_sha256": disk_sha, "artifacts": { "disk.raw": {"sha256": disk_sha, "size": disk_size}, @@ -124,6 +130,10 @@ def main(argv): if not info["gt_version"]: print("BUILDINFO gt_version 为空(gt 未装好)", file=sys.stderr) return 1 + if playwright == "1" and not info["versions"].get("chromium"): + print("BUILDINFO versions.chromium 为空(浏览器未装好或" + "读回路径不对)", file=sys.stderr) + return 1 if info["tag"] != tag: print("BUILDINFO tag 不一致", file=sys.stderr) return 1