🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI
广告☁️ 云服务器特惠阿里云首购 8 折 · 腾讯云合作特惠
DeepSeek Harness Hub
← 返回列表

DWJZ/dsh-allow

DeepSeek 客户端兼容 / 相关生态spec-screened扫描:中风险在 GitHub 查看 ↗
⚠ 装前注意

description: "dsh-allow:按路径给 DSH shell 调用授予 read / write /…

基本兼容但装前注意:未发布到 npm registry,仅可从源码安装 · 最近上游提交 2026/9/21 · 已提供中文文档

按路径与能力(read/write/create/delete/execute)授予 DSH shell 调用的文件权限,并在进程真正运行其下的 macOS Seatbelt profile 里强制;会话里的「审批」标签页显示每次判定是规则、自动复核还是人拍的板。 / Filesystem permissions for DSH shell calls, granted per path and capability instead of per command name, enforced in the process sandbox, with an Approvals tab showing which layer decided each call.

综合分
30.7
GitHub 分
30.7
用户评分
—
★ Stars
1
周下载量
—
兼容 / 相关生态插件(非 dsh 原生,请按其对应运行时安装)
git clone https://github.com/DWJZ/dsh-allow.git
信任档位:仅索引本站尚未对其实装验证,仅收录元数据
是什么
生态插件(可安装,未声明 dsh 能力)
装得上吗
静态安装检查有提示项,装前建议看一眼 README
安全吗
本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
还在维护吗
活跃:最近一次提交在 4 天前

档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →

