Codewhale 命令执行沙箱威胁模型:Seatbelt、Bubblewrap 与外部沙箱后端的完整防护解析
Codewhale 命令执行沙箱威胁模型Seatbelt、Bubblewrap 与外部沙箱后端的完整防护解析【免费下载链接】CodewhaleOpen-source coding agent for your terminal, built in Rust and on a journey of continuous community improvement. Issues and PRs welcome.项目地址: https://gitcode.com/GitHub_Trending/de/Codewhale导读在终端编码代理中模型会提议并执行 Shell 命令因此命令执行边界的安全设计决定了整个工作流的信任底线。本文以 Codewhale 官方威胁模型文档 docs/SANDBOX.md 为主体结合crates/tui/src/sandbox下的真实实现系统讲解 Codewhale 沙箱机制的平台覆盖、选择逻辑、策略语义、外部后端OpenSandbox / ShannonNet以及诊断与归因方法。读完你将掌握批准不等于沙箱的边界划分、macOS Seatbelt 与 Linux Bubblewrap 的开启条件和完整配置、SandboxPolicy各档位与可写根/受保护子路径的底层推导逻辑以及如何通过诊断命令确认当前会话真实可用的隔离级别。核心前提批准不是沙箱沙箱也不是批准Codewhale 将模型提议的命令隔离为相互独立的控制层docs/SANDBOX.md 在开篇即明确批准策略、感知工作区的工具workspace-aware tools与操作系统级命令包装器OS command wrapper是三套独立的控制机制。docs/AUTHORIZATION_ORDER.md描述的是策略审批层级它们运行在命令真正到达执行边界之前而 docs/SANDBOX.md 只描述已经接线进命令执行路径command execution path的行为。因此一个命令通过了人工批准不代表它处于沙箱之中配置选择了workspace-write也不能证明当前平台真的有一个可用的 OS 包装器——选择是策略层面的声明可用性是运行时探测/配置解析的结果源码目录里存在 seccomp 实现模块或未来的 Windows 辅助契约不等于命令真的被这些机制限制了。只有真正接入子命令启动路径并被实际选中的包装器才会被 Codewhale 宣称为活跃沙箱。这一点在 PUBLIC_SANDBOX_BACKENDS 常量中得到印证该公开能力清单刻意只保留命令行执行路径能够真实选择并应用的包装器并且该常量被网站事实漂移门禁web/lib/facts-drift.ts解析删除或改名都会破坏发布门禁——能说多少沙箱能力本身是被代码与门禁共同约束的契约。平台总览哪些机制、在什么条件下被报告docs/SANDBOX.md 给出的平台矩阵如下这是理解全文各节的索引表机制平台选择条件Codewhale 上报值Seatbeltsandbox-execmacOS运行时探测成功时自动启用macos-seatbeltBubblewrap/usr/bin/bwrapLinuxprefer_bwrap true且文件可执行linux-bwrap无 OS 包装器无可选 bwrap 的 Linux默认none无 OS 包装器Windows当前实现noneOpenSandbox 兼容服务任意受支持宿主sandbox_backend opensandbox外部执行路径ShannonNet worker签名能力调用任意 tailnet 节点具备shannonCLI 的任意受支持宿主sandbox_backend shannon外部执行路径从源码看get_platform_sandbox_with_bwrap_preference(prefer_bwrap: bool)是这份选择逻辑的直接实现crates/tui/src/sandbox/mod.rsmacOS 上调用seatbelt::is_available()Linux 上只有在prefer_bwrap true且bwrap::is_available()时才返回LinuxBubblewrap。探测失败或未配置时返回None对应上报值none。也就是说有源码、有模块永远不会让is_sandbox_available()返回真——模块需要被选中的包装器而不是它本身的存在。SandboxType枚举的Display实现mod.rs也印证上报值none、macos-seatbelt、linux-bwrap。注意 Windows 分支的显示名是windows-sandbox但get_platform_sandbox并不把它纳入候选因而它不会出现在面向用户的当前可用沙箱上报里见下文 Windows 一节。macOSSeatbelt 运行时探测与动态生成 ProfilemacOS 上的沙箱由系统自带的sandbox-execSeatbelt提供。Codewhale 会先运行一个最小化 profile 来探测/usr/bin/sandbox-exec只有探测成功且所选SandboxPolicy确实请求沙箱时子命令才会被包裹进一个动态生成的 Seatbelt profile。该 profile 提供的能力边界docs/SANDBOX.md大范围的只读文件系统访问由所选策略限定的写权限包括工作区以及受支持工具所需的特定运行时/缓存路径仅当策略允许时才放行网络访问。若探测失败或sandbox-exec不可用Codewhale 上报none并不带 Seatbelt 包装器直接启动命令也不会在这个回退路径上打任何 Seatbelt 标记。实现上prepare_seatbeltcrates/tui/src/sandbox/mod.rs在包裹命令的同时向子进程环境注入CODEWHALE_SANDBOXseatbelt与兼容别名DEEPSEEK_SANDBOXseatbelt——这个环境标记是这次执行确实被 Seatbelt 包裹的运行时证据与前面不打标记的回退路径形成严格对照。此外mod.rs 的set_denied_read_subpaths展示了 Seatbelt 规则的一个隐蔽细节macOS 内核按解析后的路径匹配所以一条只针对/var/...写的拒绝规则永远拦不住真实的/private/var/...文件——同一路径的两个拼写原样与规范化后的 canonical 形式都会被记录进 deny-list否则 deny 规则形同虚设。Linux可选的 Bubblewrap 命名空间包装Linux 的命令沙箱默认关闭、显式开启。在顶层配置中加入prefer_bwrap true只有当/usr/bin/bwrap是常规可执行文件时 Codewhale 才会选中 bubblewrap判定在bwrap::is_available()内完成。没有CODEWHALE_PREFER_BWRAP环境变量覆盖——这是有意设计防止环境变量悄悄改变进程隔离姿态它只能靠顶层prefer_bwrap配置键控制相关接线见 crates/tui/src/exec_agent.rs配置结构见 crates/tui/src/config.rs。包装器根据解析后的SandboxPolicy推导挂载与网络命名空间生成的命令形如/usr/bin/bwrap \ --unshare-all \ [--share-net] \ --ro-bind / / \ --dev /dev \ --proc /proc \ --tmpfs /tmp \ [--dev-bind device-root device-root ...] \ --bind writable-root writable-root ... \ --ro-bind protected-descendant protected-descendant ... \ [--ro-bind extra-ro-root extra-ro-root ...] \ --chdir cwd \ -- program args固定的基础视图#5410沙箱始终获得私有的/dev全新设备节点因此/dev/null这类重定向能正常工作这正是原始缺陷 #5410 的来源——继承自只读根绑定的宿主设备节点对open(O_WRONLY)返回EROFS私有的/proc避免读取进程表的工具链行为异常tmpfs 挂载的/tmp为链接器与测试脚手架提供可写但隔离的暂存空间而不扩大文件系统策略。实现层为这份默认三件套提供的两个可选扩展键bwrap_ro_roots额外以只读方式绑定挂载的宿主路径最后应用因此可用来收窄某条策略可写路径bwrap_dev_roots以读写方式绑定的宿主字符/块设备节点如/dev/null。目录永远不会被采纳——这个键不允许沦为通用的可写根逃生通道。缺失的路径被静默跳过——一条过期的配置绝不能导致沙箱启动失败。这些约束在BwrapMountExtensions::resolve()mod.rs中逐一落地只读根需 canonicalize 成功、且不能是/设备根还需通过is_char_device() || is_block_device()校验。之所以用--ro-bind / /就已经暴露了宿主文件系统只读所以额外只读根很少需要——它们是为策略或未来默认收窄了根绑定的布局准备的mod.rs。workspace-write 与 read-only 的可写面沙箱给子进程一个只读的根视图具体差异取决于策略workspace-write每个安全且真实存在的策略根都被挂载为读写——包括工作目录、配置的附加根、/tmp与TMPDIR除非被排除、以及验证过的 Git worktree 元数据根。已存在的.codewhale与.deepseek后代目录在其可写父级之后被重新挂载为只读。缺失路径、非目录路径与/一律不会被提升为可写挂载。从 policy.rs 的get_writable_roots源码可以还原完整的推导顺序先复制writable_roots加入 canonical 化的工作目录再为每个根调用resolve_git_worktree_writable_roots——Git worktree 把可变元数据存放在 worktree 目录之外因此只放行从工作区.git指针推导出的gitdir/commondir其余外部路径保持工作区边界接着按exclude_slash_tmp/exclude_tmpdir决定是否加入/tmp与TMPDIR最后为每个可写根扫描其下已存在的.codewhale/.deepseek目录将其登记为该可写根的只读子路径。read-only不存在任何可写绑定工作目录停留在只读根视图内部。网络命名空间--unshare-all默认隔离网络仅当策略的network_access为真时 Codewhale 才追加--share-net。对应源码里的spec.sandbox_policy.has_network_access()mod.rs策略层的取值见 policy.rsReadOnly恒为 falseWorkspaceWrite/ExternalSandbox看字段DangerFullAccess恒为 true。danger-full-access与external-sandbox完全绕过本地包装器。不选装的后果与安装指引用户未选装、/usr/bin/bwrap缺失或不可执行时Codewhale 上报none并直接启动命令——不存在假装有沙箱的标记性回退也不会悄悄换成别的 Linux 沙箱。仓库虽含crates/tui/src/sandbox/seccomp.rs但它未接线进子命令启动模块注释与 mod.rs 的 cfg 均说明这点故不对外宣称。Bubblewrap 需要单独安装Codewhale 不内置vendoring它Ubuntu/Debianapt install bubblewrapFedoradnf install bubblewrapArchpacman -S bubblewrapWindows当前不宣传任何 OS 沙箱Windows 的命令路径目前上报none。源码树里的windows.rs只是一个未来的 Job Object 进程树清理辅助契约尚未接线进选择逻辑因此不得把它描述成以下任何一种能力只读文件系统或 workspace-write 强制网络阻断注册表隔离受限令牌restricted-token或 AppContainer 隔离。模块级文档mod.rs 与windows.rs反复强调未来的第一个辅助契约仅做进程树包含process-tree containment它不暗示文件系统、网络、注册表或 AppContainer 隔离。Windows 的宿主权限与批准策略仍然生效但那是权限控制不是 Codewhale 的 OS 命令沙箱。prepare_windowsmod.rs分支只为强制测试与未来接线而存在并且get_platform_sandbox并不主动返回 Windows。Linux 进程加固是纵深防御不是命令沙箱在 Linux 启动阶段Codewhale 以 best-effort 方式给自己的进程施加三条内核级限制crates/tui/src/sandbox/process_hardening.rsPR_SET_DUMPABLE0进程不可被 ptrace/proc/self/变为 root 所有PR_SET_NO_NEW_PRIVS1本进程及全部后代永不能经 setuid/setgid/fscaps 获得新特权RLIMIT_CORE0禁用核心转储防止 API 密钥、令牌、提示词等敏感内存数据在崩溃时落盘。每条失败都会被记录启动照常继续。这些限制降低的是进程检视、提权与 core-dump 风险并没有为子命令创建文件系统或网络隔离因而不会被列为沙箱后端。模块文档还给出严格的时序约束apply_process_hardening()必须在 Tokio 运行时启动、任何工作线程产生之前调用——dumpable 状态按线程组生效、no-new-privs 对整个进程树不可逆一旦线程存在再修改可能与/proc查询竞争process_hardening.rs。唯一的例外是启动姿态本身#5723当启动沙箱模式解析为danger-full-access经CODEWHALE_SANDBOX_MODE或配置文件的sandbox_mode键PR_SET_NO_NEW_PRIVS会被跳过好让代理 Shell 里的sudo/su/setuid 辅助程序继续工作——完全访问就应当真的是完全访问。每档更窄的姿态都保留该标志作为纵深防御且CODEWHALE_NO_NEW_PRIVS在两个方向上覆盖姿态决策#5413falsey 值、0、false、no、off、disabled总是跳过该标志truthy 值总是设置它该标志对进程树不可逆决定只能在启动时做出会话内对单次调用的沙箱升级无法再解除它。should_apply_no_new_privsprocess_hardening.rs给出精确优先级显式覆盖胜出 → 其次danger-full-access跳过 → 其余姿态含不可解析值一律保留失败即关门fail-closed。而no_new_privs_active()会用PR_GET_NO_NEW_PRIVS读回真实的内核标志状态让诊断面如实披露残余的 setuid 阻断而不是复述启动时的决定。外部后端一OpenSandbox 兼容服务配置sandbox_backend opensandbox后Shell 执行被送往配置的 OpenSandbox 兼容 HTTP 端点取代本地子进程启动sandbox_backend opensandbox sandbox_url http://localhost:8080 sandbox_api_key YOUR_API_KEYcreate_backendcrates/tui/src/sandbox/backend.rs在此分支用sandbox_url缺省http://localhost:8080与sandbox_api_key构造OpenSandboxBackend。Codewhale 会校验请求/响应契约但隔离保证属于所配置的服务及其运营者——后端有多强边界就有多强。sandbox_backend none或省略该键则保持本地执行。从SandboxKind::parsebackend.rs可见后端名字解析是大小写不敏感的且接受open-sandbox、open_sandbox等别名。SandboxBackendtraitbackend.rs定义了这种后端的通用契约exec返回结构化SandboxOutputstdout/stderr/exit code默认实现把子代理与父代共享同一后端for_child返回None这正是普通远程执行器对sub-agent的语义。OpenSandbox 也属于无委托权威的后端见下节对比。外部后端二ShannonNet 签名能力执行当sandbox_backend shannon时每条 Shell 命令都变成一次经shannonCLI 发出的签名cap://sandbox/exec调用。真正执行它的 worker 由 ShannonNet 路由器选中的某个已准入提供者承担——典型如shannon-worker --kind docker或位于另一台 tailnet 节点上的shannon-tsnet-worker——Codewhale永远不会得知其地址。会话生命周期与 Work Tree 同步会话启动时 Codewhale 解析其持久的codewhaleAgent首次则创建创建一个以工作区命名的 Task World并挂接能力worker 校验这条授权链后在一个无网络、资源受限的容器中执行并在签名的回执receipt中返回 stdout、stderr 与退出码。shannon trace task可以列出每条命令及其服务方与传输证据。sandbox_shannon_sync true默认时worker 为每个 Task World 保留一个可写的会话容器Codewhale 在每条命令前把会话工作树同步进去首次全量同步非忽略文件树——遵循.gitignore、本地与全局 excludes.git本身也被尊重符号链接与超过 16 MiB 的文件被跳过之后仅同步新增/修改文件与删除按每请求 6 MiB 分块命令在/work中以引擎本地刚编辑过的内容运行写出的结果保留给下一条命令——因此远程构建与测试套件可以正常工作。worker 拒绝路径穿越、绝对路径、符号链接及超出尺寸预算的归档后端断开或空闲 TTL 到期即销毁会话且绝不把自己的检出暴露给会话。一次失败的同步会使该命令失败而不是让它跑在一棵过期的树上。对应配置sandbox_backend shannon sandbox_shannon_home ~/.shannon # 默认$SHANNON_HOME 或 ~/.shannon sandbox_shannon_capability cap://sandbox/exec # 默认 sandbox_shannon_sync true # 默认实现上sandbox_shannon_home支持~展开并按sandbox_shannon_home→$SHANNON_HOME→~/.shannon的优先级解析shannon二进制来自$SHANNON或PATHbackend.rs。隔离保证属于 workerCodewhale 只校验回执契约。与所有外部后端一致后台、交互与 TTY 模式不受支持。子代理的委托权威与受限上下文ShannonNet 后端下的子代理运行在委托权威之下这是它与 OpenSandbox 最本质的区别agent工具派生子进程时后端派生一个由会话codewhaleAgent 认证的 ShannonNet 子身份World 从会话 World 投影而来、只暴露沙箱能力委托深度被衰减子进程的 Shell 命令以该子身份在该 World 中签名送入子进程自己的会话容器子进程结束时任务上记录一条 join 回执其最终摘要与结果子进程的 World 被销毁委托无法建立时派生直接失败——绝不让子进程以会话主体的身份运行无委托权威的后端OpenSandbox则如常与父代共享后端。此外子代理得到的不是完整转录而是有界上下文会话针对该任务的 native-memory 命中当[memory]启用时会被导入codewhaleAgent 的记忆图并附带出处ShannonNet 把子进程投影 World 可能看到的内容机密笔记永不流入编译成一个短块追加到子进程提示词中并附上编译器的信息流注释与上下文哈希。会话结束即关闭 World释放会话后端会触发内容寻址检查点、销毁 World、拆除 worker 的会话容器detached。/shannon [world|trace|children]可检视存活会话Agent、投影进 World 的能力及授权深度、Agent 树与任务上的回执。策略档位与回退sandbox_mode 全解本地sandbox_mode取值sandbox_mode workspace-write # read-only | workspace-write | danger-full-access | external-sandbox各档位的实际语义与 docs/SANDBOX.md 及 policy.rs 的SandboxPolicy一一对应read-only与workspace-write仅在对应包装器Seatbelt/Bubblewrap被选中且可用时才由它强制执行无包装器时命令在无 OS 隔离下运行。danger-full-access刻意绕过本地 OS 包装器SandboxPolicy::DangerFullAccess的should_sandbox()恒为 falsepolicy.rs。Linux 上它还会在启动时跳过PR_SET_NO_NEW_PRIVS进程加固保证sudo/setuid 工作流继续可用#5723。注意 policy.rs 中该姿态的标签会随 no-new-privs 实际状态变化——是全访问沙箱禁用 允许 setuid还是全访问但 no-new-privs 仍开启都会如实呈现。external-sandbox声明执行已在外部隔离绕过第二重本地包装器对应SandboxPolicy::ExternalSandbox。无包装器选中时Shell 命令直接运行批准规则与感知工作区的原生文件工具仍是独立的控制手段。策略解析上的一个重要事实项目配置文件可以收紧sandbox_mode。config/src/lib.rs中的project_sandbox_mode_is_allowed与sandbox_mode_rankcrates/config/src/lib.rs实现了层级化比较——项目配置只能把会话sandbox_mode收窄如向read-only方向而不能把用户基线放宽无法解析的写法同样无法静默放松。另外sandbox_mode被user_constitution.rs列为受宪法保护的运行期策略字段crates/config/src/user_constitution.rs。规范化的环境变量覆盖sandbox_mode与外部后端存在规范化canonical的环境变量覆盖入口CODEWHALE_SANDBOX_MODECODEWHALE_SANDBOX_BACKENDCODEWHALE_SANDBOX_SHANNON_HOME、CODEWHALE_SANDBOX_SHANNON_CAPABILITY、CODEWHALE_SANDBOX_SHANNON_SYNCCODEWHALE_SANDBOX_URLCODEWHALE_SANDBOX_API_KEY没有CODEWHALE_PREFER_BWRAP覆盖项——使用顶层prefer_bwrap配置键。这些环境变量的读取集中在 crates/tui/src/config.rs含CODEWHALE_SANDBOX_URL对DEEPSEEK_SANDBOX_URL的向后兼容回退以及 crates/config/src/lib.rs 的启动模式解析。此外每次真实进入 Seatbelt/Bubblewrap 包裹的执行还会向子进程注入CODEWHALE_SANDBOX值seatbelt/bwrap与DEEPSEEK_SANDBOX环境标记供工具与脚本感知自身处境。诊断与失败归因只认真实证据codewhale setup --status、codewhale doctor、codewhale doctor --json与diagnostics工具会报告在解析后的 bubblewrap 偏好下、本地实际可用的包装器机器可读实现见 crates/tui/src/tools/diagnostics.rs。即便报告了包装器单条命令仍可能在策略不请求沙箱时绕过它。在 Linux 上仅仅发现沙箱相关 syscall 或源码模块不会让sandbox_available变为真——可用性是选中 探测通过的双重结果。拒绝归因刻意保持保守Seatbelt 使用其包装器专属的拒绝模式Bubblewrap 的设置错误必须以bwrap:前缀开头才能判定来自 bwrap 文件系统视图的只读文件系统错误也可定位边界子命令的泛化Permission denied或Operation not permitted本身不足以证明是 Codewhale 的沙箱拦了它未沙箱命令的失败永远不会被标记为沙箱拒绝。对应的was_denied/denial_messagemod.rs正是这样实现的SandboxType::None恒返回 falsebwrap 分支只认bwrap:行与Read-only file system提示Seatbelt 分支匹配file-write/network特征。策略层的posture_label系列policy.rs还会结合真实的沙箱强制状态LocalOs/Unavailable/ExternalBackend输出人可读的姿态标签避免配置说沙箱了、实际没有包装器这类误导。已知局限任何沙箱都有边界docs/SANDBOX.md 用一节明示沙箱的局限这些同样应当成为使用者设计工作流时的前提可用性在启动前检查选中的包装器仍可能因宿主策略、容器限制或探测后的竞态而失败Bubblewrap 会忽略缺失、非目录或 canonicalize 到/的可写根路径也可能在策略解析与包装器启动之间消失Seatbelt profile 是运行时生成的必须针对它要支持的命令实测Windows 当前没有可宣传的本地包装器外部沙箱后端的强度上限就是它所配置的服务没有任何沙箱能抵御内核漏洞或全部的资源耗尽与侧信道攻击。实现参考索引本文涉及的实现与文档证据均可直接进入仓库继续研读crates/tui/src/sandbox/mod.rs — 诚实选择逻辑、PUBLIC_SANDBOX_BACKENDS公开能力标记、SandboxManager/CommandSpec/ExecEnv核心类型crates/tui/src/sandbox/seatbelt.rs — macOS Seatbelt 包装器与可用性探测crates/tui/src/sandbox/bwrap.rs — Linux 可选 bubblewrap 包装器crates/tui/src/sandbox/policy.rs —SandboxPolicy各档位、可写根与网络访问语义crates/tui/src/sandbox/process_hardening.rs — Linux 父进程加固与CODEWHALE_NO_NEW_PRIVScrates/tui/src/sandbox/backend.rs — 外部后端选择与SandboxBackendtraitcrates/tui/src/sandbox/opensandbox.rs 与 crates/tui/src/sandbox/shannon.rs — 两个外部后端的实现crates/tui/src/tools/diagnostics.rs — 机器可读诊断输出docs/SANDBOX.md — 本文主体文档docs/AUTHORIZATION_ORDER.md — 进入执行边界前的策略审批层级贯穿全文的设计主线值得最后再强调一次Codewhale 在沙箱这个最容易自我吹嘘的领域选择了克制与诚实——源码模块存在不等于沙箱生效探测失败就如实上报none泛化权限错误不冒充沙箱拒绝。使用者在评估任何终端编码代理时都可以用这套证据标准去追问它宣传的隔离是否真的接线进了命令启动路径【免费下载链接】CodewhaleOpen-source coding agent for your terminal, built in Rust and on a journey of continuous community improvement. Issues and PRs welcome.项目地址: https://gitcode.com/GitHub_Trending/de/Codewhale创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考