Skip to content

feat(sandbox): Windows 免管理员 workspace-write 沙箱后端 - #518

Open
coder-hhx wants to merge 2 commits into
feature/rust-embed-cubesandboxfrom
feature/windows-sandbox
Open

feat(sandbox): Windows 免管理员 workspace-write 沙箱后端#518
coder-hhx wants to merge 2 commits into
feature/rust-embed-cubesandboxfrom
feature/windows-sandbox

Conversation

@coder-hhx

@coder-hhx coder-hhx commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

叠加 PR:base 是 #505 的分支 feature/rust-embed-cubesandbox,不是 main。等 #505 合入后本 PR 的 base 会自动回落到 main。这样 Windows 代码不拖累基础沙箱 PR 的合入节奏。

Closes #520

概述

#505 的基础 OS 沙箱之上,实现 Windows 端免管理员写围栏,替换原先 sandbox.rs windows 分支的 unsupported 桩。免管理员、零配置、fail-closed,语义为 workspace-write(广读、写限工作区+临时目录)。

sandbox 模式在 Windows 放开;sandboxOffline(断网+敏感目录读掩蔽)免管理员无法实现,保持 fail-closed 禁用

机制(Option A:自我再执行 launcher)

  • sandbox.rs windows wrap_command 返回 (current_exe, ["__sandbox_exec","--write-root",root,"--",program,args...])
  • windows_sandbox.rs::run_sandbox_launcher_if_requested() 作为 run() 首行(Tauri 初始化前)识别 marker:
    1. (OI)(CI) 继承写 ACE(合成 workspace SID)到 write_root + 工作区内临时目录
    2. WRITE_RESTRICTED 受限令牌(合成 SID 作 restricting SID ⇒ 广读、写受限)
    3. CreateProcessAsUserW 拉真实 shell,WaitForSingleObject(INFINITE) 后透传退出码
    4. 任何失败退 127,绝不静默直跑
  • 进程树 kill:launcher 阻塞等待使 tracked PID 存活,taskkill /T 沿完整 PPID 链级联;额外 Job Object KILL_ON_JOB_CLOSE 兜底 ⇒ 多一跳不破坏 cancel/kill 语义。

能力契约 / 前端门控

  • SandboxCapability 新增 network_control: boolean,Rust snake_case → 双端 TS adapter 贯通
  • windows capability() 返回 supported:true, mechanism:"restricted-token", network_control:false;mac/Linux 保持 network_control:true
  • CommandSafetyModeSelector 改为按 network_control 单独禁用 sandboxOffline,sandbox 仍可用;i18n 新增 chat.safety.sandboxOfflineUnavailable(en/zh),移除过期的 sandboxUnavailableWindows

截图 / preview

说明:前端门控在 Windows 能力契约(network_control:false)下的实际渲染。

命令执行方式下拉 —— 沙箱 可选并被选中(✓);沙箱·断网 因 Windows 免管理员方案无法断网而 fail-closed 置灰,附提示「当前平台不支持断网沙箱(Windows 免管理员方案无法断网)」:

Windows 命令执行方式下拉

输入框已应用沙箱 —— 选中后 composer 显示绿色「沙箱」药丸:

输入框沙箱药丸

安全加固(采纳两轮 review)

  • resolve_program_in_path:lpApplicationName 用 PATH 内绝对路径解析,工作区 cwd 绝不被搜索(挡 planted-binary 向量),argv[0] 保留原始命令名
  • ensure_write_ace 跳过 null-DACL(避免留下 deny-all 空 DACL)
  • setup_fenced_temp 拒绝 reparse point(挡 junction/symlink 逃逸)
  • inheritable_std_handlesINVALID_HANDLE_VALUE 守卫

