fix(chv-muse-r12fix2-1): tmpfiles.d 预建 worker 运行时路径(P6-1)
R12 复测钉死的根因:chv-gitea-worker.service 用 ProtectSystem=strict + ReadWritePaths=/home/chv/workspace /run/chv-gitea /var/log/chv-gitea-worker.log,systemd 建 mount namespace 时要求每个 列出路径事先存在,否则 226/NAMESPACE crash-loop(NRestarts=12); 交付镜像里 /run/chv-gitea(/run 是 tmpfs)与 /var/log/chv-gitea-worker.log(worker 首次写审计才建)两处都不存在, worker 从未起来过。 取舍:只用 tmpfiles.d(/etc/tmpfiles.d/chv.conf,加 d /run/chv-gitea 0700 与 f /var/log/chv-gitea-worker.log 0600,与 P4 的 /run/chv 同款 写法、同一文件)。ExecStartPre 不行——命名空间搭建在任何 ExecStartPre 之前,226 发生在它运行之前;改 ReadWritePaths 为已存在 目录(/var/log)会把写权限放大到整个目录。tmpfiles.d 由 systemd-tmpfiles-setup 在 sysinit 跑、早于 multi-user 的服务启动; 不新增进镜像的文件(chv.conf 本就是 build.sh 内联生成),lockfile 无需登记。unit 文件只加注释说明耦合,不改 ReadWritePaths 本身。 测试:WorkerUnitTmpfilesTest 钉住 ReadWritePaths 每一项挥发路径都有 对应的 tmpfiles 行(类型 + 模式)、P4 四行仍在、unit 无 ExecStartPre。
This commit is contained in:
1 parent
a18a530bfd
commit
35d9c3ff3f
3 files changed
+94
-1
No files matched your search
+14
-1
@@ -388,7 +388,20 @@ VC_ARGS=(-a "$OUT/disk.raw"
|
|||||||
# root 所有时 chv-browser 建不了 cdp-broker.sock,broker
|
# root 所有时 chv-browser 建不了 cdp-broker.sock,broker
|
||||||
# bind 报 PermissionError 而 crash-loop。绝不用 0666/0777
|
# bind 报 PermissionError 而 crash-loop。绝不用 0666/0777
|
||||||
# 那种放宽(与 round-11 authd socket 组权限 0660 同款口径)。
|
# 那种放宽(与 round-11 authd socket 组权限 0660 同款口径)。
|
||||||
--run-command 'printf "d /run/chv 2775 root chv-browser -\nd /run/chv/shots 0755 chv-browser chv-browser -\nd /run/chv/ask-queue 0750 chv-browser chv-browser -\nd /run/chv-browser 0755 chv-browser chv-browser -\n" > /etc/tmpfiles.d/chv.conf && systemctl enable chv-broker chv-browser chv-cdp-broker || true')
|
# round-12 修复轮第二轮(项 1,P6):tmpfiles.d 再预建 worker
|
||||||
|
# 的运行时路径。chv-gitea-worker.service 用 ProtectSystem=strict
|
||||||
|
# + ReadWritePaths=/home/chv/workspace /run/chv-gitea
|
||||||
|
# /var/log/chv-gitea-worker.log;systemd 建 mount namespace 时
|
||||||
|
# 要求每个列出路径事先存在,否则 226/NAMESPACE(R12 复测钉死:
|
||||||
|
# /run 是 tmpfs、开机不存在;log 文件要 worker 首次写审计才建,
|
||||||
|
# 而 worker 永远跑不到那一步)。ExecStartPre 救不了——命名空间
|
||||||
|
# 搭建在任何 ExecStartPre 之前,226 发生在它运行之前;改
|
||||||
|
# ReadWritePaths 为已存在目录(/var/log)会把写权限放大到整个
|
||||||
|
# 目录,也不要。tmpfiles.d 由 systemd-tmpfiles-setup 在 sysinit
|
||||||
|
# 跑、早于 multi-user 的服务启动,且与 P4 的 /run/chv 同款写法,
|
||||||
|
# 不新增进镜像的文件(chv.conf 本就是 build.sh 内联生成),
|
||||||
|
# lockfile 无需登记。模式与 worker 审计 0600 同款口径。
|
||||||
|
--run-command 'printf "d /run/chv 2775 root chv-browser -\nd /run/chv/shots 0755 chv-browser chv-browser -\nd /run/chv/ask-queue 0750 chv-browser chv-browser -\nd /run/chv-browser 0755 chv-browser chv-browser -\nd /run/chv-gitea 0700 root root -\nf /var/log/chv-gitea-worker.log 0600 root root -\n" > /etc/tmpfiles.d/chv.conf && systemctl enable chv-broker chv-browser chv-cdp-broker || true')
|
||||||
# P3 交接(Muse P3 的 authd/sentinel 叶子模块):文件在仓库里存在时
|
# P3 交接(Muse P3 的 authd/sentinel 叶子模块):文件在仓库里存在时
|
||||||
# 拷入镜像(本分支已有,合入后自动生效);不存在时只警告、不失败——
|
# 拷入镜像(本分支已有,合入后自动生效);不存在时只警告、不失败——
|
||||||
# M4 既定 build.sh 不硬要求 cloud/,见上。缺叶子模块时 chv-authd
|
# M4 既定 build.sh 不硬要求 cloud/,见上。缺叶子模块时 chv-authd
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ NoNewPrivileges=yes
|
|||||||
CapabilityBoundingSet=
|
CapabilityBoundingSet=
|
||||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||||
SystemCallFilter=@system-service
|
SystemCallFilter=@system-service
|
||||||
|
# ReadWritePaths 下的路径必须在开机时已存在(ProtectSystem=strict
|
||||||
|
# 下 systemd 建 mount namespace 的硬要求,缺一个即 226/NAMESPACE):
|
||||||
|
# /run/chv-gitea 与 /var/log/chv-gitea-worker.log 由
|
||||||
|
# /etc/tmpfiles.d/chv.conf 预建(build.sh 内联写,round-12 修复轮
|
||||||
|
# 第二轮项 1);/home/chv/workspace 开机时已在(R12 复测的 226
|
||||||
|
# 只报过前两处)。ExecStartPre 不能替代 tmpfiles.d——命名空间
|
||||||
|
# 搭建在它之前,226 发生在它运行之前。
|
||||||
ReadWritePaths=/home/chv/workspace /run/chv-gitea /var/log/chv-gitea-worker.log
|
ReadWritePaths=/home/chv/workspace /run/chv-gitea /var/log/chv-gitea-worker.log
|
||||||
# worker 崩溃不拖垮 agent:broker/薄 CLI 收到类型化失败即返回,
|
# worker 崩溃不拖垮 agent:broker/薄 CLI 收到类型化失败即返回,
|
||||||
# 不重试、不挂起;systemd 只负责拉起 worker 本身。
|
# 不重试、不挂起;systemd 只负责拉起 worker 本身。
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
import importlib.util
|
import importlib.util
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -756,6 +757,78 @@ class ExecutorAuditHookTest(unittest.TestCase):
|
|||||||
safety_mod.DEFAULT_AUDIT_LOGGER = old
|
safety_mod.DEFAULT_AUDIT_LOGGER = old
|
||||||
|
|
||||||
|
|
||||||
|
# -- (7b) worker 单元沙箱路径预建 -------------------------------------------
|
||||||
|
class WorkerUnitTmpfilesTest(unittest.TestCase):
|
||||||
|
"""round-12 修复轮第二轮(项 1,P6):ProtectSystem=strict 下
|
||||||
|
ReadWritePaths 的每一项必须在开机时已存在,否则 systemd 建
|
||||||
|
mount namespace 直接 226/NAMESPACE(R12 复测钉死:/run/chv-gitea
|
||||||
|
与 /var/log/chv-gitea-worker.log 两处缺失,worker 从未起来)。
|
||||||
|
|
||||||
|
预建机制只能是 tmpfiles.d:ExecStartPre 跑在命名空间搭建之后,
|
||||||
|
救不了 226;改 ReadWritePaths 为已存在目录会放大写权限。
|
||||||
|
tmpfiles.d 与 P4 的 /run/chv 同款写法、同一文件
|
||||||
|
(/etc/tmpfiles.d/chv.conf,build.sh 内联生成,不新增进镜像
|
||||||
|
的文件,lockfile 无需登记)。
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _readwrite_paths(self):
|
||||||
|
text = (REPO_ROOT / "chv-guest"
|
||||||
|
/ "chv-gitea-worker.service").read_text()
|
||||||
|
for line in text.splitlines():
|
||||||
|
if line.startswith("ReadWritePaths="):
|
||||||
|
return line.split("=", 1)[1].split()
|
||||||
|
self.fail("unit 文件里找不到 ReadWritePaths")
|
||||||
|
|
||||||
|
def _tmpfiles_entries(self):
|
||||||
|
text = (REPO_ROOT / "chv-guest" / "build.sh").read_text()
|
||||||
|
# chv.conf 只由一处 printf 写(与 P4 共用同一文件)。
|
||||||
|
self.assertEqual(
|
||||||
|
text.count("> /etc/tmpfiles.d/chv.conf"), 1,
|
||||||
|
"chv.conf 须只由 build.sh 里一处 printf 写")
|
||||||
|
match = re.search(
|
||||||
|
r"printf \"((?:[^\"\\]|\\.)*)\" > /etc/tmpfiles.d/chv.conf",
|
||||||
|
text)
|
||||||
|
self.assertIsNotNone(match, "build.sh 里找不到写 chv.conf 的行")
|
||||||
|
raw = match.group(1).replace("\\n", "\n")
|
||||||
|
entries = {}
|
||||||
|
for line in raw.splitlines():
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) >= 3 and parts[0] in ("d", "f"):
|
||||||
|
entries[parts[1]] = (parts[0], parts[2])
|
||||||
|
return entries
|
||||||
|
|
||||||
|
def test_volatile_readwrite_paths_have_tmpfiles(self):
|
||||||
|
entries = self._tmpfiles_entries()
|
||||||
|
paths = self._readwrite_paths()
|
||||||
|
# /run 下的目录(tmpfs,开机不存在)须有 d 行;
|
||||||
|
# 文件路径(worker 首次写审计才建)须有 f 行。
|
||||||
|
self.assertEqual(entries.get("/run/chv-gitea"),
|
||||||
|
("d", "0700"))
|
||||||
|
self.assertEqual(entries.get("/var/log/chv-gitea-worker.log"),
|
||||||
|
("f", "0600"))
|
||||||
|
for path in paths:
|
||||||
|
if path.startswith("/run/") or path.endswith(".log"):
|
||||||
|
self.assertIn(path, entries,
|
||||||
|
"%s 无 tmpfiles 预建,服务会 226" % path)
|
||||||
|
|
||||||
|
def test_p4_tmpfiles_lines_kept(self):
|
||||||
|
# 同一文件里的 P4 行是回归哨兵:改 chv.conf 别把它们挤掉。
|
||||||
|
entries = self._tmpfiles_entries()
|
||||||
|
for path, kind_mode in (
|
||||||
|
("/run/chv", ("d", "2775")),
|
||||||
|
("/run/chv/shots", ("d", "0755")),
|
||||||
|
("/run/chv/ask-queue", ("d", "0750")),
|
||||||
|
("/run/chv-browser", ("d", "0755"))):
|
||||||
|
self.assertEqual(entries.get(path), kind_mode, path)
|
||||||
|
|
||||||
|
def test_no_exec_start_pre_in_unit(self):
|
||||||
|
# ExecStartPre 跑在命名空间搭建之后,救不了 226——
|
||||||
|
# 若有人加了它,说明误以为它能预建路径。
|
||||||
|
text = (REPO_ROOT / "chv-guest"
|
||||||
|
/ "chv-gitea-worker.service").read_text()
|
||||||
|
self.assertNotIn("ExecStartPre=", text)
|
||||||
|
|
||||||
|
|
||||||
class BuildInfoContentsTest(unittest.TestCase):
|
class BuildInfoContentsTest(unittest.TestCase):
|
||||||
"""round-12 修复轮(项 2,P6):worker 三件须进 BUILDINFO
|
"""round-12 修复轮(项 2,P6):worker 三件须进 BUILDINFO
|
||||||
contents(无条件拷入,与 P2/P4 同款钉法)。"""
|
contents(无条件拷入,与 P2/P4 同款钉法)。"""
|
||||||
|
|||||||
Reference in new issue
Block a user