[Unit] Description=CHV Gitea sync privsep worker (feat-chv-muse-p6) After=network-online.target chv-authd.service Wants=network-online.target # authd 是可选依赖:worker 的 git 经 P3 helper 向 authd 取凭证; # authd 没起来时 worker 的 git 调用直接拒绝,不静默用旧凭证。 # 开机时序(round-12 修复轮第三轮,缺口 ①):工作区 # /home/chv/workspace 由 cloud-final 的 chv-sync boot 克隆出来, # 晚于 multi-user.target 约 9 秒;而 ReadWritePaths 的路径必须在 # systemd 建 mount namespace 时已存在,否则 226/NAMESPACE。 # ConditionPathExists 让开机那次启动在工作区出现前干净跳过 # (不耗重启预算、不 226);真正拉起靠 chv-gitea-worker.path # (工作区一出现即触发启动)。Condition 本身绝不重试——没有 # .path 单元它就是一次跳过、服务永远不起;反过来只有 .path 而 # 无 Condition,开机那次启动仍会在命名空间搭建时 226 撞上限速。 # 两者缺一不可。StartLimit 不放宽:放宽只是把竞态窗口拉大, # wake 时间在负载下已翻倍(R12 复测 2),预算仍可能耗尽; # tmpfiles.d 也不补工作区行:/home/chv 本身 07:23:40 才出现, # 晚于 tmpfiles-setup(07:23:24),补了也没用。 ConditionPathExists=/home/chv/workspace [Service] Type=simple User=root Group=root ExecStart=/usr/local/bin/chv-gitea-worker Restart=on-failure RestartSec=2 # systemd 沙箱(与 P3 authd 同款 root 单元外服务口径,再收紧): # 只读系统、独立 /tmp、不许提权、不留 capability、只许 Unix 与 # inet 协议族、只许 @system-service 系统调用、读写路径只限工作区 # 与 worker 运行时目录。网络层强制(eBPF)是 P5 的范围,不在这里 # 冒充——出口收紧靠 Sentinel 评估(authd 放凭证前)+ 只配 helper # 的 git(见 chv-gitea-worker.py)。 ProtectSystem=strict PrivateTmp=yes NoNewPrivileges=yes CapabilityBoundingSet= RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 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 由 ConditionPathExists + # chv-gitea-worker.path 守门(round-12 修复轮第三轮缺口 ①,见 # [Unit];R12 复测 2 钉死它才是剩下的 226——开机时序竞态,不要 # 再写“开机时已在”)。ExecStartPre 不能替代 tmpfiles.d——命名空间 # 搭建在它之前,226 发生在它运行之前。 ReadWritePaths=/home/chv/workspace /run/chv-gitea /var/log/chv-gitea-worker.log # worker 崩溃不拖垮 agent:broker/薄 CLI 收到类型化失败即返回, # 不重试、不挂起;systemd 只负责拉起 worker 本身。 [Install] WantedBy=multi-user.target