[Feature] workspace-write 沙箱:支持可配置的额外可写缓存目录(~/.cache),跨 workspace 复用依赖缓存 #3527
Replies: 1 comment
|
这个需求成立,但建议不要把
一个更窄的第一版可以只支持显式的单用途目录,例如: sandbox:
caches:
- id: npm
hostPath: /var/cache/dsh/npm
mountPath: /cache/npm
sharing: profile再由 profile 注入 建议验收矩阵至少覆盖:bwrap/Landlock/Seatbelt/Windows ACL;cache 内写成功;相邻目录写失败;symlink 逃逸失败;两个 workspace 的共享策略符合配置; 披露:我维护 SandBase Harness,也在做 local/Docker/Kubernetes/self-hosted sandbox 边界。我们的经验是把 workspace、上传资源和持久状态分成明确资源类型,比暴露任意额外宿主可写根更容易审计。 Published follow-up: I turned this proposal into a source-backed implementation and acceptance guide, verified against rc.8 commit |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
dsh生成的isuse:
问题概述
workspace-write模式下,整个home目录(~/.cache、~/.npm、~/.go、~/.config、~/.local等)被设为只读;唯一可写的是当前 workspace 与/tmp。workspace 按工作目录/项目分配(见
~/.dsh/sessions/下各自独立的--<user>-<dir>--会话目录),换项目即换 workspace。于是 npm / cargo / go / pip 等依赖缓存无法跨 workspace 复用,每次进入新项目都要重新拉全量依赖,反复消耗网络流量与时间。期望:通过配置(而非改源码)把一个跨 workspace 持久保留的共享目录(典型
~/.cache)追加进workspace-write白名单。当前行为
期望行为
在配置中新增可追加的额外可写根,使
~/.cache等目录跨 workspace、跨会话可写且持久,供各包管理器的默认缓存路径(XDG_CACHE_HOME/npm_config_cache/GOMODCACHE/CARGO_HOME/PIP_CACHE_DIR)复用。相关代码位置(已核实)
可写集合目前硬编码在共享函数
writableRoots():@deepseek-ai/dsh-sandbox/lib/index.js第 154–161 行:dsh-fs-sandbox(文件工具)与dsh-sandbox-local(bash/Seatbelt 运行器)共同消费,故在此追加即对 bash 与 fs 同时生效。当前相关配置 schema 没有追加额外可写根的字段:
SandboxPolicyService.Config(dsh-sandbox-policy/lib/index.js):{ mode, workspaceRoot }PermissionPresetService.Config(dsh-permission-presets/lib/index.js):{ presets, defaultPreset }类型
SandboxExecutionPolicy(dsh-sandbox/lib/types/index.d.ts第 27–39 行)目前仅mode/workspaceRoot/ 可选sessionId。提议补丁(最小实现)
1) 类型
SandboxExecutionPolicy—dsh-sandbox/lib/types/index.d.tsexport interface SandboxExecutionPolicy { /** The file-effect mode this execution runs under. */ mode: SandboxMode; /** Absolute root directory `workspace-write` may write under. */ workspaceRoot: string; + /** + * Optional extra absolute roots `workspace-write` may additionally write + * under (e.g. a shared cross-workspace cache directory such as ~/.cache), + * surfaced through configuration instead of being hardcoded. + */ + extraWritableRoots?: readonly string[]; /** ... 原有 sessionId 字段保持不变 ... */ }2) 共享可写清单 —
dsh-sandbox/lib/index.js的writableRoots()function writableRoots(policy) { if (policy.mode !== "workspace-write") return []; return [...new Set([ policy.workspaceRoot, "/tmp", - tmpdir() + tmpdir(), + ...(policy.extraWritableRoots ?? []) ].map(canonicalPath))]; }3) 配置暴露 —
dsh-sandbox-policy/lib/index.jsstatic Config = z.object({ mode: z.union(["read-only", "workspace-write", "danger-full-access"]) .default("read-only"), - workspaceRoot: z.string() + workspaceRoot: z.string(), + extraWritableRoots: z.array(z.string()).default([]) });并在
resolve()返回的对象中透传:resolve(request = {}) { const { session } = request; return { mode: request.mode ?? (session === void 0 ? void 0 : this.overrideOf(session)) ?? this.defaultMode, workspaceRoot: resolveWorkspaceRoot(session?.header.cwd ?? this.workspaceRoot), + extraWritableRoots: this.extraWritableRoots, // 来自配置 ...(session === void 0 ? {} : { sessionId: session.id }) }; }(构造器内
this.extraWritableRoots = config.extraWritableRoots.map(resolveWorkspaceRoot);,复用现有 canonical/realpath 逻辑。)4) 权限预设(可选,让 preset 也能绑定额外根)—
dsh-permission-presets/lib/index.jspresets: z.dict(z.object({ sandbox: z.union(SANDBOX_MODES).required(), approval: z.union(APPROVAL_POLICIES).required(), name: z.string(), description: z.string(), + extraWritableRoots: z.array(z.string()).optional() // 追加 })),使用示例
随后设置:
备选 / 可接受的替代方案
若出于安全不愿对持久化home目录开白名单,可考虑:
/tmp提升为跨会话持久,并显式支持包管理器 cache 目录。环境
@deepseek-ai/dsh-sandbox0.1.0-rc.8workspace-writewrite/bash尝试写入~/.cache或home目录,报Read-only file systemAll reactions