|
| 1 | +# MisakaX Sandbox 技术选型(ADR) |
| 2 | + |
| 3 | +> **用途:** 固化 MisakaX 跨平台 Agent 沙箱的技术决策、边界、适配策略和上线门槛。 |
| 4 | +> **受众:** 架构师、安全、Rust/Python、构建与发布维护者。 |
| 5 | +> **最后审阅 / Last reviewed:** 2026-08-01 |
| 6 | +> **状态:** Proposed;需完成三个平台的 Spike Gate 后转为 Accepted。 |
| 7 | +> **依据:** [`CROSS_PLATFORM_DESKTOP_SANDBOX_RESEARCH.md`](../research/CROSS_PLATFORM_DESKTOP_SANDBOX_RESEARCH.md)。 |
| 8 | +
|
| 9 | +--- |
| 10 | + |
| 11 | +## ADR-001:采用统一 Sandbox Broker 和平台适配器 |
| 12 | + |
| 13 | +### 1. 决策 |
| 14 | + |
| 15 | +MisakaX 采用**端口-适配器架构**实现沙箱: |
| 16 | + |
| 17 | +- Rust Core 持有统一 `SandboxPolicy`、`SandboxBroker`、审批、审计、能力探测和会话生命周期。 |
| 18 | +- 独立的、窄职责 `misakax-sandbox-runner` 建立 OS 安全边界;主 Tauri 进程不直接拼接不可信 Shell 命令。 |
| 19 | +- Linux 首选 Bubblewrap + namespaces + seccomp,Landlock 作为补充/受限回退。 |
| 20 | +- macOS 首选每命令 Seatbelt profile + 独立 runner + 本地网络 Broker。 |
| 21 | +- Windows 首选一次性提权设置、专用 online/offline 沙箱账户、write-restricted token、ACL、防火墙和 Job Object。 |
| 22 | +- Docker/Podman 实现为可选 `ContainerSandboxProvider`,不作为基础安装的强依赖。 |
| 23 | +- Wasmtime 保留为未来受控 Skill 插件 Provider,不承载通用 Shell。 |
| 24 | +- 用户主动 PTY 终端由 `TerminalManager` 管理,默认标记为本机权限;Agent 自动命令必须调用 `SandboxBroker`。 |
| 25 | + |
| 26 | +### 2. 决策驱动因素 |
| 27 | + |
| 28 | +- 三平台必须可运行,但不要求底层机制相同。 |
| 29 | +- 保持现有用户项目工具链、工作区和 Tauri 桌面体验。 |
| 30 | +- 安全策略要可测试、可解释、可审计、可升级,不散落在 React/Python/命令拼接中。 |
| 31 | +- 能逐步从当前逻辑路径守卫迁移,不进行一次性重写。 |
| 32 | +- 能为 Skills、MCP Server、Shell、扫描器和未来自动化共用执行边界。 |
| 33 | + |
| 34 | +### 3. 未采用的主方案 |
| 35 | + |
| 36 | +| 方案 | 不作为主方案的原因 | |
| 37 | +|---|---| |
| 38 | +| 只用 Docker Desktop | 依赖虚拟化/大体积运行时;三平台安装和许可成本高;宿主工具链体验差 | |
| 39 | +| 只用 Windows Sandbox | 不支持 Windows Home;工作区/工具桥接和多会话体验不符合桌面 Agent | |
| 40 | +| Windows AppContainer/LPAC | 对开放式 Git/Python/Node/编译器工作流兼容性不足 | |
| 41 | +| 只用 Anthropic Sandbox Runtime | 当前只覆盖 macOS/Linux,无法完成 Windows 要求 | |
| 42 | +| 直接 Shell 调用 Codex CLI | 上游 CLI 协议和实现会变化;产品不能依赖用户安装或登录另一产品 | |
| 43 | +| 只用 Wasmtime | 无法透明运行任意本机命令和现有 Skill 脚本 | |
| 44 | +| 路径 guard + proxy 环境变量 | 可被直接系统调用绕过,不构成 OS 安全边界 | |
| 45 | + |
| 46 | +## 4. 目标架构 |
| 47 | + |
| 48 | +```mermaid |
| 49 | +flowchart TB |
| 50 | + UI["React:策略、审批、状态、审计"] --> IPC["窄 Tauri IPC"] |
| 51 | + PY["Python Agent / Brokered Backend"] --> BRIDGE["带会话令牌的本地执行桥"] |
| 52 | + IPC --> APP["Rust Application Services"] |
| 53 | + BRIDGE --> APP |
| 54 | + APP --> SB["SandboxBroker"] |
| 55 | + APP --> AB["ApprovalBroker"] |
| 56 | + APP --> AUDIT["SecurityAuditLog"] |
| 57 | + SB --> POLICY["SandboxPolicy + Capability Probe"] |
| 58 | + SB --> LINUX["LinuxSandboxProvider"] |
| 59 | + SB --> MAC["MacSandboxProvider"] |
| 60 | + SB --> WIN["WindowsSandboxProvider"] |
| 61 | + SB -. optional .-> OCI["ContainerSandboxProvider"] |
| 62 | + LINUX --> RUNNER["misakax-sandbox-runner"] |
| 63 | + MAC --> RUNNER |
| 64 | + WIN --> SETUP["misakax-sandbox-setup"] |
| 65 | + WIN --> RUNNER |
| 66 | + RUNNER --> CHILD["Shell / Skill / MCP 子进程树"] |
| 67 | + CHILD --> NET["NetworkBroker:deny by default"] |
| 68 | +``` |
| 69 | + |
| 70 | +### 4.1 依赖方向 |
| 71 | + |
| 72 | +```text |
| 73 | +React UI |
| 74 | + -> IPC DTO |
| 75 | + -> Rust application service |
| 76 | + -> sandbox domain ports / policy |
| 77 | + -> platform adapters / database / runner protocol |
| 78 | +
|
| 79 | +Python Agent |
| 80 | + -> BrokeredWorkspaceBackend |
| 81 | + -> authenticated loopback bridge |
| 82 | + -> 同一个 Rust application service |
| 83 | +``` |
| 84 | + |
| 85 | +平台 API、命令行参数、Windows token、Seatbelt profile 和 Bubblewrap 参数不得出现在 UI、Skills 或 Agent 编排层。 |
| 86 | + |
| 87 | +## 5. 核心契约 |
| 88 | + |
| 89 | +以下为概念接口;实现时按仓库当时锁定的 Rust 版本调整,不在规划阶段锁死第三方小版本。 |
| 90 | + |
| 91 | +```rust |
| 92 | +pub trait SandboxProvider: Send + Sync { |
| 93 | + fn capabilities(&self) -> SandboxCapabilities; |
| 94 | + async fn prepare(&self, request: PrepareRequest) -> Result<PreparedSandbox>; |
| 95 | + async fn spawn(&self, request: SpawnRequest) -> Result<SandboxProcess>; |
| 96 | + async fn terminate_tree(&self, process_id: SandboxProcessId) -> Result<()>; |
| 97 | +} |
| 98 | + |
| 99 | +pub struct SandboxPolicy { |
| 100 | + pub mode: SandboxMode, |
| 101 | + pub filesystem: FilesystemPolicy, |
| 102 | + pub network: NetworkPolicy, |
| 103 | + pub environment: EnvironmentPolicy, |
| 104 | + pub resources: ResourcePolicy, |
| 105 | + pub approvals: ApprovalPolicy, |
| 106 | +} |
| 107 | + |
| 108 | +pub enum SandboxMode { |
| 109 | + ReadOnly, |
| 110 | + WorkspaceWrite, |
| 111 | + FullAccess, |
| 112 | +} |
| 113 | +``` |
| 114 | + |
| 115 | +必须使用结构化 argv 和 cwd,不允许把前端字符串直接传给 platform shell 做二次解析。确需 Shell 语法时,由明确的 `ShellCommand` 类型和平台 adapter 处理,并记录完整来源。 |
| 116 | + |
| 117 | +## 6. 默认策略 |
| 118 | + |
| 119 | +### 6.1 `read-only` |
| 120 | + |
| 121 | +- 工作区和系统可读范围按平台最小映射;无任何持久写路径,仅会话临时目录可写。 |
| 122 | +- 网络关闭。 |
| 123 | +- 适合安全扫描、只读分析和未知 Skill 预览。 |
| 124 | + |
| 125 | +### 6.2 `workspace-write`(Agent 默认) |
| 126 | + |
| 127 | +- 当前会话工作区可写。 |
| 128 | +- `.git`、`.misakax`、`.codex`、`.agents`、凭据文件和用户配置默认只读/不可见。 |
| 129 | +- 网络默认关闭;按域名和一次/会话范围审批。 |
| 130 | +- 环境变量使用 allowlist,移除云 Key、SSH、浏览器和代理凭据;`inherit_env=false`。 |
| 131 | +- 限制进程数、CPU、内存、文件大小、打开句柄和执行时长。 |
| 132 | + |
| 133 | +### 6.3 `full-access` |
| 134 | + |
| 135 | +- 仅由用户在当前操作显式批准,展示影响范围和过期时间。 |
| 136 | +- 审计事件必须包含触发消息、命令摘要、工作区、批准时间和理由。 |
| 137 | +- 不得被 Skill manifest 或模型输出自行请求为永久默认。 |
| 138 | + |
| 139 | +## 7. 平台映射 |
| 140 | + |
| 141 | +| 策略能力 | Linux | macOS | Windows | |
| 142 | +|---|---|---|---| |
| 143 | +| 根只读 | Bubblewrap `ro-bind` | Seatbelt deny/write rules | write-restricted token + ACL | |
| 144 | +| 工作区可写 | 精确 bind | profile allow path | sandbox SID ACL | |
| 145 | +| 子路径再保护 | 重新 ro-bind/deny | 更具体 deny | deny ACL/受限 SID 策略 | |
| 146 | +| 网络默认拒绝 | network namespace + seccomp | Seatbelt + Broker | offline 用户防火墙 | |
| 147 | +| 域名允许 | TCP/UDS Broker | localhost/UDS Broker | online 身份 + Broker/防火墙 | |
| 148 | +| 进程树 | PID namespace/cgroup/kill | process group/runner | Job Object | |
| 149 | +| 权限准备 | 通常无需 root,探测 userns | 签名/系统版本验证 | 一次性 UAC setup | |
| 150 | +| 严格失败 | 不支持 userns 时拒绝 | profile 失败时拒绝 | setup/规则不完整时拒绝 | |
| 151 | + |
| 152 | +“兼容模式”只能在用户明确选择后使用,并在每次会话显示持续警告;它不能自动取代严格模式。 |
| 153 | + |
| 154 | +## 8. Python Sidecar 集成决策 |
| 155 | + |
| 156 | +### 8.1 首期 |
| 157 | + |
| 158 | +- 新建 `BrokeredWorkspaceBackend`,文件和 Shell 工具通过带随机会话令牌的 loopback bridge 调用 Rust。 |
| 159 | +- Rust 校验会话、工作区、工具、策略和批准,Shell 交给 Sandbox Broker。 |
| 160 | +- 停止对 `LocalShellBackend` 使用 `inherit_env=true`;除测试外不得直接作为生产 backend。 |
| 161 | +- Skill 目录以**激活视图**挂载,只包含当前允许且启用的 Skill;禁用/过期 Skill 不可见。 |
| 162 | + |
| 163 | +### 8.2 强化阶段 |
| 164 | + |
| 165 | +- 将执行 worker 与 FastAPI 控制面分离,评估把执行 worker 整体放入沙箱。 |
| 166 | +- 模型凭据由宿主侧 Model Gateway 代持;worker 获得范围受限的 loopback token,避免把 API Key 注入沙箱。 |
| 167 | +- MCP 进程启动统一接入 Sandbox Broker;远程 MCP 连接由网络策略管理。 |
| 168 | + |
| 169 | +## 9. Tauri 与终端安全决策 |
| 170 | + |
| 171 | +- 删除主 WebView 的通用 `shell:allow-execute/spawn/stdin-write/kill` 权限,终端和 Agent 使用独立窄 IPC。 |
| 172 | +- 收窄 FS/HTTP capability 和 scope,显式 deny 敏感 WebView 数据目录。 |
| 173 | +- 配置 CSP:仅允许本地打包脚本/样式,禁止远端和动态代码;开发环境例外与生产配置分离。 |
| 174 | +- 终端使用 `@xterm/xterm` + Fit addon,Rust 侧优先验证 `portable-pty 0.9.x`;依赖版本以实施时 `package.json`/`Cargo.toml` 锁定为准。 |
| 175 | +- 终端会话不复用 Sandbox Process ID;类型层面区分 `LocalTerminalSession` 和 `SandboxExecution`。 |
| 176 | + |
| 177 | +## 10. 数据与审计 |
| 178 | + |
| 179 | +至少记录: |
| 180 | + |
| 181 | +- `execution_id`、会话、工作区、请求来源(Agent/Skill/MCP/User Terminal)。 |
| 182 | +- 策略版本、provider、能力探测结果、writable/readable/denied roots 的摘要 hash。 |
| 183 | +- 命令 argv 的安全摘要、cwd、开始/结束、退出码、终止原因和资源用量。 |
| 184 | +- 网络请求目标、策略命中、用户批准和持续时间。 |
| 185 | +- 沙箱 setup/repair/uninstall 事件和平台组件版本。 |
| 186 | + |
| 187 | +日志不得默认存储环境变量值、凭据、完整终端输出或用户文件内容;命令参数中疑似 Secret 应脱敏。 |
| 188 | + |
| 189 | +## 11. Spike Gate:ADR 转为 Accepted 的条件 |
| 190 | + |
| 191 | +三个平台都必须通过以下门槛,不能只在 Windows 开发机通过后宣称跨平台完成: |
| 192 | + |
| 193 | +1. 工作区内创建/修改成功,工作区外写入失败。 |
| 194 | +2. `.git` 保护策略按预期失败;批准后可在限定操作中放行。 |
| 195 | +3. 读取 SSH/云凭据路径失败或不可见。 |
| 196 | +4. 直接 Socket、DNS、HTTP、Git/SSH 在 offline 策略下均失败。 |
| 197 | +5. 允许域名可用,未允许域名和重定向/解析绕过失败。 |
| 198 | +6. 子进程、后台进程和崩溃后进程树被回收。 |
| 199 | +7. Python、Node、Git、Rust 构建的代表性命令兼容。 |
| 200 | +8. 路径含空格、Unicode、符号链接/junction、Git worktree 和长路径用例通过。 |
| 201 | +9. provider 不可用时严格模式 fail closed,UI 给出可操作诊断。 |
| 202 | +10. 安装包签名、升级、修复和卸载不会遗留专用账户、无效防火墙或危险 ACL。 |
| 203 | + |
| 204 | +## 12. 已知风险与缓解 |
| 205 | + |
| 206 | +| 风险 | 缓解 | |
| 207 | +|---|---| |
| 208 | +| Windows setup 复杂、需 UAC | 独立 setup helper;幂等校验、修复和卸载;明确用户说明 | |
| 209 | +| Seatbelt 接口/系统版本差异 | 支持版本矩阵、签名 helper、每版本实机测试、严格失败 | |
| 210 | +| Bubblewrap/userns 被发行版禁用 | 预检、捆绑受审版本、Landlock 能力回退、兼容模式不静默 | |
| 211 | +| 网络 Broker 成为高价值边界 | 最小协议、DNS/重定向校验、无凭据日志、模糊测试和独立审计 | |
| 212 | +| 沙箱影响构建速度 | 缓存只读映射、会话复用、基准预算;不放宽安全边界换性能 | |
| 213 | +| 第三方上游快速变化 | 内部稳定接口、固定版本/SBOM、升级安全回归,不依赖用户安装 CLI | |
| 214 | + |
| 215 | +## 13. 关联文档 |
| 216 | + |
| 217 | +- [`CROSS_PLATFORM_DESKTOP_SANDBOX_RESEARCH.md`](../research/CROSS_PLATFORM_DESKTOP_SANDBOX_RESEARCH.md) |
| 218 | +- [`WORKSPACE_SKILLS_SECURITY_ARCHITECTURE.md`](./WORKSPACE_SKILLS_SECURITY_ARCHITECTURE.md) |
| 219 | +- [`SANDBOX_IMPLEMENTATION_PLAN.md`](../planning/SANDBOX_IMPLEMENTATION_PLAN.md) |
| 220 | +- [`SKILL_SECURITY_SCANNING_RESEARCH.md`](../research/SKILL_SECURITY_SCANNING_RESEARCH.md) |
0 commit comments