验证

  • ✅ Windows 编译:probe crate cargo check --target x86_64-pc-windows-msvc 零错误(#[cfg(windows)] FFI 全类型检查通过)
  • ✅ Rust host:cargo test --lib sandbox 12/12(launcher arg round-trip / 合成 SID / 命令行引用 / resolve_program_in_path)
  • ✅ 前端:GUI 715 / WebUI 578 测试(含 i18n parity)+ 双端 tsc --noEmit + biome 全绿

⚠️ 合入前必读:未做真机验证

token/ACE/CreateProcessAsUserW 这段 unsafe FFI 仅到编译级验证(Tauri crate 无法在 macOS 上交叉编译,ring/sqlite 需 MSVC)。从未在真 Windows 上功能测试,写围栏是否真的生效、广读是否真的不破工具链,都还是未知。

合入前需在真 Windows 机器上验证:工作区内写成功 / 区外写被拒 / 工具链目录可读 / sandboxOffline 置灰。因为特性 opt-in + fail-closed,落地代码在没人主动选 sandbox 前不改变任何行为。

残留(不在本 PR)

  • `bInheritHandles=TRUE` 目前是 blanket 继承;STARTUPINFOEX+PROC_THREAD_ATTRIBUTE_HANDLE_LIST 精确化待真机验证后再做(已在模块 doc 注明)
  • 真正的 Windows 断网层(Codex 路线:Job Object + WFP + 提权装 dedicated user)是后续独立工作

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

PR governance checks passed. Awaiting human review.

@StackCairn
StackCairn marked this pull request as draft August 16, 2026 15:10
在基础 OS 沙箱之上实现 Windows 端写围栏,替换原先的 unsupported 桩。
免管理员、零配置、fail-closed,语义为 workspace-write。

机制(Option A,自我再执行 launcher):
- sandbox.rs windows `wrap_command` 返回 (current_exe,
  ["__sandbox_exec","--write-root",root,"--",program,args...])
- windows_sandbox.rs `run_sandbox_launcher_if_requested()` 作为 run()
  首行(Tauri 初始化前)识别 marker:盖 (OI)(CI) 继承写 ACE(合成
  workspace SID)+ 建 WRITE_RESTRICTED 受限令牌(合成 SID 作 restricting
  SID ⇒ 广读、写限工作区)+ CreateProcessAsUserW 拉真实 shell,
  WaitForSingleObject(INFINITE) 后透传退出码;任何失败退 127,绝不直跑。
- Job Object KILL_ON_JOB_CLOSE 兜底;launcher 阻塞等待使 taskkill /T
  沿完整 PPID 链级联,进程树 kill 不受多一跳影响。

能力/门控:
- capability() 返回 supported:true, mechanism:"restricted-token",
  network_control:false。sandbox 模式在 Windows 放开;sandboxOffline
  (断网 + 读掩蔽免管理员做不到)保持 fail-closed 禁用,执行层对
  !allow_network 直接报错兜底(设置可能自 macOS 同步)。
- 前端 CommandSafetyModeSelector 改为按 network_control 单独禁用
  sandboxOffline,sandbox 仍可用;i18n 增 sandboxOfflineUnavailable。
- SandboxCapability 增 network_control:boolean,Rust→双端 TS adapter 贯通。

安全加固(采纳两轮 review):
- resolve_program_in_path:lpApplicationName 用 PATH 内绝对路径解析,
  工作区 cwd 绝不被搜索(挡 planted-binary),argv[0] 保留原名。
- ensure_write_ace 跳过 null-DACL(避免 deny-all)、setup_fenced_temp
  拒绝 reparse point、INVALID_HANDLE_VALUE 守卫。

验证:probe crate cargo check --target x86_64-pc-windows-msvc 零错误;
host cargo test --lib sandbox 12/12;GUI 715 / WebUI 578 前端测试 + 双端
tsc + biome 全绿。⚠️ token/ACE/CreateProcessAsUserW 的 unsafe FFI 仅编译
级验证,从未在真 Windows 上功能测试,合入前需真机验证边界。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coder-hhx
coder-hhx force-pushed the feature/windows-sandbox branch from a12797a to 8d70769 Compare August 16, 2026 16:37
…518

沙箱可选并被选中(✓),沙箱·断网因 Windows 免管理员方案无法断网而 fail-closed 禁用。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coder-hhx
coder-hhx marked this pull request as ready for review August 16, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant