feat(chv): 对齐 Muse P6 privsep worker + 确定性安全检查层

- cloud/chv/privsep.py(新):Gitea worker 注册表(凭证白名单只含
  GITEA_TOKEN)+ 类型化请求/响应(request_id 绑定、64KB 上限)+
  Unix socket 客户端(超时/崩溃 -> 类型化失败 WorkerRefusal)+
  客户端白名单校验
- cloud/chv/safety.py(新):UntrustedData 来源标记 +
  InjectionScanner 确定性规则(block/flag/allow,中英)+
  redact_secrets + AuditLogger(只记指纹,不记值)+
  audit_inference_request/response
- chv-guest/chv-gitea-worker.py + .service(新):systemd 沙箱化
  worker(SO_PEERCRED 只放 root,仓限 ~/workspace,git 只配 authd
  helper,绝不持 token;输出先扫描再返回)
- chv-guest/chv-sync-worker-client.py(新):agent 侧薄 CLI
- chv-guest/chv-sync.sh:pull/push/status 有 socket 时走 worker,
  否则旧路径 + stderr 警告(过渡兼容)
- cloud/chv/executor.py:_run_guest 前后加推理边界审计钩子
  (best-effort)
- docs/chv-muse-p6-gap.md(新):差距表 + 覆盖边界 + 真机待验证清单
- docs/chv-production-readiness.md:§15
- cloud/tests/test_chv_muse_p6.py(新):43 项

测试:新测试 43/43;全量 cloud 套件 1910 OK(skipped=9);mypy
在新增文件上干净(剩余 4 处为基线旧错 executor.py:1396/1401、
marker_tools.py:142,未动)。
真机验证:未做,排队在 round-11 之后,清单见
docs/chv-muse-p6-gap.md §4。
This commit is contained in:
host committed 2026-11-06 22:31:54 +00:00
1 parent 06c3e172fe
commit 81e4eaf4db
10 files changed
+2071

No files matched your search

+26
View File
@@ -34,10 +34,24 @@ GUEST_ENV="${CHV_GUEST_ENV:-/etc/chv/guest-env}"
WORKSPACE="${CHV_WORKSPACE:-/home/chv/workspace}"
USER_HOME="${CHV_USER_HOME:-/home/chv}"
SYNC_USER="${CHV_USER:-chv}"
# privsep worker(feat-chv-muse-p6):socket 在时 pull/push/status
# 改走 worker(类型化请求),不在时走旧的直接路径 + 警告(过渡兼容,
# 旧镜像退役后改为无 worker 即 fail-closed)。
WORKER_SOCK="${CHV_GITEA_WORKER_SOCK:-/run/chv-gitea/worker.sock}"
WORKER_CLIENT="${CHV_GITEA_WORKER_CLIENT:-/usr/local/bin/chv-sync-worker-client}"
die() { echo "chv-sync: $*" >&2; exit 1; }
info() { echo "chv-sync: $*"; }
# 试走 worker:返回 42 = worker 不在(调用方走旧路径);其它返回
# 值即 worker 的退出码(调用方直接退出,不再回落重跑)。
try_worker() {
local action="$1"; shift
[ -S "$WORKER_SOCK" ] || return 42
[ -x "$WORKER_CLIENT" ] || return 42
"$WORKER_CLIENT" "$action" "$@"
}
# 解析仓目录:显式给则用它;否则取 WORKSPACE 下唯一的 git 仓库。
resolve_repo() {
if [ -n "${1:-}" ]; then
@@ -97,6 +111,10 @@ cmd_boot() {
}
cmd_pull() {
local rc=0
try_worker pull "${1:-}" || rc=$?
[ "$rc" != "42" ] && exit "$rc"
echo "chv-sync: worker 不在,走旧的直接路径(过渡兼容)" >&2
local dir
dir="$(resolve_repo "${1:-}")"
[ -z "$(git -C "$dir" status --porcelain)" ] \
@@ -107,6 +125,10 @@ cmd_pull() {
}
cmd_push() {
local rc=0
try_worker push "${1:-}" || rc=$?
[ "$rc" != "42" ] && exit "$rc"
echo "chv-sync: worker 不在,走旧的直接路径(过渡兼容)" >&2
local dir
dir="$(resolve_repo "${1:-}")"
if git -C "$dir" rev-parse --abbrev-ref --symbolic-full-name '@{u}' >/dev/null 2>&1; then
@@ -120,6 +142,10 @@ cmd_push() {
}
cmd_status() {
local rc=0
try_worker status "${1:-}" || rc=$?
[ "$rc" != "42" ] && exit "$rc"
echo "chv-sync: worker 不在,走旧的直接路径(过渡兼容)" >&2
local dir
dir="$(resolve_repo "${1:-}")"
git -C "$dir" status -sb