数据截至 2026/9/22(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查⚠ 装前注意

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-allow(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

未发布到 npm registry,仅可从源码安装

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/22 00:10:02

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

由 DeepSeek 最新模型翻译生成
description: "dsh-allow:按路径给 DSH shell 调用授予 read / write / create / delete / execute 文件权限,并在进程沙箱里真正强制;卡片上给「拒绝 / 允许一次 / 总是允许」,另有「审批」标签页显示每次判定是谁拍的板。"

dsh-allow

给 DSH 加一层文件系统权限。判断依据是这条命令需要哪些文件能力,而不是命令名听起来多危险;同一份策略还会被编译成进程真正运行其下的 profile —— 所以它启动的子进程、以及命令行里根本没露出来的代码,同样受这份策略约束。

cat README.md                  →  allow    (read inside the workspace)
cat ~/.ssh/id_ed25519          →  refused  (user data is fenced, whoever reads it)
python3 -c 'open("~/.ssh/id_ed25519").read()'
→  refused by the kernel, not found by the parser
echo x > out.md                →  allow    (create inside the workspace)
rm -rf build                   →  prompt   (delete is not granted in the workspace)
python3 -c 'os.remove(…)'      →  refused by the kernel while delete is ungranted
gh pr list                     →  prompt   (execute is not granted for that binary)
echo x > /Users/me/other/o     →  prompt   (create outside the workspace)
echo x > ~/.dsh/dsh-allow.json →  refused  (the permission store is never writable)

上例逐条读作:工作区内的 cat 允许;~/.ssh/id_ed25519 一律拒绝, 谁读都一样;python3 -c 里的读取由内核拒绝, 而不是被解析器发现;工作区内写入允许;工作区默认不授予 delete, 所以 rm -rf build 询问;delete 未授权时 os.remove 由内核拒绝;gh pr list 因为那个二进制没有 execute 而询问;工作区外的写入询问;权限库永远不可写, 所以写它一律拒绝。

挂在哪一层

model writes a command
↓
bash / pwsh tool call
↓
tools/pre-execute  ← this plugin: parse → derive effects → resolve (path, capability)
↓ allow                    ↓ prompt                     ↓ refuse
ctx.sandbox.confine        approval card: deny / always    no escalation
↓                      allow / allow once
Seatbelt profile compiled from the SAME rules
↓
the process tree (children, grandchildren, inline code)

这张图读作:模型写出命令 → bash / pwsh 工具调用 → 本插件在 tools/pre-execute 上解析、推导文件效果、逐条解析 (路径, 能力);允许就交给 ctx.sandbox.confine, 询问就出审批卡片(拒绝 / 总是允许 / 允许一次), 拒绝则不能提权;进程跑在同一套规则编译出的 Seatbelt profile 下, 整棵进程树(子进程、孙进程、内联代码)都受它约束。

tools/pre-execute 是文档化的策略接缝,也是 shell 命令唯一的路径。插件不替换 sandbox provider:它包住已注册 provider 的 confine,把由当前有效策略编译出的 profile 交给它,自己处理不了的平台原样委托回去。tools/post-execute 负责把「允许一次」用掉,另有一道针对写文件工具的小闸门拦下权限库。

能力与规则

模型里有五种文件能力,一条规则只为某个路径授予其中若干种:

| 能力 | 含义 |
| --- | --- |
| read | 读文件、列目录 |
| write | 修改已有文件(内容、权限位、属主、时间) |
| create | 新建文件或目录 |
| delete | unlink / remove / rmdir / rename 移走 |
| execute | 把某个文件作为程序启动 |

execute 不等于「禁止运行任何脚本」:python3 foo.py 需要解释器的 execute 和 foo.py 的 read,因为 foo.py 本身没有被 execve。

持久规则是「路径 + 能力表」,不是命令行:

{
"version": 3,
"rules": [
{ "id": "f1", "path": "/Users/me/project/build", "recursive": true,
"access": { "write": true, "create": true, "delete": true },
"hits": 2, "createdAt": "2026-01-01T00:00:00.000Z" }
]
}

recursive: true 覆盖整棵子树;recursive: false 只覆盖这一个路径 —— 卡片上的「总是允许」对单个文件、单个二进制写的就是后者。

权限库不是 agent 能改的

规则文件与审计日志属于硬保护路径:write/create/delete 对任何人(包括用户规则)都拒绝,编译出的 profile 还会在所有授权之后再次拒绝。覆盖 $DSH_HOME/dsh-allow.json 与 $DSH_HOME/dsh-allow-audit.ndjson,配置指到哪就保护到哪。

同一道保护也加在写文件的工具上(write、edit、str_replace_editor),所以 agent 也不能用文件工具改写自己的规则;其它文件工具调用仍由 harness 自己的围栏负责。

harness home(~/.dsh)只读,shell 命令改不了「审判它的那套状态」。

clone 进 workspace 的仓库也无法给自己扩权:dsh-allow 不会读取 workspace 里的 .dsh-allow.json。仓库内容永远不该授予宿主机权限。

优先级

从高到低,某个能力第一次被某一级明确表态就按它执行;同一级内部,路径更具体的优先:

1. 平台保留路径 —— /System、/bin、/sbin、/usr(除 /usr/local)、/AppleInternal、/private/var/db、/dev,以及权限库本体,其 write/create/delete 对任何人(包括用户规则)都拒绝。
2. 显式规则 —— 规则文件(source: user)与本次获批调用的一次性授权(source: session)。
3. 平台基线 —— workspace、临时目录、harness home,以及 macOS 自身需要的系统路径。
4. 全局默认 —— 未授予。

路径按规范化后的绝对路径逐段比较:~、相对路径、.、..、以及符号链接祖先都会先解析,所以 /tmp/x 与 /private/tmp/x 是同一条路径,也无法用 ../ 绕过规则。每次判定会同时拿「写法路径」和「真实路径」去匹配,因此 /opt/homebrew/bin/gh 的授权和它指向的 Cellar 二进制的授权各自有效,又都不会打开 /opt/homebrew 其余部分。workspace 根自身也只是普通路径;一条规则绝不会覆盖只是前缀相同的兄弟目录(/w/build 不覆盖 /w/build-2)。

默认权限与平台基线

workspace 内:read、write、create、execute 允许,delete 默认拒绝。

临时目录五种全允许。系统路径给 macOS 必需的部分:/bin、/sbin、/usr/bin、/usr/sbin、/usr/lib、/usr/libexec、/System、/Library/Apple、/Library/Developer 给 read + execute;/etc、/var、/usr、/usr/share、/Library、/Applications、/dev、/opt/homebrew 只给 read。

home 目录之下还会额外放开两类:read + execute 给用户自己装的工具链(~/.nvm、~/.local、~/.cargo、~/.rustup、~/.bun、~/.deno、~/.volta、~/.pyenv、~/.rbenv、~/.sdkman、~/.go、~/.asdf、~/.gem、~/Library/pnpm),只给 read 给程序启动必需的少量配置(~/.gitconfig、~/.config/git、~/.gitignore)。这些路径是「程序要跑起来就非读不可」的,里面放的是程序与设置,不是凭据。

其余位置(workspace 之外的 $HOME、~/Documents、~/Library,以及其中所有凭据库)在你打开之前都是关着的,同时读围栏会扣住它们的内容。read-only 会话会把基线按沙箱模式收窄:workspace 只保留 read + execute,而且在只读会话里没有任何规则能把写权限加回来。

Homebrew 与符号链接可执行文件

Homebrew 的前缀不是默认可执行的:/opt/homebrew 可读,但 /opt/homebrew/* 不可执行,因此每个 Homebrew 二进制都要单独授权一次。对 execute /opt/homebrew/bin/gh 点「总是允许」只会写这一条路径,不会顺带覆盖第二个工具。

命令的文件效果怎么读出来

命令行用 tree-sitter + tree-sitter-bash 解析(结构:管道、列表、控制流、替换、重定向、here-document、函数体),然后按程序对参数做了什么,把每条简单命令变成 (路径, 能力):rm 删除操作数、mkdir 创建、mv 删源建目标、cp 读源建目标、grep 读路径参数但绝不把 pattern 当路径、sed -i 读写同一个文件、dd if= 读而 of= 建、curl -o 建。重定向也算效果:> 写或建、.v2.bak:那些规则描述的是命令,不是文件能力,无法翻译。

测试

npm test              # units, host wiring, card render, the audit ledger, and the real-sandbox suite
npm run test:unit     # policy, effects, enforcement, reviewer, decisions, audit ledger
npm run test:sandbox  # macOS Seatbelt integration (needs a host that can start sandbox-exec)

三条命令分别是:全部测试(单元 + 宿主接线 + 卡片渲染 + 审批记录 + 真实沙箱)、只跑单元、以及 macOS Seatbelt 集成(需要能启动 sandbox-exec 的宿主)。

test/reviewer.spec.mjs 注入模型,覆盖「告诉复核什么」(只有真实用户消息、分析过的权限、固定的 prompt)、各种答案形态(ALLOW、ASK、带围栏的 JSON、自然语言、未知判定、空答案),以及所有失败路径(没有路由、没有 LLM 服务、provider 抛错、终止错误块、超时、答案不合法)。test/smoke.mjs 覆盖闸门接线:ALLOW 走既有的按调用一次性授权、规则文件一个字节不改;ASK、复核失败、以及复核关闭时,都由卡片接管。

test/audit.spec.mjs 不依赖宿主,把审批记录端到端跑一遍:一次判定记成哪个来源、点名了哪些规则;不管卡片是从哪一半回答的,一次人工决定只产出一行;半行、别人的审批、认不出的 outcome 都不能产出记录;尾部读取的块边界、会话过滤与字节上限;以及审计路由的方法、loopback、条数与 baseline 规则。test/client.smoke.mjs 另外用 React 渲染这个标签页,断言一次调用一行,且字典之外没有任何文案。

test/sandbox.integration.mjs 跑的是真内核,覆盖:权限库对任何写入者都拒绝;rm / rmdir / rename / python -c 'os.remove' / node -e 'fs.rmSync' 全部被拒而写和建正常;再授予 delete 后又能删;单独关闭 write 与 create;读围栏让 cat 和 open().read() 失败;execute 围栏拒绝未授权二进制;python → sh 与 node → sh 的孙进程继承全部限制;内核拒绝的 profile 一个字节也不执行;workspace 外写入除非被授权否则一律拒绝。覆盖的内容包括:

- 权限库对任何写入者都拒绝 —— 即使有规则把它所在的目录整个开放,依然拒绝;
- rm、rmdir、rename、python -c 'os.remove'、node -e 'fs.rmSync' 全部被拒而写入与新建正常,再授予 delete 后又能删;
- 单独关闭 write、单独关闭 create,以及「只有 create」时能新建并写入内容;
- 读被拒:cat、python、node、bash,以及 python → sh、python → cat 孙进程;给一条读授权后又能读;
- 同一份读围栏下 /bin/sh、python3、node、git --version、gh --version 全部正常运行;
- execute 围栏拒绝未授权的二进制;给符号链接授权后它能启动指向的那个二进制;
- 内核拒绝的 profile 一个字节也不执行;workspace 外写入除非被授权否则一律拒绝。

当 sandbox-exec 无法应用 profile 时(包括测试本身跑在另一层 Seatbelt 沙箱里),它会打印明显的 SKIP —— 要在真内核上验证,请从普通终端运行。
CI 的 macOS 任务会设 DSH_ALLOW_REQUIRE_SEATBELT=1,把这个跳过变成失败:那边变绿意味着内核真的被跑过,而不是被跳过。

限制

- 如果一台 Mac 的 xcode-select 指向 Xcode bundle,git、python3、clang 都是 exec 进 /Applications/Xcode.app/Contents/Developer 的 shim,而基线够不到那里:它给的是 /Library/Developer 下的 Command Line Tools,不是 Xcode 的 developer 目录。这样的宿主得自己开一次 —— /allow add read,execute /Applications/Xcode.app/Contents/Developer folder —— 否则策略层允许、内核却拒绝。
- 「审批」标签页最多读审计日志最后 4 MiB、每次最多 500 条,打开期间每三秒重读一次:超长会话更早的判定会落在这个窗口之外。
- 块边界正好落在一行审计记录中间时,那一行会被丢掉,而不是报出一条读不完整的判定。
- 这个版本之前写下的记录没有 sessionId,所以永远不会出现在会话的审批记录里。
- 被围住的区域仍然可以解析路径:stat、列目录会泄漏 metadata,被扣掉的只是文件内容。
- 把配置和令牌放在同一个目录下的工具需要一条针对该目录的读授权:gh、aws、docker 之类在授予 ~/.config/ 之前会报自己的错。默认拒掉 hosts.yml、credentials、id_ed25519 正是目的,想打开是明确的动作。
- 命令行看不出效果的部分由沙箱判定,而不是由解析器猜:程序表里没有的效果一律交给围栏。
- 单独的 create 可以新建并写入内容;改动已存在的文件需要 write。
- 最强的读围栏(enforce: full)「能表达但活不下来」:macOS 自己要读的东西比策略基线列出的更多,/bin/sh 会直接 abort;auto 落在 guarded 围栏上。
- 两个较弱的 Seatbelt 结论:不可读的路径仍然可被解析(metadata 始终放行);通配拒绝必须逐操作写出来。
- 改名需要源的 delete 加目标的 create。
- 读效果只为固定的一张程序表推导;真正的边界是围栏,不是这张表。
- 「允许一次」是按会话串行、而不是按调用并行的:授权存活期间,同会话的其它调用会等被批准的那次结算。若核心把 callId 传进 sandbox policy,这个等待就能去掉 —— 目前核心不传。
- profile runner 固定为 /usr/bin/sandbox-exec;Seatbelt 不在这个位置的宿主会退回到 harness 自己的 profile 并报告 off。
- 自动复核是便利,不是边界:一个错误或被诱导的模型可能放行用户本会拒绝的请求。限制它的是「它能放行什么」—— 一次调用、只针对该请求的最窄规则 —— 以及底下仍有内核在强制策略。
- 复核会在卡片前多一次模型调用,所以卡片最多可能晚 timeoutMs 出现。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(DWJZ)的其他插件

💬 加入社群

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

DPharness QQ 群二维码,QQ 扫码进群
QQ 扫码进群
DPharness 飞书群二维码,飞书扫码进群
飞书扫码进群