# 🛡️ dsh-permission-rules
**DeepSeek Harness 的 Claude Code 风格声明式权限规则。**
*规则裁决已知的。评审模型裁决未知的。*
[](LICENSE)
[](https://github.com/topics/dsh-plugin)
[](#)
[](https://github.com/PerryLink/dsh-permission-rules/actions)
[](https://github.com/PerryLink/dsh-permission-rules/releases)
[](https://www.npmjs.com/package/dsh-permission-rules)
[](https://www.npmjs.com/package/dsh-permission-rules)
[English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
---
## Compatibility
| Surface | Status |
|---|---|
| Harness | DeepSeek Harness `0.1.0-rc.5`–`0.1.0-rc.6` |
| Node | `^22.19.0 || >=24.0.0` |
| Platforms | 全部(host + Web 设置客户端) |
| Model | 任意(deny/ask 原因经工具结果呈现) |
## What you get
`dsh-permission-rules` 在 `tools/pre-execute` waterfall 上为每次工具调用前置一个有序的 **`allow` / `deny` / `ask`** 规则列表——确定、即时、可审计,由你用纯 YAML 编写:
- **`deny`** 阻断调用;规则的 `reason` 成为模型可见的错误。
- **`ask`** 走官方审批接缝(挂载 `dsh-auto-review` 用第二模型作答,或由人作答;两者皆无时 harness 失败关闭)。
- **`allow`**(及未命中)严格经 `next()` 委托——下游监听器绝不会被短路。
每次命中**和**每次透传都作为 `permissionRules/decision` 会话事件审计落盘(仅日志——不会向模型上下文额外注入任何内容)。
- **丰富匹配** —— 工具名 glob(含 `mcp__*`)、agent 身份选择器(`main` / `subagent` / `preset:*`)、参数键/值 glob **或** 正则(含 `!pattern` 取反与 `absent` 键维度)、**任意嵌套深度**的工作区相对路径 glob,以及 `when` 宿主条件(环境变量、平台)。
- **分层规则文件** —— 可选 `searchUp` 从会话 cwd 到文件系统根合并每个 `.dsh/rules.yaml`,就近优先。
- **试运行上线** —— `enforce: false` 审计策略*会*做什么,同时放行每个调用。
- **热重载** —— Chokidar 监听带去抖;损坏的编辑保留旧规则、绝不崩溃。
- **失败大声** —— 非法 YAML、未知 action/字段、坏 glob/正则、易回溯模式或超过 `maxRules` 的规则在加载期失败。
## Rule syntax
```yaml
# /.dsh/rules.yaml
rules:
- match: { tools: [bash, pwsh], params: { command: "git push*" }, paths: ["**/secrets/**"] }
action: deny
reason: "No pushes from protected paths"
- match: { tools: [edit, write] }
action: ask
reason: "File writes need confirmation"
```
- **匹配维度** —— `tools`(glob,含 `mcp__*`)、`agents`(`main` / `subagent` / `preset:`;未知身份永不匹配——失败关闭)、`params`(键/值 glob 或正则,`!pattern` 取反,`absent` 键维度)、`paths`(任意嵌套深度抽取的工作区相对 glob)、`when`(`env` 变量 glob/正则 + 封闭 `platform` 列表),以及 `network`(`domains` / `ips` / `ports` / `schemes`——glob、通配符、CIDR、端口范围)。
- **动作** —— `allow` / `deny` / `ask`,按文件顺序求值,首个命中胜出。
- **规则元数据** —— `enabled: false`(可见但失效)、`description`、`tags`;未知字段加载失败。
- **Schema** —— JSON Schema 见 [docs/rules-format.schema.json](docs/rules-format.schema.json)(编辑器补全 `# yaml-language-server: $schema=...`);完整词汇表与 5 条安全基线见 [docs/rules-format.en.md](docs/rules-format.en.md)。
## Network policy
Codex 风格的**进程级网络策略**:shell 子进程流量经内置本地 **HTTP/CONNECT 代理**,每个连接由有序网络规则或映射到官方沙箱预设的三档模式裁决:
- **`deny-all`** —— 只读沙箱预设:阻断所有出站。
- **`whitelist`** —— workspace-write 预设:放行列表目标,其余按 `unlisted: ask`(或 `deny`)。
- **`allow-all`** —— danger-full-access 预设:放行一切。
- **`auto`**(默认)—— 跟随沙箱预设;无沙箱策略服务的宿主上解析为 `autoFallback`(`allow-all`)。
- **匹配** —— `match.network` 用 `domains` / `ips` / `ports` / `schemes`(glob、通配符、CIDR、端口范围;数值型 YAML 端口可接受)。`tools/pre-execute` 热路径上的 URL 候选抽取作用于 web 工具参数与嵌入 bash/pwsh 命令文本的 URL;回环目标可按 `loopback` 策略短路规则。
- **审计** —— 被拒连接向所属会话追加 `permissionRules/network`(同样的自适应 `ignorable` 门),块计数器与近期拦截在 `/rules network` 与设置页展示。
## Quick start
```sh
# 1. install the bundle into your profile
dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
# or from npm (published releases)
dsh plugin --profile web add dsh-permission-rules
# 2. restart and verify the row
dsh --profile web --dump-config | grep -A4 'id: permission-rules'
```
## Install & uninstall
- **git channel**(最新 `main`):`dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"` —— `prepare` 脚本仅用生产依赖构建。
- **npm channel**(发布版本):`dsh plugin --profile web add dsh-permission-rules`。
- **tarball channel**:在本仓库执行 `pnpm pack`,然后 `dsh plugin --profile web add ./dsh-permission-rules-.tgz`。
- **uninstall**:`dsh plugin --profile web remove dsh-permission-rules`。
## Configuration
所有可调项均为 Schemastery `Config` 字段(可在 cordis.yml 中修改)。按 id 覆盖会整行替换——重述你需要的每个键。
| Key | Default | Meaning |
|---|---|---|
| `rulesFile` | `.dsh/rules.yaml` | 规则文件位置;相对 = 相对调用会话 cwd 解析,绝对 = 全局并在挂载时校验 |
| `fallbackPath` | *(none)* | 按 cwd 发现无果时使用的规则文件;挂载时校验 |
| `badFilePolicy` | `fail` | 坏规则文件:`fail` 响亮地令待处理工具调用出错;`ignore-with-warning` 警告并空继续 |
| `maxRules` | `256` | 生效源链上规则总数的硬上限 |
| `maxCachedWorkspaces` | `512` | 缓存的工作区规则加载硬上限(LRU 逐出) |
| `patternMode` | `glob` | `params`/`paths`/`when.env` 模式风格:`glob` 或 `regex`(工具名始终为 glob) |
| `watch` | `true` | Chokidar 监听 + 变更重载 |
| `watchStabilityThresholdMs` | `200` | 重载去抖窗口(毫秒) |
| `language` | `en` | `/rules` 输出语言:`en`、`zh`、`es`、`pt`、`hi` |
| `caseInsensitivePaths` | *(win32)* | `paths` 模式与工作区根比较忽略 ASCII 大小写;Windows 上为 `true` |
| `audit` | `all` | 审计粒度:`all` 记录每次命中与透传;`hits` 跳过透传事件 |
| `searchUp` | `false` | 从会话 cwd 向上遍历父目录并合并每个找到的规则文件,就近优先 |
| `maxGlobStars` | `2` | 每个 glob 模式无界 `*`/`**` 量词的硬上限 |
| `enforce` | `true` | `false` = 试运行:deny/ask 命中带 `dryRun` 标记审计,每个调用都透传 |
| `allowUnmarkedAudit` | `false` | 前标记宿主丢弃 `ignorable` 标记;插件以一次性警告禁用会话日志审计。设 `true` 重新启用 |
| `network.enabled` | `true` | 代理、环境注入与 web 工具模式默认的总开关 |
| `network.mode` | `auto` | 策略模式:`auto` 跟随沙箱预设,或 `deny-all` / `whitelist` / `allow-all` |
| `network.autoFallback` | `allow-all` | `auto` 无沙箱策略服务时使用的模式 |
| `network.unlisted` | `ask` | 白名单模式下未命中规则目标:`ask` 或 `deny` |
| `network.proxyBind` | `127.0.0.1` | 本地代理绑定地址(仅回环) |
| `network.proxyPort` | `0` | 本地代理端口;`0` 选空闲临时端口 |
| `network.proxyMaxRecent` | `100` | 设置页保留的近期拦截记录上限 |
| `network.loopback` | `allow` | 回环目标:`allow`(Codex 对齐)或 `policy` |
| `network.injectEnv` | `true` | 是否为子进程注入代理环境变量 |
| `network.noProxy` | `clear` | 子进程 NO_PROXY 处理:`clear` 强制策略或 `preserve` |
## Tools & surfaces
| Surface | Kind | Notes |
|---|---|---|
| `tools/pre-execute` | listener | 首个匹配的 allow/deny/ask 规则 + 网络 URL 候选抽取 |
| `/rules` | command | `list` · `reload` · `decisions [n]` · `test ` |
| `permissionRules/decision` | event | 每次命中与透传的仅日志审计 |
| `permissionRules/network` | event | 被拒连接的代理层审计 |
| HTTP/CONNECT proxy | service | 治理 shell 子进程流量的内置本地代理 |
| settings page | client | 网络模式编辑器、规则编辑器、块计数器、近期拦截 |
```
/rules list the active rules, their source files, and any last-reload error
/rules list explicit alias for the bare listing
/rules reload re-read the rule-file chain for this workspace
/rules decisions [n] show the last n permission decisions of this session (default 10)
/rules test dry-evaluate the rules against a hypothetical call
```
`/rules test` 也接受前置标志:`--cwd `、`--env KEY=VALUE`(可重复)、`--agent `(可重复)与 `--platform `。在多文件链(如 `searchUp`)中,每条列出的规则行都归属到其自身源文件。
## Permissions & data
- **Permissions**:workshop 清单声明 `files:read`、`files:watch`、`files:write`、`session:append` 与 `network:outbound`。`ask` 决策走官方审批接缝——不重实现、不绕过。
- **Data**:规则文件从磁盘读取;不写任何规则数据。无模型调用、无评审子代理。
- **Session log**:`permissionRules/decision` 绝不注入模型上下文,并以信封的 `ignorable: true` 标记追加,任何 harness 构建都能加载日志。
## Security boundaries
- **是策略,不是内核。** `paths` 候选只来自一组文档化的参数键(任意嵌套深度、有深度上限),且仅工作区相对路径匹配。
- **这里没有评审者。** 插件绝不生成子代理或调用模型——产出 `ask` 决策就是其工作的终点。
- **不改沙箱。** OS 级沙箱策略属于沙箱接缝,与本插件无关。
- **响亮地拒绝错误配置。** 未知 YAML 字段、未知 action 与坏模式在加载期被拒绝。
- **回溯界限。** glob 模式以 `maxGlobStars` 限制无界星号展开;正则模式拒绝嵌套无界量词与量化重叠字面交替。
## Known limitations
- **前标记宿主上的审计标记。** `permissionRules/decision` 以 `ignorable: true` 追加;`Session.append` 早于该标记的宿主(`0.1.0-rc.6` 线)静默丢弃它,因此运行时以一次性警告禁用会话日志审计。设 `allowUnmarkedAudit: true` 重新启用;用 `scripts/repair-session-logs.mjs` 修复已写日志。
- **路径候选是启发式的。** 只有文档化的参数键参与路径匹配,且工作区相对匹配仅在 `caseInsensitivePaths` 开启时忽略 ASCII 大小写。
- **glob 是保守子集。** 无花括号展开——写两个模式,或用正则模式。
- **正则回溯守卫是结构性的、非穷尽的。** 对不可信文件优先用 glob 模式。
## Collaborating with dsh-auto-review
- `dsh-permission-rules` 产出 `ask`;`dsh-auto-review` 在 `approval/request` waterfall 上以只读第二模型裁决作答(或委托给人)。两者都挂载即得完整闭环。
- 集成测试:`permissionRules/decision` → `approval/asked` → `autoReview/verdict` → `approval/decided`,评审者以脚本化 mock 替换。
- 官方 harness 的 `never` 审批策略与每个失败关闭保证保持不变。
## Session log repair
在 `ignorable` 标记出现之前写入的会话日志可能被较新 harness 构建拒绝(`SessionFormatUnsupportedError`)。随附的 `scripts/repair-session-logs.mjs` 仅重写目标审计行以携带 `ignorable: true`,保帧、带备份:
```sh
node scripts/repair-session-logs.mjs scan [--home DIR] # 报告外来行,不改任何内容
node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
```
`--home` 默认 `$DSH_HOME/sessions`(或 `~/.dsh/sessions`)。
## Development
```sh
pnpm install # node ^22.19 || >=24
pnpm run typecheck # tsc, src + tests
pnpm run lint # eslint, src + tests + scripts
pnpm test # vitest: 139 tests, 9 suites
pnpm run test:coverage # coverage gate (90/80/90/90)
pnpm run build # tsc declarations + tsdown bundles (lib/)
pnpm run pack:check # build + pack (the published artifact)
node scripts/check-readme-sync.mjs # five-language README sync gate (also in CI)
```
无头端到端验证记录见 [VERIFICATION.md](VERIFICATION.md)。
## Topics
`dsh`, `dsh-plugin`, `deepseek-harness`, `permission`, `policy`, `allow-deny-ask`, `approval`, `safety`, `network`, `network-policy`, `proxy`
## Contributors
- [@PerryLink](https://github.com/PerryLink) —— 创建者与维护者:规则词汇与求值、运行时、HMR 监听、会话日志审计、网络策略 + 代理,以及五语文档。
- [@22xuan](https://github.com/22xuan) —— 关于 rc.6 宿主静默丢弃审计事件 `ignorable` 标记的详细报告([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2))与上游 harness 讨论;v0.4.1 的运行时宿主能力检测与文档更正直接源自该分析。
## PerryLink DSH Plugin Family
本项目是 [PerryLink](https://github.com/PerryLink) 维护的 [15 个 DeepSeek Harness 插件](https://github.com/PerryLink) 之一。如果这个对你有用,其他插件多半也有用:
| Plugin | One-liner |
|---|---|
| [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
| [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Engineering-discipline guard: requirements grill, test gates, adversary review |
| [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Durable background child agents with a Web UI sidebar, messaging and interrupt |
| [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | LSP diagnostics, formatting, completion, code actions and rename over language servers |
| [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | Claude Code outputStyles-equivalent runtime style switching |
| [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
| **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | Claude Code-style declarative allow/deny/ask permission rules with audit |
| [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | Second-model auto-review on the approval chain, fail-closed by default |
| [dsh-memento](https://github.com/PerryLink/dsh-memento) | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
| [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Security-audit skill pack: secret scan, dependency and supply-chain review |
| [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Pin sessions in the Web sidebar with durable ordering |
| [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Terminal-style input history for the web composer: arrows, Ctrl+R search |
| [dsh-github](https://github.com/PerryLink/dsh-github) | GitHub PR/issues integration for DSH, every write gated by approval |
| [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Plugin-development knowledge base as an on-demand agent skill |
| [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
## License
[Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors