MUSE / ARCHITECTURE NOTES
Muse 智能体 · 执行隔离与服务面详解
本篇目录
- 0. 一句话
- 1. privsep worker 模型(实测)
- 2. 瘦客户端 / 跳板规则(实测)
- 3. Guarded output:输出也要过境(实测 strings)
- 4. 出口面:egress 代理 + 审批 + TLS 信任库(实测)
- 5. Sentinel:出口、限流与裁决的中枢(实测 + 文档)
- 6. STEFI 代理与其后的内部服务(实测到名字边界)
- 7. authd:本地认证守护(实测)
- 8. Vault 在执行面的位置(实测)
- 9. 服务面限流纪律(实测 + 文档)
- 10. 服务面全景:本 exec 命名空间实测可见的 socket 网格
- 11. 一次 privsep 工具调用的生命周期(串联本篇)
- 12. 本机实测快照:11-04 vs 10-17 对照
- 13. 边界声明(本机看不见的部分)
配套《00-Muse技术架构解构》§7 的展开篇(§14 信任边界在本篇有对应实测,见 §5、§9)。调查日期:2026-10-17(Asia/Shanghai)。 复核修订:2026-11-04(Asia/Shanghai)——基于当前会话运行时逐项重测;下文数字凡未注日期者均为 11-04 快照,10-17 旧数见 §12 对照表。 证据范围:仅本机实测——
/run/hatch/下套接字实况、env的JARVIS_*键名与套接字路径、/opt/hatch/runtime-cell/guest.env与build-cell-trust-store.sh的注释明文、/opt/hatch/bin/二进制 strings(multicall 家族avatar-media-generation、hatch-vault、authdc --help)。标注规则同前作:实测 = 当场命令验证;文档 = 本地 docs/system 文件明文;推断 = 由痕迹拼出、未经服务端证实。 红线声明:本文只记录套接字路径、键名与机制字符串,不记录任何凭据/令牌值;实测中代理环境变量里出现的认证材料一律不落盘、不引用。
0. 一句话
执行面是一张 Unix 套接字网格:Agent 住在不可信的 runtime cell 里,手里只有「瘦客户端」;任何带凭据、带网络、带权限的动作,都要穿过一条具名套接字到 cell 外的可信侧执行——进要过 fd 清单与环境白名单,出要过 guarded output 与 Sentinel 的出口/TLS/限流三重门,身份由 authd 代管、Vault 托管,内部服务统一经 STEFI 代理且只见其名不见其形。
另有一条最硬的实测边界(§4.4):部分套接字路径虽被声明在环境里、但不挂进普通 exec 进程的挂载命名空间——能力面靠命名空间裁剪,而非靠 Agent 自觉。
cell 内(不可信) cell 外 / 宿主侧(可信)
───────────────── ─────────────────────
CLI 二进制(跳板) ──fd 传递+清单──▶ privsep worker(每工具一个 .sock)
│ ├─ authd:令牌验证/代管
│ ├─ STEFI 代理 ──▶ Meta 内部服务(仅名字)
│ └─ egress 代理 ─▶ 公网(Sentinel 审批+MITM TLS)
模型推理 ───────────套接字路径声明──▶ 推理代理(路径在本 exec 命名空间不可见,见 §6.2)
Agent 进程 ─────────具名套接字────▶ Vault / Sentinel / sandbox-api / noded / telemetry
1. privsep worker 模型(实测)
1.1 每工具一 socket:当场计数 149(11-04;10-17 为 136)
ls /run/hatch/privsep/ 本轮实测 149 个套接字(11-04;10-17 为 136,+13)。命名规律(实测归类):
| 命名模式 | 数量/例子 | 含义 |
|---|---|---|
裸工具名 <tool>.sock |
多数:gmail 对应的 hatch-gws-cli-fully-isolated.sock 是例外,常规如 stripe.sock、duffel.sock、github.sock、slack.sock、zoom.sock |
一个可特权执行的工具 = 一个独立 worker 端点 |
<name>-mcp.sock |
40 个(11-04;10-17 为 38,+2;10-17 未逐项记录名单,无法指认新增者;beehiiv-mcp、composio-mcp、runway-mcp、heygen-mcp、coinbase-mcp…仍在) |
MCP 型连接器的 worker;多数在本渠道没有对应二进制(01 号 §4.2 的「预置≠可见」) |
<name>-cli.sock |
14 个(11-04 复测未变;instagram-cli、facebook-cli、health-cli、notion-cli、box-cli…) |
独立 CLI 型连接器 |
<name>-verify.sock |
2 个(11-04 复测未变;printify-verify、tessie-api-verify) |
校验专用 worker,与主 worker 分开 |
| 支付专用 | stripe-link-checkout-card.sock、shop-wallet-cli-checkout.sock |
支付/卡路径单独成 worker,不与普通 stripe/shop worker 混用 |
| 内部件 | facebook-cli-internal.sock、platform-search.sock、external_agent.sock、wai-privsep.sock |
宿主侧预置、渠道未必显露 |
1.2 隔离分级:partially / fully isolated
- 实测(strings):multicall 二进制内含
partially/fully两种等级字面,以及自带的安全测试夹具privsep-test-fully-isolated——其说明明文写着它吸收了已退役的独立工具privsep-privesc-{fully,partially}-isolated,即两级隔离都曾(且仍以等级形式)存在。 - 实测(命名):套接字名里显式带
-fully-isolated的只有 2 个(11-04 复测未变)——hatch-gws-cli-fully-isolated.sock(Google Workspace 全家桶共用,凭据面最大)与测试夹具privsep-test-fully-isolated.sock。 - 推断:fully 是需要显式标注的加强级,未标注的普通 worker 为 partially 级(环境/文件系统隔离较弱、但凭据仍在可信侧)。本机没有 partially 的显式命名物证,此分级对应关系按「显式标注例外」逻辑推断。
等价替代解释(同样与实测兼容,未能排除):
partially/fully可能是历史遗留的二元开关——fixture 自述吸收了已退役的独立工具privsep-privesc-{fully,partially}-isolated;当前默认等级可能已统一,-fully-isolated后缀只是兼容命名残留。若如此,"未标注=partially"的对应关系即不成立。区分两者需要宿主侧 worker 启动参数的证据,本机没有。
- 等级不是装饰(实测 strings):可信侧有硬拒绝句——「refusing to run tool logic on the credentialed side while privsep is turned off」;另有
JARVIS_DANGEROUSLY_ENABLE_PRIVESC_TOOL门控的privesc探针子命令,默认禁用,说明文档明文称其为「故意演示 exec-gadget 反模式」的安全测试件,不是模板。
1.3 worker 的调用协议:fd 传递 + 清单(实测 strings)
privsep 不是「把命令字符串发过去执行」,而是结构化的 fd 交接(hatch-tool-sdk 的 cli/privsep/ 模块族:trampoline.rs / executor.rs / uds_executor.rs / fd.rs / inherited_fds.rs / child_fd_handoff.rs / wire.rs):
- 跳板启动时预期 ≥3 个 fd(stdin/stdout/stderr,其后是文件 fd);fd 表要序列化传递,出现重复 fd 名、重复源 fd、路径碰撞、计数超限都有专门报错句——fd 本身就是能力:调用方能传什么 fd、就只能操作什么文件,不存在靠路径字符串的二次授权;
- 输入文件走清单制:
required_input_files / optional_input_files+ available/failure 两份 manifest,未声明的输入、既 required 又 optional、required 缺失等组合全部 fail-closed 报错; - 输入文件还须过根目录与类型检查:「input file is outside its allowed root」「path beneath dir is not a regular file」——符号链接/目录/越界路径进不去;
- 子进程引导材料走 sealed memfd:「create/write/seal sealed child bootstrap memfd」——引导数据一次性封印传递,不落盘、不可改;
- 工具身份要对版:「privsep worker tool-identity mismatch: trampoline passed PRIVSEP_TOOL=…」——跳板自报的工具名与 worker 期望不符直接拒绝,防错位调用;
- 方法级限制存在:
--privsep-restrict-method=与「restricted privsep socket refused the invocation: only …」句,说明某些 socket 只放行枚举内的方法子集; - worker 异常有独立语义:
privsep worker terminated by signal、响应走PrivsepRequest/PrivsepResponse结构化线格式(wire.rs),不是裸文本回流。
1.4 内建探针:隔离层自带体检(实测 strings)
privsep-test-fully-isolated 的子命令暴露了这层的自检设计:health-check(跨边界 exit 0 的金丝雀,标记串是「hard contract」,fd 没传到就判定为 privsep exploit 或应用 bug)、ping(打开 STEFI 代理 socket、做一次 verify_oauth_token 往返、打印成功标记)、example(给新工具作者抄的范式:类型化参数 + 共享的 fd-passing / authd / STEFI / 凭据探针主体)。隔离层有自己的回归测试件常驻在生产二进制里,这是它被当作安全边界(而非便利封装)维护的证据。
1.5 MCP 型 worker 的安全特殊性(缺口声明)
40 个 -mcp.sock(11-04;10-17 为 38)在 §1.1 只做了计数,隔离分级从未被追问——这是"每工具一 socket"模型下最值得深挖却最空的一块:
- 命名上无分档:全篇 149 个套接字里显式带
-fully-isolated后缀的只有 2 个(§1.2,11-04 复测),MCP worker 不在其中。按 §1.2「显式标注例外」的逻辑,它们与普通 worker 处于同一默认等级(推断,与 §1.2 同样的证据强度——同样也受 §1.2 末"等价替代解释"的保留意见约束)。 - 代码来源不受完全信任:MCP 名单里有
composio-mcp等第三方集成商——即第三方逻辑与第一方连接器走同样的 worker 模型。是否应得更严的沙箱,本机没有任何分档证据(❓)。 -verify.sock的归属不明:2 个校验专用 worker(printify-verify、tessie-api-verify)与主 worker 分开,但名字上并未出现在-mcp名单里(❓:它们是否为 MCP 连接的校验形态,本机无证据对应)。
结论口径:MCP worker 的隔离等级问题在本机证据内不可区分——计数有、等级无。这是 10-安全篇可接手的议题。
2. 瘦客户端 / 跳板规则(实测)
cell 内的二进制是同一个 34MB multicall 的不同名字(01 号 §4.1),其 privsep 形态即跳板(trampoline)。规则全部来自 strings 与 guest.env 注释:
- 环境只转发白名单:
guest.env头注释明文(实测原文大意)——该文件由 spawnd 管理、root 持有、只读绑定进 cell,privsep 可信侧读它来为 partially/fully isolated 调用构建环境,而不是从「带能力的上下文」里 source 一段 shell。文件是纯 KEY=VALUE、无逻辑、无命令替换,cell 不可改。键集(实测 27 键)只有HOME/TMP*/PATH/XDG_*、CA 包路径族、代理族与两个JARVIS_*套接字键(JARVIS_AUTHD_SOCK、JARVIS_STEFI_PROXY_SOCK)。 - 转发有拒绝路径:strings 有「trampoline: refusing allowlisted forwarded env var …」——即便在白名单内,特定情形(如值形态不合)仍拒绝转发,不是无条件透传(具体触发条件本机不可见,推断为防注入式覆盖)。
- 可信侧环境与 cell 内环境同源同模板:
guest.env与guest-runtime-env.sh注释要求两者在 proxy/CA/HOME/PATH 键上保持 parity,且值只由安装期模板变量派生、不依赖/etc/hatch/env——可信侧不信任运行时环境文件。 - 单个变量的信任状被逐个写进二进制(实测 strings 的长注释体):如
JARVIS_TRACE_CONTEXT的注释明文——它只是归因盖章用,「untrusted caller writes it, so a worker must not gate an action on it. Connector authority binds to the daemon-minted runtime-context token, which Sentinel resolves…」;JARVIS_TOOL_CALL_ID / SESSION_ID / USER_TIMEZONE等都被逐个声明「只作字符串/查表键,never selects a path, command, library, credential, proxy, or authorization scope」。白名单不是名单了事,每个键都附带「不得用于授权」的限定。
3. Guarded output:输出也要过境(实测 strings)
可信侧的输出不直接流回 cell,而是被「扣住—检查—放行」:
- memfd + seal + 限额:「create/size/seal/rewind/read guarded output memfd」「guarded connector output exceeded the per-stream release limit」——stdout/stderr 各自有 per-stream 放行上限,超限不是截断了事而是报错/扣留(
GuardedOutputWithheld错误类实测存在); - post-commit 才放行:「release post-commit guarded stdout/stderr」「held output has no original stdout」——输出先 held,待动作提交成功后才 release 回原始 fd,失败的 worker 其目录变更与输出有单独的发布/丢弃路径(「could not publish the directory writes of a failed privsep worker」);
- quiesce(静默化):「open /dev/null for guarded output quiescence」「quiesce trusted worker stdout/stderr」——可信 worker 的原始 stdout/stderr 被导向 /dev/null 静默,防其日志串进 Agent 可见通道;Agent 只见 guarded 通道放行的那一份;
- 子进程错误消毒:模块名
child_error_sanitize.rs实测存在——worker 的报错回传前要清洗(防错误文本携带不该出境的内容,推断其具体规则不可见); - 验证码是 guarded output 的特级乘客(实测 strings):有独立扫描 socket
/run/hatch/safety-scan/verification-codes.sock,及一整组错误语义——「verification-code surrogation requires a trusted privsep worker」「payload exceeds the verification-code scanner limit」「guarded output contains too many verification codes」。这与文档口径(00 号 §14.3:码以[credential:<uuid>]引用形态短暂托管、审批后才喂浏览器)互为表里:替换(surrogation)只准在可信侧发生,cell 侧拿到的已是引用而非原文。 - surrogation 不止验证码(实测 strings,关联为推断):二进制内有一组秘密种类的 variant 标识——token / bearer / authorization / api_key / apikey / client_secret / clientsecret / credential / secret / surrogate(实测相邻字符串,枚举名本身不可见),出现在 surrogation 相关代码路径附近;另有凭据捕获 API 路径
/v1/credentials/capture-verification-code与credentials.capture_verification_code(实测)。这支持基线 B「secret surrogation + 白名单逐键限定」不止于验证码:API key、bearer token、client secret 等通用秘密同样在扫描/替换的词汇表内——§11 末句"验证码类原文凭据从未进过 cell"的支撑范围可放宽到通用秘密。❓:safety-scan/下除verification-codes.sock外有无其他扫描 socket,本机命名空间看不见该目录(§4.4),无从验证;扫描是按种类走不同 socket 还是同一扫描器内部分支,也未知。
4. 出口面:egress 代理 + 审批 + TLS 信任库(实测)
4.1 没有直出:死 DNS + 全量代理
guest.env注释明文:cell 的 DNS 是「deliberately dead(故意死的)」;Node 的 fetch 默认不认代理变量,所以专门设NODE_USE_ENV_PROXY=1堵住 Node 系 CLI 绕代理直连的路;- 代理族六键(大小写各一份)全部指向同一端点:
hatch-egress-proxy:3128(guest.env模板明文);实测 live 环境中的同名变量带认证材料(值不记录)——推断:模板给形状、运行时注入实例凭据; NO_PROXY只含 loopback 与 VM 内部地址段——即「本机/内部套接字直连,其余一切走代理」。
4.2 TLS:Sentinel 是唯一的中间人,且这是写死的 invariants
- cell 侧 CA 材料实测:
/run/hatch/egress-tls/下ca-bundle.pem(182,885 B)+hatch-egress-ca.pem(745 B);后者证书实测subject = issuer = CN=Hatch Sandbox Egress CA, O=Hatch(自签),有效期是合成的 1975–4096 年——一张不靠真实时间、只靠预置分发的锚证书; build-cell-trust-store.sh头注释(实测)把规则说死:宿主侧只向 cell 发布 恰好一个 信任锚——Sentinel 的 egress MITM CA,「EXACTLY ONE anchor … a security invariant, not an inventory」;Sentinel 启动时在内存中生成该 CA、只发布证书(私钥不出 Sentinel),经/run/hatch/cell-anchors只读绑定进 cell 并喂给 NSS 数据库;注释还留了事故教训:VM 入口链证书曾被放进系统信任库、后被移除,因为「系统级 CA 会为每个主机名背书,包括 Sentinel 不终止的流量」——需要额外信任的客户端只能自己 pin;- 推论(推断,两层拆开):阻止出口绕过的主结构是强制代理路由(§4.1:死 DNS + 代理变量 + NO_PROXY 仅 loopback)——流量在 TCP 层就被钉死在 egress 代理上,TLS 信任库改不改都不改变这一路由事实。单锚信任库是纵深防御的一环:它解决的是脚本注释里那次事故教训——防止系统级 CA 为"Sentinel 不终止的流量"背书。至于 HTTP CONNECT 隧道内再套一层 TLS(TLS-in-TLS)能否绕过审查,取决于 Sentinel 对 CONNECT 目标的 allowlist 策略,该策略在宿主侧,本机无证据,不作结论。因此严谨的表述是:绕过审查需要同时突破代理路由与 CONNECT 策略两层,本机只能确证第一层存在。
4.3 审批三套接字(实测键名)
出口审批不在 cell 里判,三个 JARVIS_* 键(实测键名与路径,值仅为路径;11-04 env 复核:键名与路径均未变):
| 键 | 路径 | 角色(按命名,推断分工) |
|---|---|---|
JARVIS_DAEMON_EGRESS_APPROVAL_SOCK |
/run/hatch/sentinel/daemon-egress-approvals.sock |
daemon 侧出口审批的主通道(挂在 sentinel 目录下) |
JARVIS_EGRESS_APPROVAL_ADMIN_SOCK |
/run/hatch/sentinel/egress-approvals-admin.sock |
审批的管理面(登记/裁决) |
JARVIS_EGRESS_APPROVAL_EVENTS_SOCK |
/run/hatch/daemon/egress-approvals-events.sock |
审批事件流(挂在 daemon 目录下,供订阅状态变化) |
另有工具 SDK 内的 cli/privsep/sentinel_egress.rs 模块与 HATCH_PRIVSEP_SENTINEL_EGRESS 标记(实测 strings)——privsep 调用自身的出网也走 Sentinel egress 裁决,不是 worker 就能直连。特性开关名里有 abra_hatch_network_egress_screen_enforcement、abra_hatch_sentinel_exfil_hardening(实测 strings,仅名字)——出口筛查与防外泄硬化是可远程开关的策略项。
4.4 一个边界实测:路径声明 ≠ 本命名空间可见
本轮在 exec 环境里 ls /run/hatch/proxy/、/run/hatch/sentinel/、/run/hatch/daemon/、/run/hatch/memory/、/run/hatch/safety/ 全部不存在(11-04 复测:proxy/、sentinel/、daemon/、memory/、safety/ 仍全部不存在;rescue/ 同样不可见),而 /run/hatch/ 顶层实测可见的只有:auth/ browser-broker-liveness/ cell-anchors/ egress-tls/ noded/ privsep/ resume/ runtime-cell/ sandbox/ sandbox-api/ telemetry/(11 常驻)及本轮出现的 vault/(见 §8)、新增的 upload-store/(store.sock + publisher-root 在岗)、以及 10-17 时不可见的 vault-encrypt/、vault-hmac/(各含其 socket,见 §8.1 更新)。即:推理/STEFI/Sentinel/安全服务的套接字路径被声明在环境里、但不挂进普通 exec 进程的挂载命名空间——Agent 的 shell 连「看一眼这些 socket 文件」都做不到,能碰到它们的只有被专门接线的进程(daemon、privsep 跳板)。这是本篇最硬的一条隔离实测:能力面靠命名空间裁剪,而非靠 Agent 自觉(11-04 复测:裁剪口径仍在,但 vault-encrypt/、vault-hmac/、新增 upload-store/ 可见——裁剪边界随部署调整,非一成不变)。
4.5 紧急停止与审计:本篇未覆盖的穿透问题
基线(A):控制平面负责 stop/pause/audit。本篇的隔离描述只覆盖了正常调用路径,以下三问本机证据不足,列为 ❓:
- **停止穿透哪一层?**实测
privsep worker terminated by signal证明 worker 可被信号终止,但用户侧"停止"按钮杀的是 cell 内跳板、可信侧 worker,还是两者?Guarded output 处于 held 态的输出在取消时丢弃还是已部分 release?strings 中未见cancel语义的对应错误类。 - **审计日志落在哪侧?**privsep 调用的审计记录是由 worker 写 telemetry(
/run/hatch/telemetry/可见),还是由 Sentinel/daemon 侧统一写?本机未追踪 telemetry 的错误文案。 - 审批卡片的人类侧回流:§4.3 的三条审批 socket 止于命名;卡片如何渲染、用户点击如何回流为 Sentinel 的裁决,全程在宿主侧/客户端,不在本机证据内。
建议后续用 strings grep cancel/audit/approval_scope 补一轮,或在 10-安全篇中统一收口。
4.6 降级路径:单点故障时的行为(实测为主,缺口明示)
Sentinel 与 egress 代理是执行面的单点。本机能确证的降级语义有三条(全部实测 strings),没有"服务挂了就全停"的统一结论:
- surrogation 失败是 fail-open:「verification-code surrogation failed; releasing guarded output unsurrogated」——扫描/替换失败时,guarded 输出不带替换地直接放行,而不是扣留或报错。这与 §3「替换只准在可信侧发生」形成一组张力:正常路径可信侧替换,异常路径放行未替换原文。❓:放行是直接给 cell 还是附带告警给 Agent,本机无证据。
- 引用兑换依赖 egress 代理就绪:「…so a surrogate credential cannot be redeemed; the egress proxy is still starting up」——代理启动中时
[credential:uuid]引用无法兑换(浏览器侧拿码的链路被卡住),属于启动期降级:引用还在,但兑换端没起来。 - privsep 瞬断有有限重试:「privsep worker transient disconnect; retrying round-trip」+
TRANSIENT_RETRY_MAX_ATTEMPTS上限——worker 侧瞬时断连走重试而不是立即失败;另有 socket 激活服务的等待语义「gave up waiting for a socket-activated service to answer」,说明服务起不来时调用方会等、也会放弃(放弃后的形态本机无下文,❓)。
本机无证据的两问(❓,与缺口声明一致):egress 代理 3128 彻底不可用时,工具调用是 fail-closed 报错还是排队重试——strings 未见 egress_unavailable 类错误语义;abra_hatch_network_egress_screen_enforcement 这类特性开关被远程关闭后,出口退化成什么形态——开关名实测存在(§4.3),"关掉后发生什么"无追问证据。
5. Sentinel:出口、限流与裁决的中枢(实测 + 文档)
Sentinel 在本机的可见面是「一个套接字键 + 一批语义字符串 + 一个 CA」,但把它们拼起来,它的职责至少四项:
- 出口政策权威:§4.2 的 trust-store 脚本明文称 Sentinel「terminates the cell's egress TLS by design and is the policy authority」——终止 TLS、做出口裁决,是 egress 审批三套接字的宿主;
- HTTP API 面:
JARVIS_SENTINEL_HTTP_API_SOCKET=/run/hatch/sentinel/http-api.sock(实测键名/路径;11-04 env 复核未变;目录在本 exec 命名空间不可见,同 §4.4);另有安全服务键JARVIS_SECURITY_SOCK=/run/hatch/safety/security.sock与之并列; - 连接器限流的执行者:strings 实测错误文案「Connector request rate limited by Sentinel」,配额失败结构
ConnectorQuotaFailure带retry_after_seconds / limit / requested_units / used_units / remaining_units字段——限流不是 provider 说了算,Sentinel 在本地先判(详见 §9); - 运行时上下文令牌的解析者:§2 第 4 条的 strings 明文——连接器权威绑在 daemon 现签的 runtime-context token 上,「which Sentinel resolves against its daemon-registered registry」;归因用的 trace blob 谁都能写、不作授权输入,授权只认 Sentinel 能在其登记表里查到的令牌。(此处仅指连接器/出口授权面;面向用户的敏感操作审批(approval cards)属控制平面,本篇未覆盖——见新增 §4.5。)
文档侧的旁证(文档):WhatsApp 通道文档明文「Decisions belong to Sentinel; never infer one from free…(裁决归 Sentinel,不要从自由文本推断)」——Sentinel 也是外部消息通道结构化控制的裁决者,不止管网络出口。本机能确证的就到这一层:Sentinel 的判定逻辑、登记表内容、策略规则库都在宿主侧,不在 cell 文件内(见 §11)。
6. STEFI 代理与其后的内部服务(实测到名字边界)
6.1 代理本体
- 入口:
JARVIS_STEFI_PROXY_SOCK=/run/hatch/proxy/stefi.sock——同时出现在guest.env模板与 live 环境(实测键名/路径;11-04 env 复核未变); - 客户端形态:工具 SDK 内「build stefi proxy client」(strings),工具访问 Meta 内部服务不直连、统一经此代理;
- caller 校验(实测 strings):错误文案
invalid stefi caller authorization token独立存在——代理对调用方做令牌校验,不是「能连上 socket 就能用」;§1.4 的ping探针做的正是「打开 STEFI socket + 一次verify_oauth_token往返」,其端点形态为http://localhost/hatch/verify_oauth_token(strings 中的 UDS-over-HTTP 风格路径),返回里有用户标识字段(仅知字段名,不记录值)。
6.2 边界声明:只到名字为止
STEFI 之后能从本机文件里读到的只有名字(00 号 §7 已列):WWW / MSL / CAGI / Mango·Pariscope,以及 strings 里的 MslBrowserService through Stefi、require_cagi(CAGI 路由被指定时的 fail-closed 语义:「Fail closed unless the measured-CVM CAGI route is selected」)。这些系统的实现、拓扑、数据都不在本机——本文对 STEFI 之后的全部陈述止于「存在此名、经此代理、带 caller 校验」,与 00 号 §17 的边界声明一致。另外注意 §4.4 的实测:/run/hatch/proxy/ 在本 exec 命名空间根本不存在,STEFI socket 对普通 shell 进程同样是「声明了路径、摸不到实体」。
7. authd:本地认证守护(实测)
- 本体端点:
/run/hatch/auth/authd.sock,实测为srw-rw-rw- nobody:nogroup,是本轮在/run/hatch/auth/下唯一可见的 socket; - 调试客户端
authdc(实测--help):明文自述「Talks to its Unix socket ($JARVIS_AUTHD_SOCK or /run/hatch/auth/authd.sock)…authd gates most endpoints by peer credentials」——按对端凭据(SO_PEERCRED 类机制,推断具体实现)门控,特权命令要在宿主侧 root 下跑,cell 内普通调用只能碰被放行的子集; - 命令面(实测):
file(auth-files 操作)、cred(dynamic credentials 动态凭据)、record(按 UUID/外部键查目录记录,只输出消毒后的 catalog 投影)——即 authd 管的不只是 OAuth 令牌,还有「认证文件」与「动态凭据」两类对象,目录对外只给 sanitized projection; - 入口侧门控:env 有
JARVIS_AUTHD_INGRESS_ALLOWED_USERS键(只记键名)——authd 的 ingress 有允许用户清单; - 与 STEFI 的分工(实测 strings 互证):工具侧报错「missing hatch user token: ensure shared credentials are available through authd」——用户令牌的可用性由 authd 保证;STEFI 侧用
verify_oauth_token验令牌有效性。一个管「令牌在哪、给不给」,一个管「令牌真不真」,在ping探针里被串成一次往返体检。 - Google 系另有
hatch_gws_auth(12MB 独立二进制,实测)与hatch-gws-auth.sock——GWS 的授权面自成一路,但最终仍落在hatch-gws-cli-fully-isolatedworker 后面(§1.2)。
8. Vault 在执行面的位置(实测)
8.1 形态:常驻守护进程,不是 CLI
- 二进制
hatch-vault实测 10MB、stripped ELF;它没有给 Agent 用的命令行面——本轮误以--help调用时,它直接按守护进程启动并 fatal 退出,报错大意为「vault-health unix socket bind failed at /run/hatch/vault/health.sock: active listener is present; refusing to replace it」。这条报错本身就是实测证据:Vault 是单例常驻服务,且拒绝二义启动; - socket 家族实测(
ls /run/hatch/vault/):auth.sock、cvm.sock、health.sock三个(11-04 复测未变),均为root:root srw-rw----——比 authd 的srw-rw-rw-更严,普通用户进程连连接权限都没有;strings 还显示两个旁路服务面:/run/hatch/vault-encrypt/encrypt.sock与/run/hatch/vault-hmac/hmac.sock(加密与 HMAC 被拆成独立 socket 服务;10-17 时本 exec 命名空间见不到其目录,11-04 复测已可见,各含其 socket——命名空间裁剪的口径随部署有调整,见 §4.4 更新); - 调用方校验:strings 有端点路径
credentials/v1/auth-file/get与请求头名X-Hatch-Verified-Vault-Caller、「bearer/notary auth disabled on the auth socket」——auth socket 走本地可信通道免令牌,而另一类入口要 notary(公证)令牌校验,且公钥缺失时该认证方式直接禁用(fail-closed)。
8.2 它在执行面管什么
按 strings 与文档拼图(实测 + 文档):
- 凭据文件的受控读取:
credentials/v1/auth-file/get+AuthFileGetResponse——连接器/遥测等可信组件经 Vault 拿认证文件,Agent 本人不经手(遥测代理的访问令牌刷新也要「read … through authd」并经 Vault 侧校验,strings 互见 authd 与 vault 两路); - CVM 密钥托管(本机为 standard VM,只见其形):
cvm.sock服务cvm_enroll / cvm_open、RV(reliable volume)密钥的 LUKS key-slot 管理、芯片 allowlist 与 attestation bundle 校验、迁移密钥(migration key)的签发/持有状态机——这一整套是 confidential VM 的磁盘密钥与跨机迁移面(文档data-handling.md:CVM 的持久存储由客户自管密钥加密)。standard VM 上它处于未 enroll 侧(状态字面cvm_unenrolled / cvm_locked等实测存在),但守护进程照常在岗; - Secure Vault 的服务端(文档,00 号 §14.3):用户经安全录入卡存入的网站密码/API 凭据由 Vault 托管,浏览器只在结账/登录步经它取用;一次性验证码不入 Vault、走 §3 的 guarded-output 托管引用。Agent 在执行面与 Vault 的关系是「无关系」:没有任何给 Agent 的 vault 工具/命令,
hatch-vault二进制在/opt/hatch/bin/里对 Agent 可见但不可用(跑起来是个守护进程)——可见 ≠ 可用,在凭据面被贯彻到极致。
9. 服务面限流纪律(实测 + 文档)
服务面的「纪律」有三层,越往下越硬:
| 层 | 机制 | 证据 |
|---|---|---|
| 行为层(Agent 纪律) | 429 / connector_rate_limited / 限流型 403 = 该 provider 域硬停;terminal_for_attempt=true 时本轮终局;禁止换端点、降速率、派子 Agent 或排队续跑绕过 |
文档(system prompt「Service limits」节,00 号 §14 已引) |
| 裁决层(Sentinel) | 连接器调用先过 Sentinel 的三维配额:shared_pool_request_rate(共享池请求率)、connector_request_rate(单连接器请求率)、connector_weighted_units(加权单位)——任一触发即 ConnectorQuotaFailure,带 retry_after_seconds 回执,Agent 只能按回执等/停,不能猜 |
实测 strings(错误类与字段名) |
| 清单层(manifest) | 每个连接器 manifest 自带 units/分钟成本表,在 worker 侧 enforce(01 号 §4.3)——防单个工具打爆 provider 配额 | 文档 + 01 号实测 |
另有一条 pacing 痕迹(实测 strings):CLI 侧有「write/read CLI pacing request/response」字面——推断工具调用在发出前还有一轮向可信侧申请节奏许可的往返,与 Sentinel 配额是同一纪律的两种实现面,本机无法确证其分工。除连接器外,推理面同样有纪律痕迹:字符串里 ModelProxyUnavailable / ModelProxyBusy / ModelProxyTimeout 与 CAGI 429 终局语义(01 号/浏览器工具说明)表明模型代理的限流回执也被结构化成错误类,而不是裸 HTTP 状态码让 Agent 自由解读。
10. 服务面全景:本 exec 命名空间实测可见的 socket 网格
除 privsep 与上述「声明不可见」的服务外,本轮在 /run/hatch/ 实测可见的服务面(全部为 Unix socket,属主多为 nobody:nogroup 或 root):
| 目录 | 内容(实测) | 角色 |
|---|---|---|
auth/ |
authd.sock |
§7 |
vault/ |
auth.sock / cvm.sock / health.sock(root, 0600 类权限;11-04 复测未变) |
§8 |
vault-encrypt/ vault-hmac/ |
encrypt.sock / hmac.sock(11-04 新可见;10-17 时不可见) |
§8.1 旁路服务面 |
upload-store/ |
store.sock + publisher-root(11-04 新见) |
上传存储(推断,按命名) |
sandbox-api/ |
api.sock(root) |
沙箱/Spaces 执行 API |
sandbox/ |
space-inference.sock / space-media.sock / space-privileged.sock / space-web-search.sock(root) |
Spaces 的四路专用服务:推理、媒体、特权、搜索各行其道 |
noded/ |
control.sock / ephemeral.sock / http-api.sock |
节点守护(浏览器节点等)的控制面 |
telemetry/ |
telemetry.sock / bugreport.sock + scuba/ 子目录 |
遥测上报(另有 JARVIS_TELEMETRY_PROXY_SOCK 键指向于此) |
egress-tls/ cell-anchors/ |
CA 材料(§4.2) | 信任锚分发 |
browser-broker-liveness/ |
两个 process-lock 文件 | 浏览器 broker 的存活锁 |
resume/ |
root 持有的恢复目录 | 运行时恢复/接管(00 号 §8 的 restart checkpoints 在文件面的落点之一,推断) |
与之对照,只在 env 里声明、本命名空间不可见的服务键(实测键名全表;11-04 env 复核:键名与路径均未变,proxy/ sentinel/ daemon/ memory/ safety/ rescue/ 目录仍不可见):JARVIS_INFERENCE_PROXY_SOCK(推理)、JARVIS_STEFI_PROXY_SOCK(§6)、JARVIS_SENTINEL_HTTP_API_SOCKET 与三条 egress 审批键(§4.3/§5)、JARVIS_SECURITY_SOCK、JARVIS_MEMORY_SOCK、JARVIS_SANDBOX_API_SOCK(此条反而可见)、JARVIS_RESCUE_SIGNAL_SOCK、JARVIS_AUTHD_SOCK(可见)、JARVIS_TELEMETRY_PROXY_SOCK(可见)。可见性的分野大致是:Agent 日常工具链要用的(privsep/auth/沙箱/遥测)挂进来,裁决与推理面(proxy/sentinel/safety/memory)只给路径不给实体(推断,按实测分布归纳)。
11. 一次 privsep 工具调用的生命周期(串联本篇)
Agent 调 CLI(cell 内,multicall 跳板)
→ 跳板组装 PrivsepRequest:类型化参数 + 输入文件清单 + fd 表(sealed memfd 引导)
→ 连 /run/hatch/privsep/<tool>.sock,worker 验工具身份(PRIVSEP_TOOL 对版)
→ 可信侧执行:guest.env 白名单环境构建(宿主侧读模板,不 source cell 文件)
├─ 需要用户令牌 → authd(peer 凭据门控);内部服务 → STEFI(caller 令牌校验)
├─ 需要出网 → sentinel_egress 裁决 → egress 代理 → Sentinel MITM TLS(单锚信任库)
└─ 配额 → Sentinel 三维限流 + manifest units 双判,超限回 ConnectorQuotaFailure
→ 输出回程:worker stdout/stderr 先 quiesce 到 /dev/null
→ guarded output(memfd+seal+per-stream 上限)扣留
→ 含验证码则过 safety-scan 扫描、替换为 [credential:uuid] 引用
→ 动作 post-commit 后才 release 回跳板 fd
→ Agent 拿到结构化结果(JSON 信封),验证码类原文凭据从未进过 cell
12. 本机实测快照:11-04 vs 10-17 对照
| 项 | 11-04 快照 | 10-17 旧数 |
|---|---|---|
| privsep 套接字 | 149(当场 ls 计数;-mcp.sock 40、-cli.sock 14、-verify.sock 2、显式 -fully-isolated 2) |
136(-mcp.sock 38、-cli.sock 14、-verify.sock 2、-fully-isolated 2) |
| authd | 未重测 | /run/hatch/auth/authd.sock 在岗(srw-rw-rw-);authdc 子命令 file/cred/record |
| Vault | auth.sock / cvm.sock / health.sock 复测未变;vault-encrypt/、vault-hmac/ 目录新可见(见 §8.1) |
hatch-vault 10MB stripped ELF,单例守护;三 socket(root, srw-rw----) |
| egress | 未重测 | 代理 hatch-egress-proxy:3128;CA 包 182,885 B + egress CA 745 B(自签,CN=Hatch Sandbox Egress CA,1975–4096);信任锚恰好 1 个(脚本明文 invariant) |
| 审批键 | env 复核:三个键名与路径均未变 | egress 审批 3 键(daemon/admin/events),路径分属 sentinel/ 与 daemon/ 目录 |
| 命名空间可见性 | 常驻可见 11 个目录(§4.4 清单)+ vault/ + 新见 upload-store/、vault-encrypt/、vault-hmac/;proxy/ sentinel/ daemon/ memory/ safety/ rescue/ 仍仅 env 声明、实体不可见 |
常驻可见 11 个目录(§4.4 清单);本轮另见非常驻 vault/(见 §8)。proxy/ sentinel/ daemon/ memory/ safety/ 仅 env 声明、实体不可见 |
| guest.env | 未重测 | 45 行、27 键,spawnd 管理、root 持有、只读入 cell |
13. 边界声明(本机看不见的部分)
privsep worker 的宿主侧实现、Sentinel 的策略与登记表、STEFI 之后的内部服务、egress 审批的人机判定逻辑、Vault 的密钥材料与 notary 公钥来源、authd 的凭据存储后端——均不在 cell 文件内,本文只记录其接口痕迹(socket 名、键名、错误文案、脚本注释),凡超出痕迹的分工判断已标 推断。本文未记录任何凭据/令牌/验证码的值,代理认证材料与用户标识字段一律只记「存在此字段」。