dsh-permission-rules 0.7.21 → 0.7.22
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 +7 -0
- package/README.en.md +504 -0
- package/README.es.md +504 -0
- package/README.hi.md +504 -0
- package/README.md +309 -245
- package/README.pt.md +504 -0
- package/docs/assets/dsh-permission-rules-flow-dark.svg +58 -0
- package/docs/assets/dsh-permission-rules-flow-light.svg +58 -0
- package/docs/assets/dsh-permission-rules-flow-v5-dark.svg +103 -0
- package/docs/assets/dsh-permission-rules-flow-v5-light.svg +103 -0
- package/docs/assets/dsh-permission-rules-hero-en-dark.webp +0 -0
- package/docs/assets/dsh-permission-rules-hero-en-light.webp +0 -0
- package/docs/assets/dsh-permission-rules-hero-zh-dark.webp +0 -0
- package/docs/assets/dsh-permission-rules-hero-zh-light.webp +0 -0
- package/docs/rules-format.en.md +5 -4
- package/docs/rules-format.md +5 -4
- package/lib/index.js +230 -40
- package/lib/types/config.d.ts +9 -4
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/prose.d.ts +6 -0
- package/lib/types/prose.d.ts.map +1 -1
- package/lib/types/rules.d.ts +74 -15
- package/lib/types/rules.d.ts.map +1 -1
- package/lib/types/runtime.d.ts +59 -12
- package/lib/types/runtime.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +9 -4
- package/src/prose.ts +21 -0
- package/src/rules.ts +131 -24
- package/src/runtime.ts +140 -24
- package/README-es.md +0 -443
- package/README-hi.md +0 -445
- package/README-pt.md +0 -443
- package/README-zh.md +0 -443
package/README.es.md
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/dsh-permission-rules-hero-en-dark.webp">
|
|
5
|
+
<img src="docs/assets/dsh-permission-rules-hero-en-light.webp" width="100%" alt="El libro de decisiones de dsh-permission-rules: la primera coincidencia de una cadena de reglas ordenada, su tarjeta de veredicto deny y la franja del proxy para la salida de shell">
|
|
6
|
+
</picture>
|
|
7
|
+
|
|
8
|
+
# dsh-permission-rules
|
|
9
|
+
|
|
10
|
+
**Recupera la autoridad de decisión sobre las llamadas de herramientas: cada allow / deny / ask vive en YAML, de forma determinista, instantánea y auditable.**
|
|
11
|
+
|
|
12
|
+
Un middleware de permisos declarativo al estilo Claude Code para DeepSeek Harness: las reglas deciden lo conocido y un modelo revisor decide lo desconocido; además incluye una política de red de nivel de proceso al estilo Codex y un proxy local que gobiernan la salida de los subprocesos de shell.
|
|
13
|
+
|
|
14
|
+
[Instalar](#instalación-en-tres-pasos) · [Configuración](#configuración) · [FAQ](#faq) · [简体中文](README.md) · [English](README.en.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
|
|
15
|
+
|
|
16
|
+
[](LICENSE)
|
|
17
|
+
[](#compatibilidad)
|
|
18
|
+
[](https://www.npmjs.com/package/dsh-permission-rules)
|
|
19
|
+
[](https://github.com/PerryLink/dsh-permission-rules/actions/workflows/ci.yml)
|
|
20
|
+
[](#compatibilidad)
|
|
21
|
+
|
|
22
|
+
[](https://github.com/PerryLink/dsh-permission-rules/stargazers)
|
|
23
|
+
[](https://www.npmjs.com/package/dsh-permission-rules)
|
|
24
|
+
[](https://dshfind.com/plugins/PerryLink/dsh-permission-rules?ref=badge)
|
|
25
|
+
[](https://securityscorecards.dev/viewer/?uri=github.com/PerryLink/dsh-permission-rules)
|
|
26
|
+
[](https://dsh.market/)
|
|
27
|
+
[](https://gitee.com/perrylink/dsh-permission-rules)
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
dsh plugin --profile <name> add dsh-permission-rules
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<sub>Plugin de la comunidad, no afiliado a DeepSeek. Repositorio canónico: <https://github.com/PerryLink/dsh-permission-rules> (Gitee es un espejo).</sub>
|
|
36
|
+
|
|
37
|
+
## Qué es
|
|
38
|
+
|
|
39
|
+
`dsh-permission-rules` pone una lista ordenada de reglas **`allow` / `deny` / `ask`** delante de cada llamada de herramienta en el waterfall `tools/pre-execute`: determinista, instantánea, auditable y escrita por ti en YAML puro. Las reglas deciden las llamadas que conoces; las dudosas van al seam oficial de aprobación, donde responde un modelo revisor o una persona. Una segunda capa añade una política de red de nivel de proceso al estilo Codex: la salida de los subprocesos de shell pasa por un proxy local HTTP/CONNECT integrado, regido por reglas de red o por tres modos mapeados a los presets oficiales de sandbox.
|
|
40
|
+
|
|
41
|
+
<picture>
|
|
42
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/dsh-permission-rules-flow-v5-dark.svg">
|
|
43
|
+
<img src="docs/assets/dsh-permission-rules-flow-v5-light.svg" width="100%" alt="Estructura de dsh-permission-rules: las llamadas de herramientas y la salida de shell confluyen en una cadena de reglas ordenada, se bifurcan en veredictos de herramientas y de red, y cierran con dos eventos de auditoría solo-log">
|
|
44
|
+
</picture>
|
|
45
|
+
|
|
46
|
+
*Estructura: dos canales (llamadas de herramientas / salida de shell) confluyen en una cadena de reglas ordenada —gana la primera coincidencia— y se bifurcan en veredictos de herramientas y de red, cerrados por dos eventos de auditoría solo-log.*
|
|
47
|
+
|
|
48
|
+
## Instalación en tres pasos
|
|
49
|
+
|
|
50
|
+
1. **Instala** (elige un canal):
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
# canal git (main más reciente; el script prepare compila solo con dependencias de producción)
|
|
54
|
+
dsh plugin --profile web add github:PerryLink/dsh-permission-rules
|
|
55
|
+
# canal npm (versiones publicadas)
|
|
56
|
+
dsh plugin --profile web add dsh-permission-rules
|
|
57
|
+
# canal tarball: pnpm pack en este repo y luego
|
|
58
|
+
dsh plugin --profile web add ./dsh-permission-rules-<version>.tgz
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. **Escribe tu primera regla** (`.dsh/rules.yaml` en la raíz del proyecto; es opcional, la línea base de alto riesgo viene activada):
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
# <project>/.dsh/rules.yaml
|
|
65
|
+
rules:
|
|
66
|
+
- match: { tools: [bash, pwsh], params: { command: "git push*" }, paths: ["**/secrets/**"] }
|
|
67
|
+
action: deny
|
|
68
|
+
reason: "No pushes from protected paths"
|
|
69
|
+
|
|
70
|
+
- match: { tools: [edit, write] }
|
|
71
|
+
action: ask
|
|
72
|
+
reason: "File writes need confirmation"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
3. **Verifica que se monta**:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# tras reiniciar el perfil, confirma la fila del plugin
|
|
79
|
+
dsh --profile web --dump-config | grep -A4 'id: permission-rules'
|
|
80
|
+
# evalúa en seco una llamada hipotética en la superficie de comandos real; no ejecuta ninguna herramienta
|
|
81
|
+
/rules test bash {"command":"git push origin main","cwd":"src/secrets/app"}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
"bash" matches rule 1 (deny): 禁止 push 到受保护路径
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Desinstalar**: `dsh plugin --profile web remove dsh-permission-rules` (o borra la fila del patch del perfil).
|
|
89
|
+
|
|
90
|
+
<details>
|
|
91
|
+
<summary>Instalar desde el mercado de DSH Desktop</summary>
|
|
92
|
+
|
|
93
|
+
Todos los plugins de PerryLink figuran en el mercado integrado de DSH Desktop: **Mercado → Fuentes → Añadir fuente → pega** `https://perrylink-dsh-catalog.perrylink.workers.dev/catalog-source.json` **→ selecciona**. La instalación sigue requiriendo la verificación de identidad npm del mercado y tu confirmación.
|
|
94
|
+
|
|
95
|
+
</details>
|
|
96
|
+
|
|
97
|
+
## Capacidades clave
|
|
98
|
+
|
|
99
|
+
`dsh-permission-rules` pone reglas ordenadas delante de cada llamada de herramienta en `tools/pre-execute`: determinista, instantáneo, auditable:
|
|
100
|
+
|
|
101
|
+
- **`deny`** bloquea la llamada; el `reason` de la regla se convierte en el error visible para el modelo.
|
|
102
|
+
- **`ask`** usa el seam oficial de aprobación (monta `dsh-auto-review` para que responda un segundo modelo, o responde una persona; sin ninguno, el harness falla cerrado).
|
|
103
|
+
- **`allow`** (y la ausencia de coincidencia) delega estrictamente vía `next()`: los listeners posteriores nunca se cortocircuitan.
|
|
104
|
+
|
|
105
|
+
Cada acierto **y** cada paso directo se audita como evento de sesión `permissionRules/decision` (solo registro: no se inyecta nada extra en el contexto del modelo).
|
|
106
|
+
|
|
107
|
+
- **Coincidencia rica** — globs de nombre de herramienta (incluido `mcp__*`), selectores de identidad de agente (`main` / `subagent` / `preset:*`), globs **o** regex de claves/valores de argumentos (con negación `!pattern` y la dimensión de clave `absent`), globs de rutas relativas al workspace a **cualquier profundidad**, condiciones de host `when` (variables de entorno, plataforma) y **descomposición de comandos de shell** (`argv`: palabra de comando, tokens de argumento, firma de tubería) para coincidencias precisas a nivel de token.
|
|
108
|
+
- **Línea base de alto riesgo integrada** — un conjunto deny/ask incluido (comandos destructivos, escalada de privilegios, descarga y ejecución, rutas sensibles) activado por defecto y añadido tras las reglas de usuario, de modo que una regla más cercana puede anularlo; se controla con `builtin.enabled`.
|
|
109
|
+
- **Archivos de reglas jerárquicos** — `searchUp` opcional fusiona cada `.dsh/rules.yaml` desde el cwd de la sesión hasta la raíz del sistema, lo más cercano primero.
|
|
110
|
+
- **Despliegue en simulación** — `enforce: false` audita lo que la política *haría* mientras deja pasar cada llamada.
|
|
111
|
+
- **Recarga en caliente** — watch de Chokidar con debounce; una edición rota a nivel de archivo conserva las reglas anteriores y nunca bloquea, mientras que una sola regla inválida solo se deshabilita a sí misma. En un host WSL, o para un archivo bajo `/mnt/<unidad>`, el watch pasa a polling porque allí los eventos nativos no son fiables.
|
|
112
|
+
- **Ruidosa pero acotada** — los errores de archivo (YAML inválido y similares) siguen `badFilePolicy`; una regla inválida (glob/regex malo, campo/acción desconocidos) solo se deshabilita a sí misma y se muestra al inicio y en `/rules`, mientras las demás siguen funcionando (issue #49).
|
|
113
|
+
|
|
114
|
+
### Superficie de comandos y herramientas
|
|
115
|
+
|
|
116
|
+
| Superficie | Tipo | Notas |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `tools/pre-execute` | listener | Reglas allow/deny/ask de primera coincidencia + extracción de URL candidatas de red |
|
|
119
|
+
| `/rules` | command | `list` · `reload` · `decisions [n]` · `test <tool> <json>` |
|
|
120
|
+
| `permissionRules/decision` | event | Auditoría solo-log de cada acierto y paso directo |
|
|
121
|
+
| `permissionRules/network` | event | Auditoría de la capa proxy para conexiones bloqueadas |
|
|
122
|
+
| HTTP/CONNECT proxy | service | Proxy local integrado que gobierna el tráfico de los subprocesos de shell |
|
|
123
|
+
| settings page | client | Editor de modo de red, editor de reglas, contadores de bloqueos e intercepciones recientes con acción de permitir por bloqueo |
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
/rules list the active rules, their source files, and any last-reload error
|
|
127
|
+
/rules list explicit alias for the bare listing
|
|
128
|
+
/rules reload re-read the rule-file chain for this workspace
|
|
129
|
+
/rules decisions [n] show the last n permission decisions of this session (default 10)
|
|
130
|
+
/rules test <tool> <json> dry-evaluate the rules against a hypothetical call
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`/rules test` también acepta flags iniciales: `--cwd <dir>`, `--env KEY=VALUE` (repetible), `--agent <selector>` (repetible) y `--platform <name>`. En cadenas de varios archivos (p. ej. `searchUp`), cada línea de regla listada se atribuye a su propio archivo de origen.
|
|
134
|
+
|
|
135
|
+
### Ejemplos
|
|
136
|
+
|
|
137
|
+
Estos son los puntos de entrada reales del plugin; instala una vez y llama a uno.
|
|
138
|
+
|
|
139
|
+
**Ejemplo detallado** — comando `/rules test bash {"command":"git push origin main","cwd":"src/secrets/app"}`, salida:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
"bash" matches rule 1 (deny): 禁止 push 到受保护路径
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
*Observed from `test/command.spec.ts:204-219 (assertions at :209-213); src/prose.ts:121`*
|
|
146
|
+
|
|
147
|
+
**Rama de fallo** — entrada `/rules test bash {not json`, salida:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
Invalid JSON arguments "{not json": the arguments must parse as JSON.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
*Observed from `plugins/dsh-permission-rules/src/prose.ts:123; plugins/dsh-permission-rules/src/runtime.ts:1266-1272; plugins/dsh-permission-rules/test/command.spec.ts:221-228`*
|
|
154
|
+
|
|
155
|
+
**Ejemplos breves**: `tools/pre-execute` · `/rules test <tool> <json>`
|
|
156
|
+
|
|
157
|
+
## Sintaxis de reglas
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
# <project>/.dsh/rules.yaml
|
|
161
|
+
rules:
|
|
162
|
+
- match: { tools: [bash, pwsh], params: { command: "git push*" }, paths: ["**/secrets/**"] }
|
|
163
|
+
action: deny
|
|
164
|
+
reason: "No pushes from protected paths"
|
|
165
|
+
|
|
166
|
+
- match: { tools: [edit, write] }
|
|
167
|
+
action: ask
|
|
168
|
+
reason: "File writes need confirmation"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- **Dimensiones de coincidencia** — `tools` (globs, incl. `mcp__*`), `agents` (`main` / `subagent` / `preset:<name>`; una identidad desconocida nunca coincide: falla cerrado), `params` (globs o regex de clave/valor, negación `!pattern`, dimensión de clave `absent`), `paths` (globs relativos al workspace extraídos a cualquier profundidad), `when` (globs/regex de variables `env` + lista cerrada `platform`) y `network` (`domains` / `ips` / `ports` / `schemes`: globs, comodines, CIDRs, rangos de puertos).
|
|
172
|
+
- **Acciones** — `allow` / `deny` / `ask`, evaluadas en orden de archivo, gana la primera coincidencia.
|
|
173
|
+
- **Metadatos de regla** — `enabled: false` (visible pero inerte), `description`, `tags`; los campos desconocidos fallan al cargar.
|
|
174
|
+
- **Esquema** — un JSON Schema en [docs/rules-format.schema.json](docs/rules-format.schema.json) (autocompletado del editor con `# yaml-language-server: $schema=...`); el vocabulario completo y una línea base de seguridad de 5 reglas están en [docs/rules-format.en.md](docs/rules-format.en.md).
|
|
175
|
+
|
|
176
|
+
## Política de red
|
|
177
|
+
|
|
178
|
+
Una **política de red de nivel de proceso** al estilo Codex: el tráfico de los subprocesos de shell pasa por un **proxy HTTP/CONNECT local integrado**, y cada conexión la deciden reglas de red ordenadas o tres modos mapeados a los presets oficiales de sandbox:
|
|
179
|
+
|
|
180
|
+
- **`deny-all`** — el preset de sandbox de solo lectura: bloquea toda salida.
|
|
181
|
+
- **`whitelist`** — el preset workspace-write: permite los objetivos listados y aplica `unlisted: ask` (o `deny`) al resto.
|
|
182
|
+
- **`allow-all`** — el preset danger-full-access: permite todo.
|
|
183
|
+
- **`auto`** (predeterminado) — sigue el preset de sandbox; en hosts sin el servicio de política de sandbox se resuelve en `autoFallback` (`allow-all`).
|
|
184
|
+
|
|
185
|
+
- **Coincidencia** — `match.network` con `domains` / `ips` / `ports` / `schemes` (globs, comodines, CIDRs, rangos de puertos; se aceptan puertos YAML numéricos). La extracción de URL candidatas en la ruta caliente `tools/pre-execute` se dispara con argumentos de herramientas web y URL incrustadas en el texto de comandos bash/pwsh; los objetivos de loopback pueden cortocircuitar reglas según la política `loopback`. Los literales IPv6 mapeados desde IPv4 se normalizan a su forma IPv4 antes de comparar, y el proxy conecta a las direcciones sobre las que se decidió, nunca a una segunda resolución DNS: una conexión cuya adjudicación no resolvió ninguna dirección falla cerrada (502) en lugar de marcar el nombre.
|
|
186
|
+
- **Encadenado ascendente** — `network.upstreamProxy` (por defecto `off`) envía las conexiones que este proxy **permite** a través de un proxy ascendente: CONNECT pide al ascendente un túnel (`CONNECT host:port`) y las peticiones HTTP simples se reenvían en forma absoluta. Un objetivo bloqueado nunca llega al ascendente: sigue recibiendo el 403 estructurado de este plugin. Dos casos nunca se encadenan aunque haya un ascendente configurado: un objetivo de **loopback** (un proxy fuera de este host no puede enrutar su loopback) y cualquier decisión producida por una **regla con alcance `ips`** (el encadenado entrega el nombre de host al ascendente, así que "la conexión aterriza en una dirección que las reglas vieron" — issue #21 — dejaría de cumplirse justo donde a las reglas les importaba la dirección; esas decisiones siguen marcando directamente la dirección adjudicada), más un objetivo cuyo scheme no tiene ascendente utilizable. El nombre de host del propio ascendente es configuración del operador, no entrada del agente, y no lo adjudican estas reglas. Una URL con credenciales nunca se emite en crudo: los avisos, `/rules network` y la instantánea de la página de ajustes enmascaran la contraseña (`http://user:***@host:port`). Un ascendente inalcanzable, un timeout (10 s) o una respuesta no 2xx producen **502**; deliberadamente no hay fallback silencioso a la conexión directa, para que una mala configuración siga siendo visible.
|
|
187
|
+
- **Auditoría** — las conexiones denegadas añaden `permissionRules/network` a la sesión propietaria (misma puerta adaptativa `ignorable`), con contadores de bloqueos e intercepciones recientes en `/rules network` y en la página de ajustes.
|
|
188
|
+
- **Diagnóstico** — las conexiones bloqueadas llevan un mensaje `[network: …]` que nombra el objetivo bloqueado, el modo o la regla que decidió y la remediación.
|
|
189
|
+
- **Permitir desde la página de ajustes** — cada intercepción reciente ofrece una acción **Permitir**. Escribe UNA regla mínima `match: { network: { domains: [<host>] } }` / `action: allow` en la **parte superior** (índice 0) del archivo de reglas más cercano que realmente juzga esa conexión: el archivo de proyecto del workspace al que se atribuyó el bloqueo (el `rulesFile` absoluto cuando está configurado) o, para un bloqueo de nivel de host sin sesión, el archivo que resuelve la cadena de host (`rulesFile` absoluto → `<processCwd>/<rulesFile>` existente → `fallbackPath` configurado → `<processCwd>/<rulesFile>`, creado); y cuando hay varios workspaces cargados, la página ofrece primero un selector, porque cualquier cadena de workspace cargada supera a la cadena de host. Índice 0 porque las reglas son de primera coincidencia: añadida tras un `deny` existente, la regla sería texto muerto. Solo `domains`, porque esa dimensión incluye subdominios y es ajena a puerto/scheme, así que el host no se vuelve a bloquear en su siguiente puerto; los comentarios existentes y las reglas no tocadas sobreviven, y el texto pasa por la misma puerta de validación que una edición manual. El cambio surte efecto de inmediato — se releen las cadenas de workspace en caché Y la cadena de host sin sesión, sin reinicio y sin `/rules reload` — y la decisión se recalcula, así que el aviso informa el resultado REAL y nunca afirma éxito mientras la conexión sigue bloqueada. Rechaza, dejando el archivo intacto, un workspace desconocido, un objetivo fuera de las fuentes de reglas conocidas, la línea base integrada de solo lectura y un archivo que no puede leer o parsear; una conexión ya permitida no escribe nada. `network.allowHostAction: false` oculta el botón y hace que el RPC rechace.
|
|
190
|
+
|
|
191
|
+
## Configuración
|
|
192
|
+
|
|
193
|
+
Todos los ajustes son campos `Config` de Schemastery (modificables desde cordis.yml). Una anulación dirigida por id reemplaza la fila entera: repite cada clave que necesites. En un host `0.1.7-alpha` cada campo se declara `.volatile()`, así que también se edita in situ desde la página de ajustes de Plugins: la edición se confirma en las referencias en ejecución sin remontar el plugin, el runtime lee el nuevo valor en su siguiente uso, y un cambio en `network.proxyPort`, `proxyBind`, `injectEnv` o `noProxy` reengancha el proxy local de inmediato. Los límites numéricos viven en el esquema, y el editor de configuración resuelve la configuración fusionada contra ese esquema antes de persistir, de modo que un valor fuera de rango se rechaza en el momento de escribir. En un host cuyo Schemastery es anterior a `volatile()`, estos campos solo se cambian por cordis.yml.
|
|
194
|
+
|
|
195
|
+
Claves más usadas:
|
|
196
|
+
|
|
197
|
+
| Clave | Predeterminado | Significado |
|
|
198
|
+
|---|---|---|
|
|
199
|
+
| `rulesFile` | `.dsh/rules.yaml` | Ubicación del archivo de reglas; relativa = resuelta contra el cwd de la sesión llamante, absoluta = global y validada al montar |
|
|
200
|
+
| `fallbackPath` | *(none)* | Archivo de reglas usado cuando el descubrimiento por cwd no encuentra nada; validado al montar |
|
|
201
|
+
| `badFilePolicy` | `fail` | Fallos de archivo: `fail` hace fallar ruidosamente la llamada pendiente; `ignore-with-warning` avisa y continúa vacío. Una regla inválida siempre se aísla: esa regla se deshabilita y se informa al inicio y en `/rules` |
|
|
202
|
+
| `maxRules` | `256` | Límite duro de reglas en la cadena efectiva de fuentes |
|
|
203
|
+
| `patternMode` | `glob` | Estilo de patrón de `params`/`paths`/`when.env`: `glob` o `regex` (los nombres de herramienta son siempre globs) |
|
|
204
|
+
| `watch` | `true` | Watch de Chokidar + recarga al cambiar |
|
|
205
|
+
| `enforce` | `true` | `false` = modo simulación: los aciertos deny/ask se auditan con marca `dryRun` y toda llamada pasa |
|
|
206
|
+
| `language` | `en` | Idioma de salida de `/rules`: `en`, `zh`, `es`, `pt`, `hi` |
|
|
207
|
+
|
|
208
|
+
<details>
|
|
209
|
+
<summary>Tabla de configuración completa (29 claves)</summary>
|
|
210
|
+
|
|
211
|
+
| Clave | Predeterminado | Significado |
|
|
212
|
+
|---|---|---|
|
|
213
|
+
| `rulesFile` | `.dsh/rules.yaml` | Ubicación del archivo de reglas; relativa = resuelta contra el cwd de la sesión llamante, absoluta = global y validada al montar |
|
|
214
|
+
| `fallbackPath` | *(none)* | Archivo de reglas usado cuando el descubrimiento por cwd no encuentra nada; validado al montar |
|
|
215
|
+
| `badFilePolicy` | `fail` | Fallos de archivo: `fail` hace fallar ruidosamente la llamada pendiente; `ignore-with-warning` avisa y continúa vacío. Una regla inválida siempre se aísla: esa regla se deshabilita y se informa al inicio y en `/rules` |
|
|
216
|
+
| `maxRules` | `256` | Límite duro de reglas en la cadena efectiva de fuentes |
|
|
217
|
+
| `maxCachedWorkspaces` | `512` | Límite duro de cargas de reglas por workspace en caché (expulsión LRU) |
|
|
218
|
+
| `patternMode` | `glob` | Estilo de patrón de `params`/`paths`/`when.env`: `glob` o `regex` (los nombres de herramienta son siempre globs) |
|
|
219
|
+
| `watch` | `true` | Watch de Chokidar + recarga al cambiar |
|
|
220
|
+
| `watchStabilityThresholdMs` | `200` | Ventana de debounce de recarga (ms) |
|
|
221
|
+
| `language` | `en` | Idioma de salida de `/rules`: `en`, `zh`, `es`, `pt`, `hi` |
|
|
222
|
+
| `caseInsensitivePaths` | *(win32)* | Los patrones `paths` y la comparación con la raíz del workspace ignoran mayúsculas ASCII; `true` en Windows |
|
|
223
|
+
| `audit` | `all` | Granularidad de auditoría: `all` registra cada acierto Y cada paso directo; `hits` omite los pasos directos |
|
|
224
|
+
| `searchUp` | `false` | Recorre los directorios padre desde el cwd de la sesión y fusiona cada archivo de reglas encontrado, el más cercano primero |
|
|
225
|
+
| `maxGlobStars` | `2` | Límite duro de cuantificadores `*`/`**` sin límite por patrón glob |
|
|
226
|
+
| `enforce` | `true` | `false` = modo simulación: los aciertos deny/ask se auditan con marca `dryRun` y toda llamada pasa |
|
|
227
|
+
| `allowUnmarkedAudit` | `false` | Los hosts pre-marcador descartan la marca `ignorable`; el plugin desactiva la auditoría del registro de sesión con un aviso. Pon `true` para reactivarla |
|
|
228
|
+
| `network.enabled` | `true` | Interruptor maestro del proxy, la inyección de entorno y los valores por defecto del modo de herramientas web |
|
|
229
|
+
| `network.mode` | `auto` | Modo de política: `auto` sigue el preset de sandbox, o `deny-all` / `whitelist` / `allow-all` |
|
|
230
|
+
| `network.autoFallback` | `allow-all` | Modo usado cuando `auto` no tiene servicio de política de sandbox |
|
|
231
|
+
| `network.unlisted` | `ask` | Tratamiento en modo whitelist de objetivos sin coincidencia: `ask` o `deny` |
|
|
232
|
+
| `network.proxyBind` | `127.0.0.1` | Dirección de enlace del proxy local (solo loopback) |
|
|
233
|
+
| `network.proxyPort` | `0` | Puerto del proxy local; `0` elige un puerto efímero libre |
|
|
234
|
+
| `network.proxyMaxRecent` | `100` | Límite de registros de bloqueos recientes para la página de ajustes |
|
|
235
|
+
| `network.loopback` | `allow` | Objetivos de loopback: `allow` (paridad con Codex) o `policy` |
|
|
236
|
+
| `network.injectEnv` | `true` | Si se inyectan variables de entorno de proxy para los subprocesos |
|
|
237
|
+
| `network.noProxy` | `clear` | Manejo de NO_PROXY en subprocesos: `clear` impone la política o `preserve` |
|
|
238
|
+
| `network.upstreamProxy` | `off` | Proxy ascendente para las conexiones que este plugin PERMITE: `off` conecta directo, `inherit` reutiliza los nombres de proxy del entorno de lanzamiento, o una URL `http(s)://` explícita |
|
|
239
|
+
| `network.allowHostAction` | `true` | Acción "permitir este host" por bloqueo en la página de ajustes: `false` oculta el botón Permitir y hace que el RPC `permissionRules/allowHost` rechace (el editor de reglas no se ve afectado) |
|
|
240
|
+
| `builtin.enabled` | `true` | Línea base de alto riesgo integrada: `false` desactiva por completo el conjunto deny/ask incluido |
|
|
241
|
+
| `builtin.path` | *(incluido)* | Archivo de línea base de reemplazo (absoluto o relativo a `process.cwd()`); validado al montar |
|
|
242
|
+
|
|
243
|
+
</details>
|
|
244
|
+
|
|
245
|
+
## FAQ
|
|
246
|
+
|
|
247
|
+
<details>
|
|
248
|
+
<summary>¿Dónde viven los archivos de reglas? ¿El plugin escribirá en mis archivos?</summary>
|
|
249
|
+
|
|
250
|
+
Las reglas se leen de disco: `.dsh/rules.yaml` en la raíz del proyecto, o el `rulesFile` / `fallbackPath` configurado, fusionados hacia arriba con `searchUp`. La ruta normal de adjudicación no escribe ningún dato de reglas. Las únicas superficies de escritura son el editor de reglas de la página de ajustes y la acción "Permitir": esta última escribe una regla allow mínima al principio de una fuente de reglas conocida y vuelve a pasar la misma validación de parseo/compilación que una edición manual (ver "Política de red").
|
|
251
|
+
|
|
252
|
+
</details>
|
|
253
|
+
|
|
254
|
+
<details>
|
|
255
|
+
<summary>¿Qué pasa con ask si no está montado dsh-auto-review?</summary>
|
|
256
|
+
|
|
257
|
+
`ask` usa el seam oficial de aprobación: con `dsh-auto-review` montado responde un segundo modelo de solo lectura; si no, responde una persona; sin ninguno, el harness falla cerrado y la llamada nunca se permite en silencio. Este plugin nunca lanza subagentes ni llama a modelos: producir una decisión `ask` es el final de su trabajo.
|
|
258
|
+
|
|
259
|
+
</details>
|
|
260
|
+
|
|
261
|
+
<details>
|
|
262
|
+
<summary>¿Este proxy intercepta las peticiones salientes del propio host?</summary>
|
|
263
|
+
|
|
264
|
+
No. El entorno de proxy inyectado cubre los **hijos de shell lanzados** y cualquier consumidor que lea los nombres de proxy en el momento de la petición. **No** cubre el tráfico propio del proceso host basado en `fetch`: el launcher instala el dispatcher global de undici desde el entorno de lanzamiento antes de que se monte el primer plugin, y ese dispatcher enruta por su política, no por el entorno. Por tanto los endpoints del proveedor no necesitan regla de permiso, y `network.injectEnv: false` no saca al proceso host de nada. Medido el 2026-09-10 en Node 22; reproducible con `scripts/host-egress-probe.mjs`.
|
|
265
|
+
|
|
266
|
+
</details>
|
|
267
|
+
|
|
268
|
+
<details>
|
|
269
|
+
<summary>¿Cuánto cuesta en la ruta caliente?</summary>
|
|
270
|
+
|
|
271
|
+
La evaluación de reglas es un recorrido en memoria de primera coincidencia: sin llamadas a modelos ni peticiones de red; los aciertos y pasos directos solo añaden auditoría de sesión. Un watch que falla avisa y conserva las reglas anteriores. Con conjuntos grandes, pon `audit: hits` para omitir los pasos directos, o acota la carga con `maxRules` / `maxCachedWorkspaces`.
|
|
272
|
+
|
|
273
|
+
</details>
|
|
274
|
+
|
|
275
|
+
<details>
|
|
276
|
+
<summary>¿Compite con otros plugins por eventos, nombres de comando o slots?</summary>
|
|
277
|
+
|
|
278
|
+
No. Los nombres de herramienta llevan namespace y no se toma ningún nombre desnudo; las claves de servicio `permissionRules` / `permissionRulesRuntime` no son un seam integrado y ningún plugin de muchas estrellas encuestado las proporciona; no registra slots de cliente ni prefijos `webServer`, y su patch solo `insert`a su propia fila; los eventos compartidos siempre delegan vía `next()`. El argumento punto por punto está en "Interoperabilidad con otros plugins DSH".
|
|
279
|
+
|
|
280
|
+
</details>
|
|
281
|
+
|
|
282
|
+
## Límites de seguridad
|
|
283
|
+
|
|
284
|
+
- **Política, no kernel.** Los candidatos de `paths` vienen solo de un conjunto documentado de claves de argumento (a cualquier profundidad, con límite de profundidad), y solo coinciden rutas relativas al workspace.
|
|
285
|
+
- **Aquí no hay revisor.** El plugin nunca lanza subagentes ni llama a modelos: producir una decisión `ask` es el final de su trabajo.
|
|
286
|
+
- **Sin cambios de sandbox.** La política de sandbox a nivel de SO pertenece al seam de sandbox, no a este plugin.
|
|
287
|
+
- **Configuración inválida ruidosa.** Campos YAML desconocidos, acciones desconocidas y patrones malos se rechazan al cargar.
|
|
288
|
+
- **Límites de backtracking.** Los patrones glob se limitan a `maxGlobStars` expansiones de estrella sin límite; los patrones en modo regex rechazan cuantificadores anidados sin límite y alternancias literales solapadas cuantificadas.
|
|
289
|
+
- **Marcado que falla cerrado.** Los reenvíos HTTP planos y los túneles CONNECT solo conectan a direcciones adjudicadas; un allow cuya adjudicación no resolvió dirección falla cerrado con 502 en lugar de marcar el nombre (issue #23).
|
|
290
|
+
|
|
291
|
+
## Permisos y datos
|
|
292
|
+
|
|
293
|
+
- **Permisos**: declara `files:read`, `files:watch`, `files:write`, `session:append` y `network:outbound` en su manifiesto workshop. Las decisiones `ask` usan el seam oficial de aprobación: nada se reimplementa ni se evita.
|
|
294
|
+
- **Datos**: los archivos de reglas se leen de disco; la adjudicación normal no escribe datos de reglas: las únicas superficies de escritura son el editor de reglas de la página de ajustes y la acción "Permitir". Sin llamadas a modelos, sin subagentes revisores.
|
|
295
|
+
- **Registro de sesión**: `permissionRules/decision` nunca se inyecta en el contexto del modelo y se añade con la marca `ignorable: true` del sobre, de modo que cualquier build del harness carga el registro.
|
|
296
|
+
|
|
297
|
+
## Limitaciones conocidas
|
|
298
|
+
|
|
299
|
+
- **Marca de auditoría en hosts pre-marcador y hostiles.** `permissionRules/decision` se añade con `ignorable: true`; los hosts cuyo `Session.append` es anterior a la marca (las líneas `0.1.0-rc.1`–`rc.7` y `0.1.1-rc.1`–`rc.7`) la descartan en silencio, la línea `0.1.2-rc` trae la superficie alpha.5 (ninguna opción de append escribe la marca), la línea `0.1.2-alpha` rechaza los eventos de plugin al leer incluso marcados, y las líneas `0.1.3-alpha` y `0.1.5-alpha` mantienen la misma firma de append solo-superficie (verificado en los paquetes publicados `0.1.3-alpha.1`/`0.1.5-alpha.1`): el runtime precomprueba todas antes del primer append y desactiva la auditoría del registro de sesión con un aviso único. La migración entre generaciones también rechaza filas de auditoría marcadas: la puerta v1→v2 de `0.1.3-alpha` rechaza eventos v1 desconocidos, y la puerta v2→v3 de `0.1.5-alpha` rechaza todo evento no clasificado (su inventario está congelado al vocabulario v2 publicado), así que haz `strip` de las filas v1 antes de que un host 0.1.3 abra el registro y de las filas v2 antes de actualizar a un host 0.1.5. Los registros v3 nativos aceptan filas de plugin marcadas, así que solo necesitan `repair`. Pon `allowUnmarkedAudit: true` para reactivarla; repara los registros ya escritos con `scripts/repair-session-logs.mjs` (su modo `strip` elimina filas de auditoría donde la marca no ayuda).
|
|
300
|
+
- **Los candidatos de ruta son heurísticos.** Solo las claves de argumento documentadas alimentan la coincidencia de rutas, y la coincidencia relativa al workspace ignora mayúsculas ASCII solo con `caseInsensitivePaths` activo.
|
|
301
|
+
- **Los globs son un subconjunto conservador.** Sin expansión de llaves: escribe dos patrones, o usa el modo regex.
|
|
302
|
+
- **La guarda de backtracking regex es estructural, no exhaustiva.** Prefiere el modo glob para archivos no confiables.
|
|
303
|
+
- **Las peticiones salientes del propio host no pasan por este proxy.** El entorno de proxy inyectado cubre los **hijos de shell lanzados** —que es el propósito de la inyección— y cualquier consumidor que lea los nombres de proxy en el momento de la petición. **No** cubre el tráfico propio del proceso host basado en `fetch`: el launcher instala el dispatcher global de undici desde el **entorno de lanzamiento** antes de que se monte el primer plugin, ese dispatcher enruta por su política y no por el entorno, y Node muestrea el entorno de proxy al arrancar, así que un plugin montado después no puede redirigirlo. Consecuencias: los endpoints del proveedor **no** necesitan regla de permiso, y `network.injectEnv: false` no saca al proceso host de nada. Medido el 2026-09-10 en Node 22; reproducible con `scripts/host-egress-probe.mjs`.
|
|
304
|
+
- **El encadenado ascendente solo cubre lo que llega a este proxy.** En `dsh-v0.1.7-alpha.1` y posteriores, la política de proxy de lanzamiento del propio harness y su capa de entorno de subprocesos pueden tener precedencia sobre los nombres de proxy que este plugin inyecta, así que `network.upstreamProxy` describe lo que ocurre con las conexiones que maneja este proxy: no es una afirmación sobre cada ruta saliente del proceso host.
|
|
305
|
+
|
|
306
|
+
## Interoperabilidad con otros plugins DSH
|
|
307
|
+
|
|
308
|
+
Verificado contra **DSH `0.2.0-rc.2`** (el runtime para el que se publica este README) y el conjunto de plugins de muchas estrellas encuestado el 2026-10-05.
|
|
309
|
+
|
|
310
|
+
Este plugin **no interfiere** con otros plugins, incluidos los de muchas estrellas ampliamente instalados:
|
|
311
|
+
|
|
312
|
+
- **Sin colisión de nombres de herramienta.** Cada herramienta lleva namespace; no se registra ningún nombre desnudo propiedad de una herramienta incluida o de otro plugin.
|
|
313
|
+
- **Sin colisión de claves de servicio.** Proporciona `permissionRules`, `permissionRulesRuntime`; esas claves no son un seam integrado y ningún plugin de muchas estrellas encuestado las proporciona.
|
|
314
|
+
- **Sin colisión de slots.** No registra ninguna clave de slot de cliente, así que no compite por un asiento de `shadows-shipped-ui`.
|
|
315
|
+
- **Sin colisión de rutas HTTP.** No registra ningún prefijo `webServer`.
|
|
316
|
+
- **Sin colisión de capa patch.** El patch del bundle solo `insert`a su propia fila; nunca sobrescribe el `config` de una fila integrada.
|
|
317
|
+
- **Sin mutación global.** No parchea prototipos, no reescribe `process.env` ni reemplaza el dispatcher global de fetch.
|
|
318
|
+
|
|
319
|
+
**Los listeners de eventos compartidos no interfieren por construcción.** Observa los eventos sensibles al orden `tools/post-execute`, `tools/pre-execute` con `ctx.on()`: el registro de broadcast de Cordis, donde todos los listeners se ejecutan y ninguno puede dejar en inanición a otro. **Cada listener aquí delega vía `next()`**, así que la cadena nunca se cortocircuita, y una mutación se aplica al valor que produjo `next()` en lugar de sustituir su retorno:
|
|
320
|
+
|
|
321
|
+
- `tools/post-execute` — also used by `cc-safety-net` (1576★).
|
|
322
|
+
- `tools/pre-execute` — also used by `cc-safety-net` (1576★).
|
|
323
|
+
|
|
324
|
+
Evidencia estática: `dsh-plugin-doctor` K10–K13 informan `pass` en cada comprobación de este repositorio.
|
|
325
|
+
|
|
326
|
+
## Colaboración con dsh-auto-review
|
|
327
|
+
|
|
328
|
+
- `dsh-permission-rules` produce `ask`; `dsh-auto-review` responde en el waterfall `approval/request` con un veredicto de segundo modelo de solo lectura (o delega en personas). Monta ambos para el bucle cerrado completo.
|
|
329
|
+
- Probado en integración: `permissionRules/decision` → `approval/asked` → `autoReview/verdict` → `approval/decided`, con el revisor sustituido por un mock con script.
|
|
330
|
+
- La política de aprobación `never` y toda garantía de fallo cerrado del harness oficial permanecen intactas.
|
|
331
|
+
|
|
332
|
+
## Reparación de registros de sesión
|
|
333
|
+
|
|
334
|
+
Los registros de sesión escritos antes de que existiera la marca `ignorable` pueden ser rechazados por builds más nuevas del harness (`SessionFormatUnsupportedError`). El `scripts/repair-session-logs.mjs` incluido reescribe solo las filas de auditoría objetivo para que lleven `ignorable: true`, preservando el frame y con copias de seguridad:
|
|
335
|
+
|
|
336
|
+
```sh
|
|
337
|
+
node scripts/repair-session-logs.mjs scan [--home DIR] # reporta filas ajenas, no cambia nada
|
|
338
|
+
node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
|
|
339
|
+
node scripts/repair-session-logs.mjs strip [--home DIR] [--dry-run]
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
`--home` por defecto es `$DSH_HOME/sessions` (o `~/.dsh/sessions`). Cada registro direccionado por generación se descubre por su basename canónico — `session.jsonl`, `session.v2.jsonl`, `session.v3.jsonl`, cada uno opcionalmente comprimido con `.zstd` — así que elige el modo según la generación:
|
|
343
|
+
|
|
344
|
+
- **v3 (`session.v3.jsonl`, escrito nativamente por la línea `0.1.5-alpha`)** — la ruta de lectura acepta filas de plugin marcadas, así que basta con `repair`.
|
|
345
|
+
- **v2 (`session.v2.jsonl`, escrito por la línea `0.1.3-alpha`)** — `repair` lo abre en el host que lo escribió, pero la migración v2→v3 de `0.1.5-alpha` rechaza todo evento no clasificado aunque esté marcado: ejecuta `strip` sobre los registros v2 **antes** de actualizar a un host `0.1.5-alpha`.
|
|
346
|
+
- **v1 (`session.jsonl`)** — la migración v1→v2 de `0.1.3-alpha` rechaza eventos v1 desconocidos aunque estén marcados: ejecuta `strip` antes de que un host 0.1.3 o posterior abra el registro por primera vez.
|
|
347
|
+
|
|
348
|
+
## Compatibilidad
|
|
349
|
+
|
|
350
|
+
| Superficie | Estado |
|
|
351
|
+
|---|---|
|
|
352
|
+
| Harness | DeepSeek Harness `dsh-v0.2.1-alpha.1` (adaptado el 2026-09-22, cadena de puertas completa): su configuración de plugin es el contrato de ajustes en vivo — cada campo se declara `.volatile()`, el Loader entrega a `apply` una referencia viva por campo, y una edición guardada se confirma en las referencias en ejecución SIN remontar el plugin, con valores fuera de rango rechazados por el esquema antes de escribir nada. Un host cuyo Schemastery es anterior a `volatile()` (antes de 3.18.3) sigue montando y ejecutando este plugin — los campos simplemente quedan como valores ordinarios y el formulario de configuración en vivo no está disponible — porque la marca se aplica mediante una sonda de capacidad, no por suposición. `Session.append` en esta línea aún no puede estampar la marca `ignorable` (su tercer argumento es la bolsa de intención de superficie, y el campo del sobre sobrevive solo para lecturas de registros almacenados), así que toda la línea `0.2-alpha` se precomprueba como sin marca y la auditoría del registro de sesión queda desactivada por defecto — `append` solo lee `sourceEventSeqs`/`surfaceOp` y congela el sobre, así que no tiene ruta de código que pueda estampar la marca; las líneas anteriores `0.1.7-alpha` (adaptada el 2026-09-22), `0.1.5-rc.2` (adaptada el 2026-09-09) y `0.1.3-alpha` mantienen la misma firma de append solo-superficie, y cada prelanzamiento `0.2` se clasifica con ellas (una versión ESTABLE `0.2.x` se deja a la sonda de append, así que una superficie de marca restaurada se adopta sin un nuevo release del plugin). Las migraciones de registro de esas líneas rechazan eventos de plugin no clasificados incluso marcados, así que haz `strip` de las filas de auditoría v1 antes de que un host `0.1.3-alpha` abra el registro y de las filas v2 antes de que lo migre un host `0.1.5-alpha` (los registros v3 nativos solo necesitan `repair`). |
|
|
353
|
+
| Node | `^22.19.0 || >=24.9.0` |
|
|
354
|
+
| Plataformas | Todas (host + cliente web de ajustes) |
|
|
355
|
+
| Modelo | Cualquiera (los motivos deny/ask se muestran a través de los resultados de herramientas) |
|
|
356
|
+
|
|
357
|
+
## Ecosistema y calidad
|
|
358
|
+
|
|
359
|
+
- [Espejo Gitee](https://gitee.com/perrylink/dsh-permission-rules) (espejo sincronizado; GitHub es canónico)
|
|
360
|
+
- [Página del plugin en dshfind](https://dshfind.com/plugins/PerryLink/dsh-permission-rules) (instalaciones y ranking)
|
|
361
|
+
- [Informe OpenSSF Scorecard](https://securityscorecards.dev/viewer/?uri=github.com/PerryLink/dsh-permission-rules) (impulsado por [.github/workflows/scorecard.yml](.github/workflows/scorecard.yml))
|
|
362
|
+
- [Informe de verificación de dsh-plugin-doctor](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章) (K10–K13 todos `pass`)
|
|
363
|
+
- [DSH Market](https://dsh.market/) (listado)
|
|
364
|
+
- **Canal de la tienda 1024**: `npm i -g dsh1024` una vez, luego `dsh1024 plugin --profile web add dsh-permission-rules` (cuenta para el ranking de instalaciones de [deepseek1024.com](https://deepseek1024.com))
|
|
365
|
+
- [Base de conocimiento del ecosistema](https://perrylink.github.io/dsh-plugin-guide/): datos medidos, no marketing: guía de desarrollo de plugins · datos de selección de plugins · criterios de mantenimiento
|
|
366
|
+
|
|
367
|
+
## Desarrollo
|
|
368
|
+
|
|
369
|
+
```sh
|
|
370
|
+
pnpm install # node ^22.19 || >=24.9
|
|
371
|
+
pnpm run typecheck # tsc, src + tests
|
|
372
|
+
pnpm run lint # eslint, src + tests + scripts
|
|
373
|
+
pnpm test # vitest: 24 spec files
|
|
374
|
+
pnpm run test:coverage # coverage gate (90/80/90/90)
|
|
375
|
+
pnpm run build # tsc declarations + tsdown bundles (lib/)
|
|
376
|
+
pnpm run pack:check # build + pack (the published artifact)
|
|
377
|
+
node scripts/check-readme-sync.mjs # puerta de sincronización de los README en cinco idiomas (también en CI)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Consulta [VERIFICATION.md](VERIFICATION.md) para el registro de verificación end-to-end sin interfaz. Las imágenes del README se generan programáticamente con [`scripts/gen-readme-assets.py`](scripts/gen-readme-assets.py) (Pillow dibuja los banners hero de 1440×576 en chino/inglés y claro/oscuro; un SVG de 1100×660 dibujado a mano es la figura de estructura) y se pueden volver a ejecutar sin riesgo.
|
|
381
|
+
|
|
382
|
+
Topics: `dsh`, `dsh-plugin`, `deepseek-harness`, `permission`, `policy`, `allow-deny-ask`, `approval`, `safety`, `network`, `network-policy`, `proxy`
|
|
383
|
+
|
|
384
|
+
## Familia y agradecimientos
|
|
385
|
+
|
|
386
|
+
Este proyecto forma parte de la familia de plugins de DeepSeek Harness de [PerryLink](https://github.com/PerryLink) (todos Apache-2.0). Si te resulta útil, **una estrella ayuda a que la siguiente persona lo encuentre** — no hay nada bloqueado tras ella.
|
|
387
|
+
|
|
388
|
+
- [@PerryLink](https://github.com/PerryLink) — creador y mantenedor: vocabulario y evaluación de reglas, runtime, watch HMR, auditoría del registro de sesión, política de red + proxy y la documentación en cinco idiomas.
|
|
389
|
+
- [@am-i-dead](https://github.com/am-i-dead) — separó los helpers allow-host seguros para el cliente del módulo solo-host (#24).
|
|
390
|
+
- [@22xuan](https://github.com/22xuan) — el informe detallado sobre los hosts rc.6 que descartan en silencio la marca `ignorable` del evento de auditoría ([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2)) y la discusión upstream del harness; la detección de capacidades del host en v0.4.1 y la corrección de la documentación se derivaron directamente de ese análisis.
|
|
391
|
+
- [@sjh9714](https://github.com/sjh9714) — propuso el corpus compartido de vectores de prueba de sintaxis de reglas ([#4](https://github.com/PerryLink/dsh-permission-rules/issues/4), [#5](https://github.com/PerryLink/dsh-permission-rules/issues/5)), publicado en v0.5.1 como `docs/rule-test-vectors/`, y aportó los casos límite de descomposición AST en la [discusión de diseño](https://github.com/PerryLink/dsh-permission-rules/discussions/10).
|
|
392
|
+
- [@weipeng1999](https://github.com/weipeng1999) — la propuesta de descomposición de comandos basada en AST ([#8](https://github.com/PerryLink/dsh-permission-rules/issues/8)) detrás de la discusión de diseño.
|
|
393
|
+
- [@alexchenzl](https://github.com/alexchenzl) — la solicitud de listado en el DSH Directory ([#7](https://github.com/PerryLink/dsh-permission-rules/issues/7)).
|
|
394
|
+
- [@zl190](https://github.com/zl190) — informó y verificó la brecha de compatibilidad con el harness `0.1.0-rc.7` ([PR #9](https://github.com/PerryLink/dsh-permission-rules/pulls/9)).
|
|
395
|
+
- [@cuohua](https://github.com/cuohua) — informó que la línea `0.1.1-rc` sigue descartando la marca `ignorable` aunque la puerta de versión solo cubría `0.1.0` ([#11](https://github.com/PerryLink/dsh-permission-rules/issues/11)); la puerta ampliada se derivó directamente de ese análisis.
|
|
396
|
+
|
|
397
|
+
<details>
|
|
398
|
+
<summary>Expandir todos los plugins</summary>
|
|
399
|
+
|
|
400
|
+
| Plugin | Estado |
|
|
401
|
+
|---|---|
|
|
402
|
+
| **[dsh-aqua-input-check](https://github.com/PerryLink/dsh-aqua-input-check)** | |
|
|
403
|
+
| **[dsh-archive-check](https://github.com/PerryLink/dsh-archive-check)** | |
|
|
404
|
+
| **[dsh-auto-review](https://github.com/PerryLink/dsh-auto-review)** | |
|
|
405
|
+
| **[dsh-autotier](https://github.com/PerryLink/dsh-autotier)** | 🧊 CONGELADO — ver el README del repo |
|
|
406
|
+
| **[dsh-bid-ca-precheck](https://github.com/PerryLink/dsh-bid-ca-precheck)** | |
|
|
407
|
+
| **[dsh-bid-qual-check](https://github.com/PerryLink/dsh-bid-qual-check)** | |
|
|
408
|
+
| **[dsh-cert-mcp](https://github.com/PerryLink/dsh-cert-mcp)** | 🧊 CONGELADO — ver el README del repo |
|
|
409
|
+
| **[dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind)** | |
|
|
410
|
+
| **[dsh-click](https://github.com/PerryLink/dsh-click)** | |
|
|
411
|
+
| **[dsh-composer-history](https://github.com/PerryLink/dsh-composer-history)** | |
|
|
412
|
+
| **[dsh-contract-stance](https://github.com/PerryLink/dsh-contract-stance)** | |
|
|
413
|
+
| **[dsh-customs-doc-check](https://github.com/PerryLink/dsh-customs-doc-check)** | |
|
|
414
|
+
| **[dsh-data-quality](https://github.com/PerryLink/dsh-data-quality)** | 🧊 CONGELADO — ver el README del repo |
|
|
415
|
+
| **[dsh-demurrage-ledger](https://github.com/PerryLink/dsh-demurrage-ledger)** | |
|
|
416
|
+
| **[dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck)** | |
|
|
417
|
+
| **[dsh-drill-script-check](https://github.com/PerryLink/dsh-drill-script-check)** | |
|
|
418
|
+
| **[dsh-eia-guide-check](https://github.com/PerryLink/dsh-eia-guide-check)** | |
|
|
419
|
+
| **[dsh-emergency-plan](https://github.com/PerryLink/dsh-emergency-plan)** | |
|
|
420
|
+
| **[dsh-essay-rubric-check](https://github.com/PerryLink/dsh-essay-rubric-check)** | |
|
|
421
|
+
| **[dsh-evidence-check](https://github.com/PerryLink/dsh-evidence-check)** | |
|
|
422
|
+
| **[dsh-export-ctl-check](https://github.com/PerryLink/dsh-export-ctl-check)** | |
|
|
423
|
+
| **[dsh-fast](https://github.com/PerryLink/dsh-fast)** | |
|
|
424
|
+
| **[dsh-fmea-table-check](https://github.com/PerryLink/dsh-fmea-table-check)** | |
|
|
425
|
+
| **[dsh-forecast-penalty](https://github.com/PerryLink/dsh-forecast-penalty)** | |
|
|
426
|
+
| **[dsh-fund-research](https://github.com/PerryLink/dsh-fund-research)** | |
|
|
427
|
+
| **[dsh-github](https://github.com/PerryLink/dsh-github)** | |
|
|
428
|
+
| **[dsh-gongwen-flow-check](https://github.com/PerryLink/dsh-gongwen-flow-check)** | |
|
|
429
|
+
| **[dsh-gongwen-word-check](https://github.com/PerryLink/dsh-gongwen-word-check)** | |
|
|
430
|
+
| **[dsh-guard-plan-qc](https://github.com/PerryLink/dsh-guard-plan-qc)** | |
|
|
431
|
+
| **[dsh-hazchem-check](https://github.com/PerryLink/dsh-hazchem-check)** | |
|
|
432
|
+
| **[dsh-hazplan-check](https://github.com/PerryLink/dsh-hazplan-check)** | |
|
|
433
|
+
| **[dsh-hidden-risk-map](https://github.com/PerryLink/dsh-hidden-risk-map)** | |
|
|
434
|
+
| **[dsh-hs-classify](https://github.com/PerryLink/dsh-hs-classify)** | |
|
|
435
|
+
| **[dsh-icd-rule-check](https://github.com/PerryLink/dsh-icd-rule-check)** | |
|
|
436
|
+
| **[dsh-industry-research](https://github.com/PerryLink/dsh-industry-research)** | |
|
|
437
|
+
| **[dsh-lawcite-adapter](https://github.com/PerryLink/dsh-lawcite-adapter)** | |
|
|
438
|
+
| **[dsh-laya](https://github.com/PerryLink/dsh-laya)** | |
|
|
439
|
+
| **[dsh-lc-doc-check](https://github.com/PerryLink/dsh-lc-doc-check)** | |
|
|
440
|
+
| **[dsh-learning-gap-check](https://github.com/PerryLink/dsh-learning-gap-check)** | |
|
|
441
|
+
| **[dsh-library](https://github.com/PerryLink/dsh-library)** | |
|
|
442
|
+
| **[dsh-local-ai](https://github.com/PerryLink/dsh-local-ai)** | |
|
|
443
|
+
| **[dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions)** | |
|
|
444
|
+
| **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | |
|
|
445
|
+
| **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | |
|
|
446
|
+
| **[dsh-medrec-qc](https://github.com/PerryLink/dsh-medrec-qc)** | |
|
|
447
|
+
| **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | 🧊 CONGELADO — ver el README del repo |
|
|
448
|
+
| **[dsh-nsfc-form-check](https://github.com/PerryLink/dsh-nsfc-form-check)** | |
|
|
449
|
+
| **[dsh-nurse-record-check](https://github.com/PerryLink/dsh-nurse-record-check)** | |
|
|
450
|
+
| **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | |
|
|
451
|
+
| **[dsh-origin-rvc-check](https://github.com/PerryLink/dsh-origin-rvc-check)** | |
|
|
452
|
+
| **[dsh-ota-review-check](https://github.com/PerryLink/dsh-ota-review-check)** | |
|
|
453
|
+
| **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | |
|
|
454
|
+
| **[dsh-paper-doc-adapter](https://github.com/PerryLink/dsh-paper-doc-adapter)** | |
|
|
455
|
+
| **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | |
|
|
456
|
+
| **[dsh-permit-report-check](https://github.com/PerryLink/dsh-permit-report-check)** | |
|
|
457
|
+
| **[dsh-pipeline-check](https://github.com/PerryLink/dsh-pipeline-check)** | |
|
|
458
|
+
| **[dsh-pleading-draft](https://github.com/PerryLink/dsh-pleading-draft)** | |
|
|
459
|
+
| **[dsh-plugin-doctor](https://github.com/PerryLink/dsh-plugin-doctor)** | 🚫 RETIRADO (repo archivado) |
|
|
460
|
+
| **[dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide)** | |
|
|
461
|
+
| **[dsh-plugin-kit](https://github.com/PerryLink/dsh-plugin-kit)** | 🚫 RETIRADO (repo archivado) |
|
|
462
|
+
| **[dsh-plugin-upgrade](https://github.com/PerryLink/dsh-plugin-upgrade)** | 🚫 RETIRADO (repo archivado) |
|
|
463
|
+
| **[dsh-policy-brief-draft](https://github.com/PerryLink/dsh-policy-brief-draft)** | |
|
|
464
|
+
| **[dsh-power-loss-split](https://github.com/PerryLink/dsh-power-loss-split)** | |
|
|
465
|
+
| **[dsh-power-ticket-check](https://github.com/PerryLink/dsh-power-ticket-check)** | |
|
|
466
|
+
| **[dsh-ppap-check](https://github.com/PerryLink/dsh-ppap-check)** | |
|
|
467
|
+
| **[dsh-protest-deadline](https://github.com/PerryLink/dsh-protest-deadline)** | |
|
|
468
|
+
| **[dsh-railway-window](https://github.com/PerryLink/dsh-railway-window)** | |
|
|
469
|
+
| **[dsh-repair-order-qc](https://github.com/PerryLink/dsh-repair-order-qc)** | |
|
|
470
|
+
| **[dsh-research-report](https://github.com/PerryLink/dsh-research-report)** | |
|
|
471
|
+
| **[dsh-review-reply-check](https://github.com/PerryLink/dsh-review-reply-check)** | |
|
|
472
|
+
| **[dsh-rulefile-check](https://github.com/PerryLink/dsh-rulefile-check)** | |
|
|
473
|
+
| **[dsh-safety-brief-check](https://github.com/PerryLink/dsh-safety-brief-check)** | |
|
|
474
|
+
| **[dsh-score](https://github.com/PerryLink/dsh-score)** | 🧊 CONGELADO — ver el README del repo |
|
|
475
|
+
| **[dsh-session-sync](https://github.com/PerryLink/dsh-session-sync)** | |
|
|
476
|
+
| **[dsh-site-log-check](https://github.com/PerryLink/dsh-site-log-check)** | |
|
|
477
|
+
| **[dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security)** | |
|
|
478
|
+
| **[dsh-soe-decision-check](https://github.com/PerryLink/dsh-soe-decision-check)** | |
|
|
479
|
+
| **[dsh-soilwater-check](https://github.com/PerryLink/dsh-soilwater-check)** | |
|
|
480
|
+
| **[dsh-sop-sync-check](https://github.com/PerryLink/dsh-sop-sync-check)** | |
|
|
481
|
+
| **[dsh-spc-gbt-adapter](https://github.com/PerryLink/dsh-spc-gbt-adapter)** | |
|
|
482
|
+
| **[dsh-talk](https://github.com/PerryLink/dsh-talk)** | |
|
|
483
|
+
| **[dsh-tender-extract](https://github.com/PerryLink/dsh-tender-extract)** | |
|
|
484
|
+
| **[dsh-tender-matrix](https://github.com/PerryLink/dsh-tender-matrix)** | |
|
|
485
|
+
| **[dsh-test-drive](https://github.com/PerryLink/dsh-test-drive)** | |
|
|
486
|
+
| **[dsh-ticktick](https://github.com/PerryLink/dsh-ticktick)** | 🚫 RETIRADO (repo archivado) |
|
|
487
|
+
| **[dsh-translate](https://github.com/PerryLink/dsh-translate)** | |
|
|
488
|
+
| **[dsh-warranty-calc](https://github.com/PerryLink/dsh-warranty-calc)** | |
|
|
489
|
+
| **[dsh-budget](https://github.com/PerryLink/dsh-budget)** | 🧊 CONGELADO — ver el README del repo |
|
|
490
|
+
| **[dsh-claude-move](https://github.com/PerryLink/dsh-claude-move)** | 🧊 CONGELADO — ver el README del repo |
|
|
491
|
+
| **[dsh-defend](https://github.com/PerryLink/dsh-defend)** | 🧊 CONGELADO — ver el README del repo |
|
|
492
|
+
| **[dsh-draw](https://github.com/PerryLink/dsh-draw)** | 🧊 CONGELADO — ver el README del repo |
|
|
493
|
+
| **[dsh-reach](https://github.com/PerryLink/dsh-reach)** | 🧊 CONGELADO — ver el README del repo |
|
|
494
|
+
| **[dsh-background-agents](https://github.com/PerryLink/dsh-background-agents)** | 🚫 RETIRADO (repo archivado) |
|
|
495
|
+
| **[dsh-session-pin](https://github.com/PerryLink/dsh-session-pin)** | 🚫 RETIRADO (repo archivado) |
|
|
496
|
+
| **[dsh-team-rooms](https://github.com/PerryLink/dsh-team-rooms)** | 🚫 RETIRADO (repo archivado) |
|
|
497
|
+
|
|
498
|
+
</details>
|
|
499
|
+
|
|
500
|
+
## Licencia
|
|
501
|
+
|
|
502
|
+
[LICENSE](LICENSE) (Apache License 2.0) © 2026 dsh-permission-rules contributors
|
|
503
|
+
|
|
504
|
+
<p align="center"><sub>Apache-2.0 · Plugin de la comunidad, no afiliado a DeepSeek.</sub></p>
|