dsh-permission-rules 0.4.2 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.es.md +160 -117
- package/README.hi.md +162 -119
- package/README.md +133 -90
- package/README.pt.md +161 -118
- package/README.zh.md +162 -119
- package/docs/rule-test-vectors/README.md +28 -0
- package/docs/rule-test-vectors/corpus.json +109 -0
- package/lib/client.js +4693 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +1530 -179
- package/lib/typert.host.js +4305 -0
- package/lib/types/client/index.d.ts +28 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/locales.d.ts +9 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/remote.d.ts +181 -0
- package/lib/types/client/remote.d.ts.map +1 -0
- package/lib/types/client/section.d.ts +35 -0
- package/lib/types/client/section.d.ts.map +1 -0
- package/lib/types/config.d.ts +54 -2
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/events.d.ts +45 -0
- package/lib/types/events.d.ts.map +1 -1
- package/lib/types/index.d.ts +8 -6
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/network.d.ts +90 -0
- package/lib/types/network.d.ts.map +1 -0
- package/lib/types/prose.d.ts +15 -0
- package/lib/types/prose.d.ts.map +1 -1
- package/lib/types/proxy.d.ts +128 -0
- package/lib/types/proxy.d.ts.map +1 -0
- package/lib/types/remote-service.d.ts +45 -0
- package/lib/types/remote-service.d.ts.map +1 -0
- package/lib/types/rules.d.ts +131 -0
- package/lib/types/rules.d.ts.map +1 -1
- package/lib/types/runtime.d.ts +153 -21
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/settings.d.ts +28 -0
- package/lib/types/settings.d.ts.map +1 -0
- package/lib/types/typert.host.d.ts +166 -0
- package/lib/types/typert.host.d.ts.map +1 -0
- package/lib/types/wire.d.ts +421 -0
- package/lib/types/wire.d.ts.map +1 -0
- package/package.json +182 -144
- package/scripts/repair-session-logs.mjs +7 -2
- package/src/client/index.ts +111 -0
- package/src/client/locales.ts +94 -0
- package/src/client/remote.ts +41 -0
- package/src/client/section.ts +201 -0
- package/src/config.ts +111 -0
- package/src/events.ts +46 -0
- package/src/index.ts +2 -0
- package/src/network.ts +177 -0
- package/src/prose.ts +85 -10
- package/src/proxy.ts +327 -0
- package/src/remote-service.ts +109 -0
- package/src/rules.ts +424 -5
- package/src/runtime.ts +464 -53
- package/src/settings.ts +74 -0
- package/src/typert.host.ts +25 -0
- package/src/wire.ts +239 -0
- package/lib/types/config.js +0 -99
- package/lib/types/config.js.map +0 -1
- package/lib/types/events.js +0 -44
- package/lib/types/events.js.map +0 -1
- package/lib/types/glob.js +0 -307
- package/lib/types/glob.js.map +0 -1
- package/lib/types/index.js +0 -27
- package/lib/types/index.js.map +0 -1
- package/lib/types/prose.js +0 -173
- package/lib/types/prose.js.map +0 -1
- package/lib/types/rules.js +0 -610
- package/lib/types/rules.js.map +0 -1
- package/lib/types/runtime.js +0 -818
- package/lib/types/runtime.js.map +0 -1
package/README.md
CHANGED
|
@@ -20,63 +20,32 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Compatibility
|
|
24
|
+
|
|
25
|
+
| Surface | Status |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Harness | DeepSeek Harness `0.1.0-rc.5`–`0.1.0-rc.6` |
|
|
28
|
+
| Node | `^22.19.0 || >=24.0.0` |
|
|
29
|
+
| Platforms | All (host + web settings client) |
|
|
30
|
+
| Model | Any (deny/ask reasons surface through tool results) |
|
|
31
|
+
|
|
32
|
+
## What you get
|
|
24
33
|
|
|
25
34
|
`dsh-permission-rules` puts an ordered **`allow` / `deny` / `ask`** rule list in front of every tool call on the `tools/pre-execute` waterfall — deterministic, instant, auditable, and written by you in plain YAML:
|
|
26
35
|
|
|
27
|
-
- **`deny`** blocks the call
|
|
28
|
-
- **`ask`** rides the official approval seam
|
|
36
|
+
- **`deny`** blocks the call; the rule's `reason` becomes the model-visible error.
|
|
37
|
+
- **`ask`** rides the official approval seam (mount `dsh-auto-review` for a second-model answerer, or a human answers; with neither, the harness fails closed).
|
|
29
38
|
- **`allow`** (and no-match) strictly delegates via `next()` — downstream listeners are never short-circuited.
|
|
30
39
|
|
|
31
40
|
Every hit **and** every passthrough is audit-logged as a `permissionRules/decision` session event (log-only — nothing extra is injected into the model context).
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
· deny/ask claim the call │ AI verdict (second model) │ no ── next() ──▶ human UI
|
|
39
|
-
· allow/passthrough → next() └───────────────┬──────────────┘
|
|
40
|
-
│ deny ──▶ denied tool result │ allowed-once / rejected
|
|
41
|
-
│ ask ──▶ ctx.approval ──────────────────────────┘
|
|
42
|
-
│
|
|
43
|
-
audit: permissionRules/decision → approval/asked → autoReview/verdict → approval/decided
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Why rules *and* a reviewer?
|
|
47
|
-
|
|
48
|
-
A second model answers *"is THIS call okay?"* with judgment, but costs a round-trip and can be wrong. Declarative rules answer deterministically, instantly, and without a model — but only cover what an admin wrote down. Combined, you get the **"rules first, AI backstop"** loop: rules decide the known, the reviewer decides the unknown.
|
|
49
|
-
|
|
50
|
-
## Features
|
|
51
|
-
|
|
52
|
-
- ✅ **Three-state semantics** — `allow`, `deny`, `ask`, evaluated in file order, first match wins
|
|
53
|
-
- ✅ **Rich matching** — tool-name globs (including `mcp__*`), agent-identity selectors (`main` / `subagent` / `preset:*`), argument key/value globs **or** regexes (with `!pattern` negation and an `absent` key dimension), workspace-relative path globs extracted from documented argument keys at **any nesting depth**, and `when` host conditions (env vars, platform)
|
|
54
|
-
- ✅ **Hierarchical rule files** — optional `searchUp` merges every `.dsh/rules.yaml` from the session cwd to the filesystem root, nearest first, so a child project can override parent rules
|
|
55
|
-
- ✅ **Rule metadata** — `enabled: false`, `description`, `tags`; `/rules` warns about rules shadowed by an earlier catch-all
|
|
56
|
-
- ✅ **Waterfall-safe** — `allow`/passthrough always call `next()`; only `deny`/`ask` short-circuit
|
|
57
|
-
- ✅ **Official approval seam** — `ask` flows through `ctx.approval`; never re-implemented, never bypassed
|
|
58
|
-
- ✅ **Full audit** — `permissionRules/decision` events carry the rule action, the workspace cwd, AND the final outcome for every call; `/rules decisions` replays the trail in-session; hosts that predate the audit envelope marker degrade to audit-off with a one-time warning instead of writing unresumable logs (`allowUnmarkedAudit` opts back in)
|
|
59
|
-
- ✅ **Dry-run rollout** — `enforce: false` audits what the policy *would* do (would-be action + real downstream outcome, `dryRun`-marked) while passing every call through; safe policy trialing in production
|
|
60
|
-
- ✅ **Dry-run testing** — `/rules test <tool> <json-args>` evaluates the active rules without executing anything, with `--cwd`, `--env`, `--agent`, and `--platform` overrides for every match dimension
|
|
61
|
-
- ✅ **Hot reload** — Chokidar watch with debounce; a broken edit keeps the previous rules, never crashes; a rule file created mid-session (the project file or the fallback) is adopted automatically, no manual reload
|
|
62
|
-
- ✅ **Fail loud** — invalid YAML, unknown actions/fields, bad globs/regexes, backtracking-prone patterns, or > `maxRules` fail the load
|
|
63
|
-
- ✅ **Bounded hot path** — precompiled matchers, O(rules × patterns), capped by `maxRules`; glob backtracking degree capped by `maxGlobStars`
|
|
64
|
-
|
|
65
|
-
## Quick start
|
|
66
|
-
|
|
67
|
-
```sh
|
|
68
|
-
# 1. install the bundle into your profile
|
|
69
|
-
dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
|
|
70
|
-
|
|
71
|
-
# or from a packed tarball (built artifacts, no build permission needed)
|
|
72
|
-
pnpm pack
|
|
73
|
-
dsh plugin --profile web add ./dsh-permission-rules-0.4.1.tgz
|
|
74
|
-
|
|
75
|
-
# 2. restart
|
|
76
|
-
dsh --profile web
|
|
77
|
-
```
|
|
42
|
+
- **Rich matching** — tool-name globs (including `mcp__*`), agent-identity selectors (`main` / `subagent` / `preset:*`), argument key/value globs **or** regexes (with `!pattern` negation and an `absent` key dimension), workspace-relative path globs at **any nesting depth**, and `when` host conditions (env vars, platform).
|
|
43
|
+
- **Hierarchical rule files** — optional `searchUp` merges every `.dsh/rules.yaml` from the session cwd to the filesystem root, nearest first.
|
|
44
|
+
- **Dry-run rollout** — `enforce: false` audits what the policy *would* do while passing every call through.
|
|
45
|
+
- **Hot reload** — Chokidar watch with debounce; a broken edit keeps the previous rules, never crashes.
|
|
46
|
+
- **Fail loud** — invalid YAML, unknown actions/fields, bad globs/regexes, backtracking-prone patterns, or more than `maxRules` rules fail the load.
|
|
78
47
|
|
|
79
|
-
|
|
48
|
+
## Rule syntax
|
|
80
49
|
|
|
81
50
|
```yaml
|
|
82
51
|
# <project>/.dsh/rules.yaml
|
|
@@ -90,11 +59,42 @@ rules:
|
|
|
90
59
|
reason: "File writes need confirmation"
|
|
91
60
|
```
|
|
92
61
|
|
|
62
|
+
- **Match dimensions** — `tools` (globs, incl. `mcp__*`), `agents` (`main` / `subagent` / `preset:<name>`; unknown identity never matches — fail closed), `params` (key/value globs or regexes, `!pattern` negation, `absent` key dimension), `paths` (workspace-relative globs extracted at any nesting depth), `when` (`env` var globs/regexes + a closed `platform` list), and `network` (`domains` / `ips` / `ports` / `schemes` — globs, wildcards, CIDRs, port ranges).
|
|
63
|
+
- **Actions** — `allow` / `deny` / `ask`, evaluated in file order, first match wins.
|
|
64
|
+
- **Rule metadata** — `enabled: false` (visible but inert), `description`, `tags`; unknown fields fail the load.
|
|
65
|
+
- **Schema** — a JSON Schema ships at [docs/rules-format.schema.json](docs/rules-format.schema.json) (editor completion via `# yaml-language-server: $schema=...`); the full vocabulary and a 5-rule security baseline live in [docs/rules-format.en.md](docs/rules-format.en.md).
|
|
66
|
+
|
|
67
|
+
## Network policy
|
|
68
|
+
|
|
69
|
+
A Codex-style **process-level network policy**: shell subprocess traffic flows through a built-in local **HTTP/CONNECT proxy**, and every connection is decided by ordered network rules or by three modes mapped onto the official sandbox presets:
|
|
70
|
+
|
|
71
|
+
- **`deny-all`** — the read-only sandbox preset: block all outbound.
|
|
72
|
+
- **`whitelist`** — the workspace-write preset: allow listed targets, `unlisted: ask` (or `deny`) for the rest.
|
|
73
|
+
- **`allow-all`** — the danger-full-access preset: allow everything.
|
|
74
|
+
- **`auto`** (default) — follows the sandbox preset; on hosts without the sandbox-policy service it resolves to `autoFallback` (`allow-all`).
|
|
75
|
+
|
|
76
|
+
- **Matching** — `match.network` with `domains` / `ips` / `ports` / `schemes` (globs, wildcards, CIDRs, port ranges; numeric YAML ports are accepted). URL-candidate extraction on the `tools/pre-execute` hot path fires on web-tool arguments and URLs embedded in bash/pwsh command text; loopback targets can short-circuit rules per `loopback` policy.
|
|
77
|
+
- **Audit** — denied connections append `permissionRules/network` to the owning session (same adaptive `ignorable` gate), with block counters and recent interceptions in `/rules network` and the settings page.
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
93
81
|
```sh
|
|
94
|
-
|
|
82
|
+
# 1. install the bundle into your profile
|
|
83
|
+
dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
|
|
84
|
+
|
|
85
|
+
# or from npm (published releases)
|
|
86
|
+
dsh plugin --profile web add dsh-permission-rules
|
|
87
|
+
|
|
88
|
+
# 2. restart and verify the row
|
|
89
|
+
dsh --profile web --dump-config | grep -A4 'id: permission-rules'
|
|
95
90
|
```
|
|
96
91
|
|
|
97
|
-
|
|
92
|
+
## Install & uninstall
|
|
93
|
+
|
|
94
|
+
- **git channel** (latest `main`): `dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"` — the `prepare` script builds with production dependencies only.
|
|
95
|
+
- **npm channel** (published releases): `dsh plugin --profile web add dsh-permission-rules`.
|
|
96
|
+
- **tarball channel**: `pnpm pack` in this repo, then `dsh plugin --profile web add ./dsh-permission-rules-<version>.tgz`.
|
|
97
|
+
- **uninstall**: `dsh plugin --profile web remove dsh-permission-rules`.
|
|
98
98
|
|
|
99
99
|
## Configuration
|
|
100
100
|
|
|
@@ -104,60 +104,77 @@ All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id
|
|
|
104
104
|
|---|---|---|
|
|
105
105
|
| `rulesFile` | `.dsh/rules.yaml` | Rule file location; relative = resolved against the calling session's cwd, absolute = global and validated at mount |
|
|
106
106
|
| `fallbackPath` | *(none)* | Rule file used when per-cwd discovery finds nothing; validated at mount |
|
|
107
|
-
| `badFilePolicy` | `fail` | Bad rule file: `fail` errors the pending tool call loudly
|
|
108
|
-
| `maxRules` | `256` | Hard cap on rule count across the effective source chain
|
|
109
|
-
| `maxCachedWorkspaces` | `512` | Hard cap on cached per-workspace rule loads
|
|
107
|
+
| `badFilePolicy` | `fail` | Bad rule file: `fail` errors the pending tool call loudly; `ignore-with-warning` warns and continues empty |
|
|
108
|
+
| `maxRules` | `256` | Hard cap on rule count across the effective source chain |
|
|
109
|
+
| `maxCachedWorkspaces` | `512` | Hard cap on cached per-workspace rule loads (LRU eviction) |
|
|
110
110
|
| `patternMode` | `glob` | `params`/`paths`/`when.env` pattern flavor: `glob` or `regex` (tool names are always globs) |
|
|
111
111
|
| `watch` | `true` | Chokidar watch + reload on change |
|
|
112
112
|
| `watchStabilityThresholdMs` | `200` | Reload debounce window (ms) |
|
|
113
|
-
| `language` | `en` | `/rules` output language: `en`, `zh`, `es`, `pt`, `hi`
|
|
114
|
-
| `caseInsensitivePaths` | *(win32)* | `paths` patterns and workspace-root comparison ignore ASCII case;
|
|
113
|
+
| `language` | `en` | `/rules` output language: `en`, `zh`, `es`, `pt`, `hi` |
|
|
114
|
+
| `caseInsensitivePaths` | *(win32)* | `paths` patterns and workspace-root comparison ignore ASCII case; `true` on Windows |
|
|
115
115
|
| `audit` | `all` | Audit granularity: `all` logs every hit AND passthrough; `hits` skips passthrough events |
|
|
116
116
|
| `searchUp` | `false` | Walk parent directories from the session cwd and merge every found rule file, nearest first |
|
|
117
|
-
| `maxGlobStars` | `2` | Hard cap on unbounded `*`/`**` quantifiers per glob pattern
|
|
118
|
-
| `enforce` | `true` | `false` = dry-run mode: deny/ask hits are audit-logged with a `dryRun` marker
|
|
119
|
-
| `allowUnmarkedAudit` | `false` |
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
| `maxGlobStars` | `2` | Hard cap on unbounded `*`/`**` quantifiers per glob pattern |
|
|
118
|
+
| `enforce` | `true` | `false` = dry-run mode: deny/ask hits are audit-logged with a `dryRun` marker and every call passes through |
|
|
119
|
+
| `allowUnmarkedAudit` | `false` | Pre-marker hosts drop the `ignorable` marker; the plugin disables session-log audit with a warning. Set `true` to opt back in |
|
|
120
|
+
| `network.enabled` | `true` | Master switch for the proxy, env injection, and web-tool mode defaults |
|
|
121
|
+
| `network.mode` | `auto` | Policy mode: `auto` follows the sandbox preset, or `deny-all` / `whitelist` / `allow-all` |
|
|
122
|
+
| `network.autoFallback` | `allow-all` | Mode used when `auto` has no sandbox-policy service |
|
|
123
|
+
| `network.unlisted` | `ask` | Whitelist-mode handling of targets no rule matched: `ask` or `deny` |
|
|
124
|
+
| `network.proxyBind` | `127.0.0.1` | Local proxy bind address (loopback only) |
|
|
125
|
+
| `network.proxyPort` | `0` | Local proxy port; `0` picks a free ephemeral port |
|
|
126
|
+
| `network.proxyMaxRecent` | `100` | Cap on recent-block records kept for the settings page |
|
|
127
|
+
| `network.loopback` | `allow` | Loopback targets: `allow` (Codex parity) or `policy` |
|
|
128
|
+
| `network.injectEnv` | `true` | Whether proxy environment variables are injected for subprocesses |
|
|
129
|
+
| `network.noProxy` | `clear` | Subprocess NO_PROXY handling: `clear` enforces the policy or `preserve` |
|
|
130
|
+
|
|
131
|
+
## Tools & surfaces
|
|
132
|
+
|
|
133
|
+
| Surface | Kind | Notes |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `tools/pre-execute` | listener | First-match allow/deny/ask rules + network URL-candidate extraction |
|
|
136
|
+
| `/rules` | command | `list` · `reload` · `decisions [n]` · `test <tool> <json>` |
|
|
137
|
+
| `permissionRules/decision` | event | Log-only audit for every hit and passthrough |
|
|
138
|
+
| `permissionRules/network` | event | Proxy-layer audit for blocked connections |
|
|
139
|
+
| HTTP/CONNECT proxy | service | Built-in local proxy governing shell subprocess traffic |
|
|
140
|
+
| settings page | client | Network-mode editor, rule editor, block counters, recent interceptions |
|
|
122
141
|
|
|
123
142
|
```
|
|
124
143
|
/rules list the active rules, their source files, and any last-reload error
|
|
125
144
|
/rules list explicit alias for the bare listing
|
|
126
145
|
/rules reload re-read the rule-file chain for this workspace
|
|
127
146
|
/rules decisions [n] show the last n permission decisions of this session (default 10)
|
|
128
|
-
/rules test <tool> <json> dry-evaluate the rules against a hypothetical call
|
|
147
|
+
/rules test <tool> <json> dry-evaluate the rules against a hypothetical call
|
|
129
148
|
```
|
|
130
149
|
|
|
131
|
-
`/rules test` also accepts leading flags: `--cwd <dir
|
|
150
|
+
`/rules test` also accepts leading flags: `--cwd <dir>`, `--env KEY=VALUE` (repeatable), `--agent <selector>` (repeatable), and `--platform <name>`. In multi-file chains (e.g. `searchUp`), every listed rule line is attributed to its own source file.
|
|
132
151
|
|
|
133
|
-
|
|
152
|
+
## Permissions & data
|
|
134
153
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
- `
|
|
138
|
-
- Integration-tested (`test/integration.spec.ts`): `permissionRules/decision` → `approval/asked` → `autoReview/verdict` → `approval/decided`, with the reviewer replaced by a scripted mock.
|
|
139
|
-
- The `never` approval policy and every fail-closed guarantee of the [official harness](https://github.com/deepseek-ai/deepseek-harness) stay untouched.
|
|
154
|
+
- **Permissions**: declares `files:read`, `files:watch`, `files:write`, `session:append`, and `network:outbound` in its workshop manifest. `ask` decisions ride the official approval seam — nothing is re-implemented or bypassed.
|
|
155
|
+
- **Data**: rule files are read from disk; no rule data is written. No model calls, no reviewer subagents.
|
|
156
|
+
- **Session log**: `permissionRules/decision` is never injected into the model context and is appended with the envelope's `ignorable: true` marker so any harness build loads the log.
|
|
140
157
|
|
|
141
158
|
## Security boundaries
|
|
142
159
|
|
|
143
160
|
- **Policy, not a kernel.** `paths` candidates come only from a documented set of argument keys (at any nesting depth, depth-capped), and only workspace-relative paths match.
|
|
144
161
|
- **No reviewer here.** The plugin never spawns subagents or calls models — producing an `ask` decision is the end of its work.
|
|
145
162
|
- **No sandbox changes.** OS-level sandbox policy belongs to the sandbox seam, not this plugin.
|
|
146
|
-
- **Loud misconfiguration.** Unknown YAML fields, unknown actions, and bad patterns are rejected at load
|
|
147
|
-
- **Backtracking bounds.** Glob patterns are capped at `maxGlobStars` unbounded star expansions; regex-mode patterns reject nested unbounded quantifiers and quantified overlapping literal alternations.
|
|
163
|
+
- **Loud misconfiguration.** Unknown YAML fields, unknown actions, and bad patterns are rejected at load.
|
|
164
|
+
- **Backtracking bounds.** Glob patterns are capped at `maxGlobStars` unbounded star expansions; regex-mode patterns reject nested unbounded quantifiers and quantified overlapping literal alternations.
|
|
148
165
|
|
|
149
|
-
##
|
|
166
|
+
## Known limitations
|
|
150
167
|
|
|
151
|
-
-
|
|
152
|
-
-
|
|
153
|
-
-
|
|
168
|
+
- **Audit marker on pre-marker hosts.** `permissionRules/decision` is appended with `ignorable: true`; hosts whose `Session.append` predates the marker (the `0.1.0-rc.6` line) silently drop it, so the runtime disables session-log audit with a one-time warning. Set `allowUnmarkedAudit: true` to opt back in; repair already-written logs with `scripts/repair-session-logs.mjs`.
|
|
169
|
+
- **Path candidates are heuristic.** Only the documented argument keys feed path matching, and workspace-relative matching is ASCII-case-insensitive only when `caseInsensitivePaths` is on.
|
|
170
|
+
- **Globs are a conservative subset.** No brace expansion — write two patterns, or use regex mode.
|
|
171
|
+
- **The regex backtracking guard is structural, not exhaustive.** Prefer glob mode for untrusted files.
|
|
154
172
|
|
|
155
|
-
##
|
|
173
|
+
## Collaborating with dsh-auto-review
|
|
156
174
|
|
|
157
|
-
- `
|
|
158
|
-
- `
|
|
159
|
-
-
|
|
160
|
-
- The regex backtracking guard is structural, not exhaustive: alternation-ambiguity cases without literal prefixes (e.g. crafted lookarounds) are the author's responsibility; prefer glob mode for untrusted files.
|
|
175
|
+
- `dsh-permission-rules` produces `ask`; `dsh-auto-review` answers on the `approval/request` waterfall with a read-only second-model verdict (or delegates to humans). Mount both for the full closed loop.
|
|
176
|
+
- Integration-tested: `permissionRules/decision` → `approval/asked` → `autoReview/verdict` → `approval/decided`, with the reviewer replaced by a scripted mock.
|
|
177
|
+
- The `never` approval policy and every fail-closed guarantee of the official harness stay untouched.
|
|
161
178
|
|
|
162
179
|
## Session log repair
|
|
163
180
|
|
|
@@ -168,28 +185,54 @@ node scripts/repair-session-logs.mjs scan [--home DIR] # report foreign row
|
|
|
168
185
|
node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
|
|
169
186
|
```
|
|
170
187
|
|
|
171
|
-
`--home` defaults to `$DSH_HOME/sessions` (or `~/.dsh/sessions`).
|
|
188
|
+
`--home` defaults to `$DSH_HOME/sessions` (or `~/.dsh/sessions`).
|
|
172
189
|
|
|
173
190
|
## Development
|
|
174
191
|
|
|
175
192
|
```sh
|
|
176
|
-
pnpm install
|
|
177
|
-
pnpm run typecheck
|
|
178
|
-
pnpm run lint
|
|
179
|
-
pnpm test
|
|
193
|
+
pnpm install # node ^22.19 || >=24
|
|
194
|
+
pnpm run typecheck # tsc, src + tests
|
|
195
|
+
pnpm run lint # eslint, src + tests + scripts
|
|
196
|
+
pnpm test # vitest: 139 tests, 9 suites
|
|
180
197
|
pnpm run test:coverage # coverage gate (90/80/90/90)
|
|
181
|
-
pnpm run build
|
|
182
|
-
pnpm run pack:check
|
|
183
|
-
node scripts/check-readme-sync.mjs
|
|
198
|
+
pnpm run build # tsc declarations + tsdown bundles (lib/)
|
|
199
|
+
pnpm run pack:check # build + pack (the published artifact)
|
|
200
|
+
node scripts/check-readme-sync.mjs # five-language README sync gate (also in CI)
|
|
184
201
|
```
|
|
185
202
|
|
|
186
|
-
See [VERIFICATION.md](VERIFICATION.md) for the headless end-to-end verification record
|
|
203
|
+
See [VERIFICATION.md](VERIFICATION.md) for the headless end-to-end verification record.
|
|
204
|
+
|
|
205
|
+
## Topics
|
|
206
|
+
|
|
207
|
+
`dsh`, `dsh-plugin`, `deepseek-harness`, `permission`, `policy`, `allow-deny-ask`, `approval`, `safety`, `network`, `network-policy`, `proxy`
|
|
187
208
|
|
|
188
209
|
## Contributors
|
|
189
210
|
|
|
190
|
-
- [@PerryLink](https://github.com/PerryLink) — creator and maintainer: rule vocabulary and evaluation, runtime, HMR watch, session-log audit, and the five-language docs.
|
|
211
|
+
- [@PerryLink](https://github.com/PerryLink) — creator and maintainer: rule vocabulary and evaluation, runtime, HMR watch, session-log audit, network policy + proxy, and the five-language docs.
|
|
191
212
|
- [@22xuan](https://github.com/22xuan) — the detailed report on rc.6 hosts silently dropping the audit event's `ignorable` marker ([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2)) and the upstream harness discussion; the v0.4.1 runtime host-capability detection and the documentation correction drew directly from that analysis.
|
|
192
213
|
|
|
214
|
+
## PerryLink DSH Plugin Family
|
|
215
|
+
|
|
216
|
+
This project is one of the [15 DeepSeek Harness plugins](https://github.com/PerryLink) maintained by [PerryLink](https://github.com/PerryLink). If this one helps you, the others likely will too:
|
|
217
|
+
|
|
218
|
+
| Plugin | One-liner |
|
|
219
|
+
|---|---|
|
|
220
|
+
| [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
|
|
221
|
+
| [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Engineering-discipline guard: requirements grill, test gates, adversary review |
|
|
222
|
+
| [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Durable background child agents with a Web UI sidebar, messaging and interrupt |
|
|
223
|
+
| [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | LSP diagnostics, formatting, completion, code actions and rename over language servers |
|
|
224
|
+
| [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | Claude Code outputStyles-equivalent runtime style switching |
|
|
225
|
+
| [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
|
|
226
|
+
| **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | Claude Code-style declarative allow/deny/ask permission rules with audit |
|
|
227
|
+
| [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | Second-model auto-review on the approval chain, fail-closed by default |
|
|
228
|
+
| [dsh-memento](https://github.com/PerryLink/dsh-memento) | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
|
|
229
|
+
| [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Security-audit skill pack: secret scan, dependency and supply-chain review |
|
|
230
|
+
| [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Pin sessions in the Web sidebar with durable ordering |
|
|
231
|
+
| [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Terminal-style input history for the web composer: arrows, Ctrl+R search |
|
|
232
|
+
| [dsh-github](https://github.com/PerryLink/dsh-github) | GitHub PR/issues integration for DSH, every write gated by approval |
|
|
233
|
+
| [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Plugin-development knowledge base as an on-demand agent skill |
|
|
234
|
+
| [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
|
|
235
|
+
|
|
193
236
|
## License
|
|
194
237
|
|
|
195
238
|
[Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors
|