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/README-pt.md DELETED
@@ -1,443 +0,0 @@
1
- <div align="center">
2
-
3
- # 🛡️ dsh-permission-rules
4
- - **Canal 1024 store**: `npm i -g dsh1024` uma vez, depois `dsh1024 plugin --profile web add dsh-permission-rules` (conta para o ranking de instalações do [deepseek1024.com](https://deepseek1024.com)).
5
-
6
- **Regras de permissão declarativas estilo Claude Code para o DeepSeek Harness.**
7
-
8
- *Regras decidem o conhecido. Um modelo revisor decide o que não é.*
9
-
10
- [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
11
- [![Gitee](https://img.shields.io/badge/Gitee-mirror-c71d23?logo=gitee)](https://gitee.com/perrylink/dsh-permission-rules)
12
- [![DSH plugin](https://img.shields.io/badge/dsh--plugin-✅-green)](https://github.com/topics/dsh-plugin)
13
- [![dsh-doctor](https://raw.githubusercontent.com/PerryLink/dsh-plugin-doctor/main/badges/PerryLink__dsh-permission-rules.svg)](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章)
14
- [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-top-rated.svg)](https://dsh.market/)
15
- [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
16
- [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-permission-rules/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-permission-rules/actions)
17
- [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-permission-rules?label=version)](https://github.com/PerryLink/dsh-permission-rules/releases)
18
- [![npm version](https://img.shields.io/npm/v/dsh-permission-rules)](https://www.npmjs.com/package/dsh-permission-rules)
19
- [![npm downloads](https://img.shields.io/npm/dm/dsh-permission-rules)](https://www.npmjs.com/package/dsh-permission-rules)
20
- [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-permission-rules?metric=downloads&lang=pt)](https://dshfind.com/pt/plugins/PerryLink/dsh-permission-rules?ref=badge)
21
-
22
- [English](README.md) · [简体中文](README-zh.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)
23
-
24
- ```sh
25
- dsh plugin --profile <name> add dsh-permission-rules
26
- ```
27
-
28
-
29
- </div>
30
-
31
- ---
32
-
33
- **📖 Base de conhecimento do ecossistema** — dados medidos, não marketing: [guia de desenvolvimento · dados de seleção · critérios de manutenção](https://perrylink.github.io/dsh-plugin-guide/).
34
-
35
- <!-- star-cta -->
36
- ## Install & uninstall
37
-
38
- - **canal git** (último `main`): `dsh plugin --profile web add github:PerryLink/dsh-permission-rules` — o script `prepare` compila apenas com dependências de produção.
39
- - **canal npm** (versões publicadas): `dsh plugin --profile web add dsh-permission-rules`.
40
- - **canal tarball**: `pnpm pack` neste repo, depois `dsh plugin --profile web add ./dsh-permission-rules-<version>.tgz`.
41
- - **desinstalar**: `dsh plugin --profile web remove dsh-permission-rules`.
42
-
43
- ## ⭐ 如果它帮到了你
44
-
45
- Este plugin faz parte da [família de plugins DSH](https://github.com/PerryLink) (mais de 40, todos Apache-2.0). Se for útil, **deixe uma estrela**: não desbloqueia nada, mas ajuda a próxima pessoa a encontrá-lo.
46
-
47
- *English:* part of a 95 plugin family for DeepSeek Harness. If it is useful, **a star helps the next person find it** — nothing is gated behind it.
48
-
49
- ## What is dsh-permission-rules?
50
-
51
- Regras de permissão declarativas estilo Claude Code para o DeepSeek Harness.
52
-
53
- Regras decidem o conhecido. Um modelo revisor decide o que não é.
54
-
55
- ![Diagrama de fluxo de dsh-permission-rules: solicitação → política/revisão → veredito.](docs/assets/dsh-permission-rules-flow.svg)
56
-
57
- *Visão geral do fluxo: solicitação → política/revisão → veredito. Os exemplos abaixo usam a superfície real de comandos.*
58
-
59
-
60
- *A mesma execução, animada.*
61
-
62
- ## Compatibility
63
-
64
- | Surface | Status |
65
- |---|---|
66
- | Harness | DeepSeek Harness `dsh-v0.2.1-alpha.1` (adaptado em 2026-09-22, cadeia completa de gates): a configuração do plugin é o contrato de settings ao vivo — cada campo é declarado `.volatile()`, o Loader entrega a `apply` uma referência viva por campo, e uma edição salva é confirmada nas referências em execução SEM remontar o plugin, com valores fora da faixa recusados pelo schema antes de qualquer escrita. Um host cujo Schemastery seja anterior a `volatile()` (antes de 3.18.3) ainda monta e executa este plugin — os campos apenas permanecem valores comuns e o formulário de configuração ao vivo fica indisponível — porque o marcador é aplicado por sondagem de capacidade, não por suposição. O `Session.append` nesta linha ainda não consegue estampar o marcador `ignorable` (seu terceiro argumento é o pacote surface-intent, e o campo do envelope só sobrevive para a leitura de logs armazenados), então toda a linha `0.2-alpha` é pré-verificada como não marcada e a auditoria do log de sessão fica desativada por padrão — o `append` lê apenas `sourceEventSeqs`/`surfaceOp` e congela o envelope, portanto não há caminho de código capaz de estampar o marcador; as linhas anteriores `0.1.7-alpha` (adaptada em 2026-09-22), `0.1.5-rc.2` (adaptada em 2026-09-09) e `0.1.3-alpha` mantêm a mesma assinatura de append surface-only, e toda versão pré-lançamento `0.2` é classificada junto delas (uma versão ESTÁVEL `0.2.x` fica a cargo da sondagem de append, então uma superfície de marcação restaurada é adotada sem um novo lançamento deste plugin). As migrações de log dessas linhas recusam eventos de plugin não classificados mesmo marcados: aplique `strip` nas linhas de auditoria v1 antes de um host `0.1.3-alpha` abrir o log e nas v2 antes de um host `0.1.5-alpha` migrá-lo (logs v3 nativos só precisam de `repair`). |
67
- | Node | `^22.19.0 || >=24.0.0` |
68
- | Platforms | Todas (host + cliente web de settings) |
69
- | Model | Qualquer (razões deny/ask aparecem pelos resultados de ferramenta) |
70
-
71
- ## What you get
72
-
73
- O `dsh-permission-rules` antepõe uma lista ordenada de regras **`allow` / `deny` / `ask`** a cada chamada de ferramenta na cascata `tools/pre-execute` — determinística, instantânea, auditável e escrita por você em YAML puro:
74
-
75
- - **`deny`** bloqueia a chamada; a `reason` da regra vira o erro visível para o modelo.
76
- - **`ask`** usa a costura oficial de aprovação (monte o `dsh-auto-review` para um answerer de segundo modelo, ou um humano responde; sem nenhum, o harness falha fechado).
77
- - **`allow`** (e sem correspondência) delega estritamente via `next()` — os listeners posteriores nunca são curto-circuitados.
78
-
79
- Cada acerto **e** cada passagem direta é registrada como um evento de sessão `permissionRules/decision` (somente log — nada extra é injetado no contexto do modelo).
80
-
81
- - **Correspondência rica** — globs de nome de ferramenta (incl. `mcp__*`), seletores de identidade de agente (`main` / `subagent` / `preset:*`), globs **ou** regexes de chave/valor de argumentos (com negação `!pattern` e dimensão de chave `absent`), globs de caminho relativos ao workspace em **qualquer profundidade de aninhamento**, condições de host `when` (variáveis de ambiente, plataforma), e **decomposição de comandos de shell** (`argv`: palavra de comando, tokens de argumento, assinatura de pipeline) para correspondência precisa por token.
82
- - **Linha de base de alto risco integrada** — um conjunto deny/ask embarcado (comandos destrutivos, escalada de privilégios, baixar-e-executar, caminhos sensíveis) habilitado por padrão e anexado após as regras de usuário (uma regra de usuário mais próxima pode sobrescrevê-lo); alterna com `builtin.enabled`.
83
- - **Arquivos de regras hierárquicos** — `searchUp` opcional mescla cada `.dsh/rules.yaml` do cwd da sessão até a raiz do sistema de arquivos, o mais próximo primeiro.
84
- - **Implantação em dry-run** — `enforce: false` audita o que a política *faria* enquanto deixa cada chamada passar.
85
- - **Recarga a quente** — vigilância Chokidar com debounce; uma edição quebrada mantém as regras anteriores, nunca falha. Num host WSL, ou para um arquivo de regras sob `/mnt/<unidade>`, a vigilância passa a polling porque os eventos nativos de mudança não são confiáveis ali.
86
- - **Falha ruidosa** — YAML inválido, ações/campos desconhecidos, globs/regexes ruins, padrões propensos a backtracking ou mais de `maxRules` regras falham a carga.
87
-
88
- ## Rule syntax
89
-
90
- ```yaml
91
- # <project>/.dsh/rules.yaml
92
- rules:
93
- - match: { tools: [bash, pwsh], params: { command: "git push*" }, paths: ["**/secrets/**"] }
94
- action: deny
95
- reason: "No pushes from protected paths"
96
-
97
- - match: { tools: [edit, write] }
98
- action: ask
99
- reason: "File writes need confirmation"
100
- ```
101
-
102
- - **Dimensões de correspondência** — `tools` (globs, incl. `mcp__*`), `agents` (`main` / `subagent` / `preset:<name>`; identidade desconhecida nunca corresponde — falha fechado), `params` (globs ou regexes de chave/valor, negação `!pattern`, dimensão de chave `absent`), `paths` (globs relativos ao workspace extraídos a qualquer profundidade), `when` (globs/regexes de variáveis `env` + lista `platform` fechada), e `network` (`domains` / `ips` / `ports` / `schemes` — globs, curingas, CIDR, faixas de porta).
103
- - **Ações** — `allow` / `deny` / `ask`, avaliadas em ordem de arquivo, primeira correspondência vence.
104
- - **Metadados de regra** — `enabled: false` (visível mas inerte), `description`, `tags`; campos desconhecidos falham a carga.
105
- - **Schema** — um JSON Schema é distribuído em [docs/rules-format.schema.json](docs/rules-format.schema.json) (autocompletar de editor via `# yaml-language-server: $schema=...`); o vocabulário completo e uma linha base de 5 regras vivem em [docs/rules-format.en.md](docs/rules-format.en.md).
106
-
107
- ## Network policy
108
-
109
- Uma **política de rede em nível de processo** estilo Codex: o tráfego de subprocessos de shell flui por um **proxy HTTP/CONNECT** local integrado, e cada conexão é decidida por regras de rede ordenadas ou por três modos mapeados sobre os presets oficiais do sandbox:
110
-
111
- - **`deny-all`** — o preset de sandbox somente leitura: bloquear todo o tráfego de saída.
112
- - **`whitelist`** — o preset workspace-write: permitir destinos listados, `unlisted: ask` (ou `deny`) para o resto.
113
- - **`allow-all`** — o preset danger-full-access: permitir tudo.
114
- - **`auto`** (padrão) — segue o preset do sandbox; em hosts sem o serviço de política de sandbox resolve para `autoFallback` (`allow-all`).
115
-
116
- - **Correspondência** — `match.network` com `domains` / `ips` / `ports` / `schemes` (globs, curingas, CIDR, faixas de porta; portas YAML numéricas são aceitas). A extração de candidatos URL na rota quente `tools/pre-execute` dispara sobre argumentos de ferramentas web e URLs embutidas em texto de comando bash/pwsh; destinos de loopback podem curto-circuitar regras conforme a política `loopback`. Literais IPv6 mapeados em IPv4 são normalizados para a forma IPv4 antes da comparação, e o proxy conecta nos endereços usados na decisão, sem uma segunda resolução DNS; uma conexão cuja adjudicação não resolveu nenhum endereço falha fechada (502) em vez de discar o nome.
117
- - **Encadeamento por proxy ascendente** — `network.upstreamProxy` (padrão `off`) envia as conexões que este proxy **permite** por um proxy ascendente: o CONNECT pede um túnel a ele (`CONNECT host:port`) e as requisições HTTP simples são encaminhadas em forma absoluta. Um destino bloqueado nunca chega ao proxy ascendente — ele continua recebendo o 403 estruturado deste plugin. Dois casos nunca encadeiam, mesmo com um proxy ascendente configurado: um destino de **loopback** (um proxy fora deste host não consegue rotear o loopback dele) e qualquer decisão produzida por uma **regra com escopo `ips`** (encadear entrega o nome do host ao proxy ascendente, então «a conexão chega a um endereço que as regras viram» — issue #21 — deixaria de valer exatamente onde as regras se importavam com o endereço; essas decisões continuam conectando direto no endereço adjudicado), além de um destino cujo esquema não tenha um proxy ascendente utilizável. O nome do host do próprio proxy ascendente é configuração do operador, não entrada do agente, e não é adjudicado por estas regras. Uma URL com credenciais nunca é emitida em claro: avisos, `/rules network` e o snapshot de settings mascaram a senha (`http://user:***@host:port`). Um proxy ascendente inalcançável, um timeout (10 s) ou uma resposta não 2xx resultam em **502** — não há, de propósito, queda silenciosa para conexão direta, para que uma má configuração continue visível.
118
- - **Auditoria** — conexões negadas anexam `permissionRules/network` à sessão proprietária (a mesma porta adaptativa `ignorable`), com contadores de bloqueio e intercepções recentes em `/rules network` e na página de settings.
119
- - **Diagnóstico** — conexões bloqueadas trazem uma mensagem `[network: …]` nomeando o destino bloqueado, o modo ou a regra que decidiu e a solução.
120
- - **Permitir pela página de settings** — cada intercepção recente oferece uma ação **Permitir**. Ela grava UMA regra mínima `match: { network: { domains: [<host>] } }` / `action: allow` no **topo** (índice 0) do arquivo de regras mais próximo que realmente julga aquela conexão: o arquivo de projeto do workspace ao qual o bloqueio foi atribuído (o `rulesFile` absoluto quando há um configurado) ou, para um bloqueio de host sem sessão, o arquivo que a cadeia do host resolve (`rulesFile` absoluto → `<processCwd>/<rulesFile>` existente → `fallbackPath` configurado → `<processCwd>/<rulesFile>`, criado). Com vários workspaces carregados, a página oferece primeiro um seletor, porque qualquer cadeia de workspace carregada tem precedência sobre a cadeia do host. No índice 0 porque as regras são de primeira correspondência: acrescentada depois de um `deny` existente, a regra seria texto morto. Somente `domains`, porque essa dimensão inclui subdomínios e independe de porta/esquema, então o host não volta a ser bloqueado na próxima porta; comentários e regras não tocadas sobrevivem, e o texto passa pela mesma porta de validação de uma edição manual. A mudança entra em vigor imediatamente — as cadeias de workspace em cache E a cadeia de host sem sessão são relidas, sem reinício e sem `/rules reload` — e a decisão é recalculada, então o aviso informa o resultado REAL e nunca afirma sucesso enquanto a conexão continua bloqueada. Recusa, sem tocar no arquivo, um workspace desconhecido, um destino fora das fontes de regras conhecidas, a linha de base integrada somente leitura e um arquivo que não consegue ler ou analisar; uma conexão já permitida não grava nada. `network.allowHostAction: false` oculta o botão e faz o RPC recusar.
121
-
122
- ## Quick start
123
-
124
- ```sh
125
- dsh plugin --profile web add github:PerryLink/dsh-permission-rules
126
- ```
127
-
128
- ```sh
129
- # 1. install the bundle into your profile
130
- dsh plugin --profile web add github:PerryLink/dsh-permission-rules
131
-
132
- # or from npm (published releases)
133
- dsh plugin --profile web add dsh-permission-rules
134
-
135
- # 2. restart and verify the row
136
- dsh --profile web --dump-config | grep -A4 'id: permission-rules'
137
- ```
138
-
139
- ### Exemplos
140
-
141
- São os pontos de entrada reais; instale e chame um.
142
-
143
- #### Exemplo detalhado
144
-
145
- **Comando**
146
-
147
- ~~~sh
148
- /rules test bash {"command":"git push origin main","cwd":"src/secrets/app"}
149
- ~~~
150
-
151
- **Saída**
152
-
153
- ~~~text
154
- "bash" matches rule 1 (deny): 禁止 push 到受保护路径
155
- ~~~
156
-
157
- *Observado em `test/command.spec.ts:204-219 (assertions at :209-213); src/prose.ts:121`*
158
-
159
- #### Ramo de falha
160
-
161
- **Entrada**
162
-
163
- ~~~text
164
- /rules test bash {not json
165
- ~~~
166
-
167
- **Saída**
168
-
169
- ~~~text
170
- Invalid JSON arguments "{not json": the arguments must parse as JSON.
171
- ~~~
172
-
173
- *Observado em `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`*
174
-
175
- #### Exemplos breves
176
-
177
- - `tools/pre-execute`
178
-
179
- ## Configuration
180
-
181
- Todos os parâmetros são campos Schemastery `Config` (alteráveis pelo cordis.yml). Uma sobrescrita direcionada por id substitui a linha inteira — reafirme cada chave de que precisa. Num host `0.1.7-alpha` cada campo é declarado `.volatile()`, então TAMBÉM é editável no local pela página de Plugins: a edição é confirmada nas referências em execução sem remontar o plugin, o runtime lê o novo valor no uso seguinte, e uma mudança em `network.proxyPort`, `proxyBind`, `injectEnv` ou `noProxy` revincula o proxy local imediatamente. Os limites numéricos ficam no schema, e o editor de configuração resolve a configuração mesclada contra esse schema antes de persistir, então um valor fora da faixa é recusado no momento da escrita. Num host cujo Schemastery seja anterior a `volatile()` estes campos só mudam por cordis.yml.
182
-
183
- | Key | Default | Meaning |
184
- |---|---|---|
185
- | `rulesFile` | `.dsh/rules.yaml` | Local do arquivo de regras; relativo = resolvido contra o cwd da sessão, absoluto = global e validado na montagem |
186
- | `fallbackPath` | *(none)* | Arquivo de regras usado quando a detecção por cwd não encontra nada; validado na montagem |
187
- | `badFilePolicy` | `fail` | Arquivo de regras ruim: `fail` faz a chamada pendente falhar ruidosamente; `ignore-with-warning` avisa e continua vazio |
188
- | `maxRules` | `256` | Limite rígido de contagem de regras na cadeia fonte efetiva |
189
- | `maxCachedWorkspaces` | `512` | Limite rígido de cargas de regras por workspace em cache (evicção LRU) |
190
- | `patternMode` | `glob` | Sabor de padrão `params`/`paths`/`when.env`: `glob` ou `regex` (nomes de ferramenta são sempre globs) |
191
- | `watch` | `true` | Vigilância Chokidar + recarga ao mudar |
192
- | `watchStabilityThresholdMs` | `200` | Janela de debounce de recarga (ms) |
193
- | `language` | `en` | Idioma de saída de `/rules`: `en`, `zh`, `es`, `pt`, `hi` |
194
- | `caseInsensitivePaths` | *(win32)* | Padrões `paths` e comparação de raiz do workspace ignoram maiúsculas ASCII; `true` no Windows |
195
- | `audit` | `all` | Granularidade de auditoria: `all` registra cada acerto E passagem; `hits` omite eventos de passagem |
196
- | `searchUp` | `false` | Percorrer diretórios pai do cwd e mesclar cada arquivo de regras encontrado, o mais próximo primeiro |
197
- | `maxGlobStars` | `2` | Limite rígido de quantificadores `*`/`**` não limitados por padrão glob |
198
- | `enforce` | `true` | `false` = modo dry-run: acertos deny/ask são registrados com marcador `dryRun` e cada chamada passa |
199
- | `allowUnmarkedAudit` | `false` | Hosts anteriores ao marcador descartam o marcador `ignorable`; o plugin desativa a auditoria de log com um aviso. Ponha `true` para reativar |
200
- | `network.enabled` | `true` | Interruptor mestre do proxy, da injeção de ambiente e dos padrões de modo de ferramenta web |
201
- | `network.mode` | `auto` | Modo de política: `auto` segue o preset do sandbox, ou `deny-all` / `whitelist` / `allow-all` |
202
- | `network.autoFallback` | `allow-all` | Modo usado quando `auto` não tem serviço de política de sandbox |
203
- | `network.unlisted` | `ask` | Manejo em modo whitelist de destinos sem regra coincidente: `ask` ou `deny` |
204
- | `network.proxyBind` | `127.0.0.1` | Endereço de vínculo do proxy local (somente loopback) |
205
- | `network.proxyPort` | `0` | Porta do proxy local; `0` escolhe uma porta efêmera livre |
206
- | `network.proxyMaxRecent` | `100` | Limite de registros de bloqueio recentes para a página de settings |
207
- | `network.loopback` | `allow` | Destinos de loopback: `allow` (paridade Codex) ou `policy` |
208
- | `network.injectEnv` | `true` | Se variáveis de ambiente do proxy são injetadas para subprocessos |
209
- | `network.noProxy` | `clear` | Manejo de NO_PROXY em subprocessos: `clear` aplica a política ou `preserve` |
210
- | `network.upstreamProxy` | `off` | Proxy ascendente para as conexões que este plugin PERMITE: `off` conecta direto, `inherit` reutiliza os nomes de proxy do ambiente de lançamento, ou uma URL de proxy `http(s)://` explícita |
211
- | `network.allowHostAction` | `true` | Ação «permitir este host» por bloqueio da página de settings: `false` oculta o botão Permitir e faz o RPC `permissionRules/allowHost` recusar (o editor de regras não é afetado) |
212
- | `builtin.enabled` | `true` | Linha de base de alto risco integrada: `false` desabilita por completo o conjunto deny/ask embarcado |
213
- | `builtin.path` | *(embarcado)* | Arquivo de linha de base de substituição (absoluto, ou relativo a `process.cwd()`); validado ao montar |
214
-
215
- ## Tools & surfaces
216
-
217
- | Surface | Kind | Notes |
218
- |---|---|---|
219
- | `tools/pre-execute` | listener | Regras allow/deny/ask de primeira correspondência + extração de candidatos URL de rede |
220
- | `/rules` | command | `list` · `reload` · `decisions [n]` · `test <tool> <json>` |
221
- | `permissionRules/decision` | event | Auditoria somente de log para cada acerto e passagem |
222
- | `permissionRules/network` | event | Auditoria da camada de proxy para conexões bloqueadas |
223
- | HTTP/CONNECT proxy | service | Proxy local integrado que governa o tráfego de subprocessos de shell |
224
- | settings page | client | Editor de modo de rede, editor de regras, contadores de bloqueio, intercepções recentes com uma ação de permissão por bloqueio |
225
-
226
- ```
227
- /rules list the active rules, their source files, and any last-reload error
228
- /rules list explicit alias for the bare listing
229
- /rules reload re-read the rule-file chain for this workspace
230
- /rules decisions [n] show the last n permission decisions of this session (default 10)
231
- /rules test <tool> <json> dry-evaluate the rules against a hypothetical call
232
- ```
233
-
234
- `/rules test` também aceita bandeiras iniciais: `--cwd <dir>`, `--env KEY=VALUE` (repetível), `--agent <selector>` (repetível) e `--platform <name>`. Em cadeias multi-arquivo (ex.: `searchUp`), cada linha de regra listada é atribuída ao seu próprio arquivo fonte.
235
-
236
- ## Permissions & data
237
-
238
- - **Permissions**: o manifesto de workshop declara `files:read`, `files:watch`, `files:write`, `session:append` e `network:outbound`. Decisões `ask` usam a costura oficial de aprovação — nada é reimplementado ou contornado.
239
- - **Data**: arquivos de regras são lidos do disco; nenhum dado de regra é escrito. Sem chamadas de modelo, sem subagentes revisores.
240
- - **Session log**: `permissionRules/decision` nunca é injetado no contexto do modelo e é anexado com o marcador `ignorable: true` do envelope, de modo que qualquer build do harness carrega o log.
241
-
242
- ## Security boundaries
243
-
244
- - **Política, não kernel.** Candidatos `paths` vêm apenas de um conjunto documentado de chaves de argumento (a qualquer profundidade, com limite), e apenas caminhos relativos ao workspace correspondem.
245
- - **Aqui não há revisor.** O plugin nunca gera subagentes nem chama modelos — produzir uma decisão `ask` é o fim do seu trabalho.
246
- - **Sem mudanças de sandbox.** A política de sandbox em nível de SO pertence à costura do sandbox, não a este plugin.
247
- - **Rejeição ruidosa de má configuração.** Campos YAML desconhecidos, ações desconhecidas e padrões ruins são rejeitados na carga.
248
- - **Limites de backtracking.** Padrões glob são limitados a `maxGlobStars` expansões de estrela não limitadas; padrões regex rejeitam quantificadores aninhados não limitados e alternâncias literais sobrepostas quantificadas.
249
- - **Discagem à prova de falhas.** Encaminhamentos HTTP simples e túneis CONNECT conectam apenas a endereços adjudicados; um allow cuja adjudicação não resolveu nenhum endereço falha fechado com 502 em vez de discar o nome (issue #23).
250
-
251
- ## Known limitations
252
-
253
- - **Marcador de auditoria em hosts anteriores ao marcador ou que rejeitam eventos.** `permissionRules/decision` é anexado com `ignorable: true`; hosts cujo `Session.append` é anterior ao marcador (as linhas `0.1.0-rc.1`–`rc.7` e `0.1.1-rc.1`–`rc.7`) o descartam silenciosamente, a linha `0.1.2-rc` traz a superfície alpha.5 (nenhuma opção de append escreve o marcador), a linha `0.1.2-alpha` rejeita eventos de plugin na leitura mesmo marcados, e as linhas `0.1.3-alpha` e `0.1.5-alpha` mantêm a mesma assinatura de append surface-only (verificado nos pacotes publicados `0.1.3-alpha.1`/`0.1.5-alpha.1`) — o runtime pré-verifica todas elas antes do primeiro append e desativa a auditoria de log com um aviso único. A migração entre gerações também rejeita linhas de auditoria marcadas: a porta v1→v2 da `0.1.3-alpha` rejeita eventos v1 desconhecidos, e a porta v2→v3 da `0.1.5-alpha` rejeita todo evento não classificado (seu inventário é congelado ao vocabulário v2 publicado), então aplique `strip` nas linhas v1 antes de um host 0.1.3 abrir o log e nas v2 antes de atualizar para um host 0.1.5. Logs v3 nativos aceitam linhas de plugin marcadas, então só precisam de `repair`. Defina `allowUnmarkedAudit: true` para reativar; repare logs já escritos com `scripts/repair-session-logs.mjs` (seu modo `strip` remove linhas de auditoria onde o marcador não ajuda).
254
- - **Candidatos de caminho são heurísticos.** Somente as chaves de argumento documentadas alimentam a correspondência de caminho, e a correspondência relativa ao workspace é insensível a maiúsculas ASCII apenas com `caseInsensitivePaths` ativado.
255
- - **Globs são um subconjunto conservador.** Sem expansão de chaves — escreva dois padrões, ou use o modo regex.
256
- - **A guarda de backtracking de regex é estrutural, não exaustiva.** Prefira o modo glob para arquivos não confiáveis.
257
- - **As requisições de saída do próprio host não passam por este proxy.** O ambiente de proxy injetado cobre os **subprocessos de shell derivados** — que é para isso que a injeção serve — e qualquer consumidor que leia os nomes de proxy no momento da requisição. **Não** cobre o tráfego baseado em `fetch` do próprio processo do host: o launcher instala o dispatcher global do undici a partir do **ambiente de lançamento** antes de o primeiro plugin ser montado, esse dispatcher roteia pela sua política e não pelo ambiente, e o Node amostra o ambiente de proxy na inicialização, então um plugin montado depois não consegue redirecioná-lo. Consequências: os endpoints do provedor **não** precisam de uma regra allow, e `network.injectEnv: false` não tira o processo do host de nada. Medido em 2026-09-10 no Node 22; reproduza com `scripts/host-egress-probe.mjs`.
258
- - **O encadeamento cobre apenas o que chega a este proxy.** Em `dsh-v0.1.7-alpha.1` e posteriores, a própria política de proxy de lançamento do harness e sua camada de ambiente para subprocessos podem ter precedência sobre os nomes de proxy que este plugin injeta, então `network.upstreamProxy` descreve o que acontece com as conexões que este proxy trata — não é uma afirmação sobre todos os caminhos de saída do processo do host.
259
-
260
- ## Collaborating with dsh-auto-review
261
-
262
- - O `dsh-permission-rules` produz `ask`; o `dsh-auto-review` responde na cascata `approval/request` com um veredito de segundo modelo somente leitura (ou delega a humanos). Monte ambos para o laço completo fechado.
263
- - Testado em integração: `permissionRules/decision` → `approval/asked` → `autoReview/verdict` → `approval/decided`, com o revisor substituído por um mock roteirizado.
264
- - A política de aprovação `never` e toda garantia de falha fechada do harness oficial permanecem intactas.
265
-
266
- ## Session log repair
267
-
268
- Logs de sessão escritos antes de o marcador `ignorable` existir podem ser recusados por builds mais novas do harness (`SessionFormatUnsupportedError`). O `scripts/repair-session-logs.mjs` distribuído reescreve apenas as linhas de auditoria alvo para carregar `ignorable: true`, preservando quadros, com backups:
269
-
270
- ```sh
271
- node scripts/repair-session-logs.mjs scan [--home DIR] # relata linhas estranhas, não muda nada
272
- node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
273
- node scripts/repair-session-logs.mjs strip [--home DIR] [--dry-run]
274
- ```
275
-
276
- `--home` por padrão é `$DSH_HOME/sessions` (ou `~/.dsh/sessions`). Ele descobre cada log pelo nome canônico da geração — `session.jsonl`, `session.v2.jsonl`, `session.v3.jsonl`, cada um opcionalmente comprimido em `.zstd` — então escolha o modo pela geração:
277
-
278
- - **v3 (`session.v3.jsonl`, escrito nativamente pela linha `0.1.5-alpha`)** — o caminho de leitura aceita linhas de plugin marcadas, então `repair` basta.
279
- - **v2 (`session.v2.jsonl`, escrito pela linha `0.1.3-alpha`)** — `repair` o abre no host que o escreveu, mas a migração v2→v3 da `0.1.5-alpha` rejeita todo evento não classificado mesmo marcado: execute `strip` nos logs v2 **antes** de atualizar para um host `0.1.5-alpha`.
280
- - **v1 (`session.jsonl`)** — a migração v1→v2 da `0.1.3-alpha` rejeita eventos v1 desconhecidos mesmo marcados: execute `strip` antes de um host 0.1.3 ou posterior abrir o log pela primeira vez.
281
-
282
- ## Development
283
-
284
- ```sh
285
- pnpm install # node ^22.19 || >=24
286
- pnpm run typecheck # tsc, src + tests
287
- pnpm run lint # eslint, src + tests + scripts
288
- pnpm test # vitest: 24 spec files
289
- pnpm run test:coverage # coverage gate (90/80/90/90)
290
- pnpm run build # tsc declarations + tsdown bundles (lib/)
291
- pnpm run pack:check # build + pack (the published artifact)
292
- node scripts/check-readme-sync.mjs # five-language README sync gate (also in CI)
293
- ```
294
-
295
- Consulte [VERIFICATION.md](VERIFICATION.md) para o registro de verificação end-to-end sem cabeça.
296
-
297
- ## Interoperability with other DSH plugins
298
-
299
- Verificado contra **DSH `0.2.0-rc.2`** (o runtime para o qual este README é publicado) e o conjunto de plugins com mais estrelas pesquisado em 2026-10-05.
300
-
301
- Este plugin **não interfere** em outros plugins, incluindo os de mais estrelas:
302
-
303
- - **Sem colisão de nome de ferramenta.** Todas as ferramentas têm namespace; nenhuma ocupa um nome puro já pertencente a uma ferramenta embutida ou a outro plugin.
304
- - **Sem colisão de chave de serviço.** Fornece apenas `permissionRules`, `permissionRulesRuntime`; essa chave não é uma costura embutida nem é fornecida por nenhum plugin de mais estrelas.
305
- - **Sem colisão de slot.** Não registra nenhuma chave de slot de cliente, então não disputa um assento `shadows-shipped-ui`.
306
- - **Sem colisão de rota HTTP.** Não registra nenhum prefixo `webServer`.
307
- - **Sem colisão na camada de patch.** O patch do bundle apenas faz `insert` da própria linha; nunca sobrescreve o `config` de uma linha embutida.
308
- - **Sem mutação global.** Não altera protótipos, não reescreve `process.env` nem substitui o dispatcher global de fetch.
309
-
310
- **Listeners de eventos compartilhados não interferem por construção.** Observa os eventos sensíveis à ordem `tools/post-execute`, `tools/pre-execute` com `ctx.on()` — o registro de difusão do Cordis, onde cada listener executa e nenhum pode privar outro do turno. **Todos os listeners aqui delegam via `next()`**, então a cadeia nunca é curto-circuitada:
311
- - `tools/post-execute` — also used by `cc-safety-net` (1576★).
312
- - `tools/pre-execute` — also used by `cc-safety-net` (1576★).
313
-
314
- Evidência estática: `dsh-plugin-doctor` K10–K13 retornam `pass` em todas as verificações deste repositório.
315
-
316
- ## Topics
317
-
318
- `dsh`, `dsh-plugin`, `deepseek-harness`, `permission`, `policy`, `allow-deny-ask`, `approval`, `safety`, `network`, `network-policy`, `proxy`
319
-
320
- ## Contributors
321
-
322
- - [@PerryLink](https://github.com/PerryLink) — criador e mantenedor: vocabulário e avaliação de regras, runtime, vigilância HMR, auditoria de log de sessão, política de rede + proxy, e a documentação em cinco idiomas.
323
- - [@22xuan](https://github.com/22xuan) — o relatório detalhado sobre hosts rc.6 descartando silenciosamente o marcador `ignorable` do evento de auditoria ([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2)) e a discussão do harness upstream; a detecção de capacidade de host em runtime v0.4.1 e a correção de documentação se derivaram diretamente dessa análise.
324
- - [@sjh9714](https://github.com/sjh9714) — propôs o corpus compartilhado de vetores de teste de sintaxe de regras ([#4](https://github.com/PerryLink/dsh-permission-rules/issues/4), [#5](https://github.com/PerryLink/dsh-permission-rules/issues/5)), incluído na v0.5.1 como `docs/rule-test-vectors/`, e contribuiu com os casos-limite de decomposição AST na [discussão de design](https://github.com/PerryLink/dsh-permission-rules/discussions/10).
325
- - [@weipeng1999](https://github.com/weipeng1999) — a proposta de decomposição de comandos baseada em AST ([#8](https://github.com/PerryLink/dsh-permission-rules/issues/8)) por trás da discussão de design.
326
- - [@alexchenzl](https://github.com/alexchenzl) — a solicitação de inclusão no DSH Directory ([#7](https://github.com/PerryLink/dsh-permission-rules/issues/7)).
327
- - [@zl190](https://github.com/zl190) — relatou e verificou a lacuna de compatibilidade do harness `0.1.0-rc.7` ([PR #9](https://github.com/PerryLink/dsh-permission-rules/pulls/9)).
328
- - [@cuohua](https://github.com/cuohua) — relatou que a linha `0.1.1-rc` ainda descarta o marcador `ignorable` embora a verificação de versão cobrisse apenas `0.1.0` ([#11](https://github.com/PerryLink/dsh-permission-rules/issues/11)); a verificação ampliada veio diretamente dessa análise.
329
-
330
- ## PerryLink DSH Plugin Family
331
-
332
- Este projeto faz parte da família de plugins do DeepSeek Harness da [PerryLink](https://github.com/PerryLink). O registro fica recolhido abaixo para que cada README mantenha uma primeira tela curta; expanda para ver cada linha e seu status.
333
-
334
- <details>
335
- <summary>Expandir todos os plugins</summary>
336
-
337
- | Plugin | Status |
338
- |---|---|
339
- | **[dsh-aqua-input-check](https://github.com/PerryLink/dsh-aqua-input-check)** | |
340
- | **[dsh-archive-check](https://github.com/PerryLink/dsh-archive-check)** | |
341
- | **[dsh-auto-review](https://github.com/PerryLink/dsh-auto-review)** | |
342
- | **[dsh-autotier](https://github.com/PerryLink/dsh-autotier)** | |
343
- | **[dsh-bid-ca-precheck](https://github.com/PerryLink/dsh-bid-ca-precheck)** | |
344
- | **[dsh-bid-qual-check](https://github.com/PerryLink/dsh-bid-qual-check)** | |
345
- | **[dsh-cert-mcp](https://github.com/PerryLink/dsh-cert-mcp)** | |
346
- | **[dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind)** | |
347
- | **[dsh-click](https://github.com/PerryLink/dsh-click)** | |
348
- | **[dsh-composer-history](https://github.com/PerryLink/dsh-composer-history)** | |
349
- | **[dsh-contract-stance](https://github.com/PerryLink/dsh-contract-stance)** | |
350
- | **[dsh-customs-doc-check](https://github.com/PerryLink/dsh-customs-doc-check)** | |
351
- | **[dsh-data-quality](https://github.com/PerryLink/dsh-data-quality)** | |
352
- | **[dsh-demurrage-ledger](https://github.com/PerryLink/dsh-demurrage-ledger)** | |
353
- | **[dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck)** | |
354
- | **[dsh-drill-script-check](https://github.com/PerryLink/dsh-drill-script-check)** | |
355
- | **[dsh-eia-guide-check](https://github.com/PerryLink/dsh-eia-guide-check)** | |
356
- | **[dsh-emergency-plan](https://github.com/PerryLink/dsh-emergency-plan)** | |
357
- | **[dsh-essay-rubric-check](https://github.com/PerryLink/dsh-essay-rubric-check)** | |
358
- | **[dsh-evidence-check](https://github.com/PerryLink/dsh-evidence-check)** | |
359
- | **[dsh-export-ctl-check](https://github.com/PerryLink/dsh-export-ctl-check)** | |
360
- | **[dsh-fast](https://github.com/PerryLink/dsh-fast)** | |
361
- | **[dsh-fmea-table-check](https://github.com/PerryLink/dsh-fmea-table-check)** | |
362
- | **[dsh-forecast-penalty](https://github.com/PerryLink/dsh-forecast-penalty)** | |
363
- | **[dsh-fund-research](https://github.com/PerryLink/dsh-fund-research)** | |
364
- | **[dsh-github](https://github.com/PerryLink/dsh-github)** | |
365
- | **[dsh-gongwen-flow-check](https://github.com/PerryLink/dsh-gongwen-flow-check)** | |
366
- | **[dsh-gongwen-word-check](https://github.com/PerryLink/dsh-gongwen-word-check)** | |
367
- | **[dsh-guard-plan-qc](https://github.com/PerryLink/dsh-guard-plan-qc)** | |
368
- | **[dsh-hazchem-check](https://github.com/PerryLink/dsh-hazchem-check)** | |
369
- | **[dsh-hazplan-check](https://github.com/PerryLink/dsh-hazplan-check)** | |
370
- | **[dsh-hidden-risk-map](https://github.com/PerryLink/dsh-hidden-risk-map)** | |
371
- | **[dsh-hs-classify](https://github.com/PerryLink/dsh-hs-classify)** | |
372
- | **[dsh-icd-rule-check](https://github.com/PerryLink/dsh-icd-rule-check)** | |
373
- | **[dsh-industry-research](https://github.com/PerryLink/dsh-industry-research)** | |
374
- | **[dsh-lawcite-adapter](https://github.com/PerryLink/dsh-lawcite-adapter)** | |
375
- | **[dsh-laya](https://github.com/PerryLink/dsh-laya)** | |
376
- | **[dsh-lc-doc-check](https://github.com/PerryLink/dsh-lc-doc-check)** | |
377
- | **[dsh-learning-gap-check](https://github.com/PerryLink/dsh-learning-gap-check)** | |
378
- | **[dsh-library](https://github.com/PerryLink/dsh-library)** | |
379
- | **[dsh-local-ai](https://github.com/PerryLink/dsh-local-ai)** | |
380
- | **[dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions)** | |
381
- | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | |
382
- | **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | |
383
- | **[dsh-medrec-qc](https://github.com/PerryLink/dsh-medrec-qc)** | |
384
- | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | |
385
- | **[dsh-nsfc-form-check](https://github.com/PerryLink/dsh-nsfc-form-check)** | |
386
- | **[dsh-nurse-record-check](https://github.com/PerryLink/dsh-nurse-record-check)** | |
387
- | **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | |
388
- | **[dsh-origin-rvc-check](https://github.com/PerryLink/dsh-origin-rvc-check)** | |
389
- | **[dsh-ota-review-check](https://github.com/PerryLink/dsh-ota-review-check)** | |
390
- | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | |
391
- | **[dsh-paper-doc-adapter](https://github.com/PerryLink/dsh-paper-doc-adapter)** | |
392
- | **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | |
393
- | **[dsh-permit-report-check](https://github.com/PerryLink/dsh-permit-report-check)** | |
394
- | **[dsh-pipeline-check](https://github.com/PerryLink/dsh-pipeline-check)** | |
395
- | **[dsh-pleading-draft](https://github.com/PerryLink/dsh-pleading-draft)** | |
396
- | **[dsh-plugin-doctor](https://github.com/PerryLink/dsh-plugin-doctor)** | |
397
- | **[dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide)** | |
398
- | **[dsh-plugin-kit](https://github.com/PerryLink/dsh-plugin-kit)** | |
399
- | **[dsh-plugin-upgrade](https://github.com/PerryLink/dsh-plugin-upgrade)** | |
400
- | **[dsh-policy-brief-draft](https://github.com/PerryLink/dsh-policy-brief-draft)** | |
401
- | **[dsh-power-loss-split](https://github.com/PerryLink/dsh-power-loss-split)** | |
402
- | **[dsh-power-ticket-check](https://github.com/PerryLink/dsh-power-ticket-check)** | |
403
- | **[dsh-ppap-check](https://github.com/PerryLink/dsh-ppap-check)** | |
404
- | **[dsh-protest-deadline](https://github.com/PerryLink/dsh-protest-deadline)** | |
405
- | **[dsh-railway-window](https://github.com/PerryLink/dsh-railway-window)** | |
406
- | **[dsh-repair-order-qc](https://github.com/PerryLink/dsh-repair-order-qc)** | |
407
- | **[dsh-research-report](https://github.com/PerryLink/dsh-research-report)** | |
408
- | **[dsh-review-reply-check](https://github.com/PerryLink/dsh-review-reply-check)** | |
409
- | **[dsh-rulefile-check](https://github.com/PerryLink/dsh-rulefile-check)** | |
410
- | **[dsh-safety-brief-check](https://github.com/PerryLink/dsh-safety-brief-check)** | |
411
- | **[dsh-score](https://github.com/PerryLink/dsh-score)** | |
412
- | **[dsh-session-sync](https://github.com/PerryLink/dsh-session-sync)** | |
413
- | **[dsh-site-log-check](https://github.com/PerryLink/dsh-site-log-check)** | |
414
- | **[dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security)** | |
415
- | **[dsh-soe-decision-check](https://github.com/PerryLink/dsh-soe-decision-check)** | |
416
- | **[dsh-soilwater-check](https://github.com/PerryLink/dsh-soilwater-check)** | |
417
- | **[dsh-sop-sync-check](https://github.com/PerryLink/dsh-sop-sync-check)** | |
418
- | **[dsh-spc-gbt-adapter](https://github.com/PerryLink/dsh-spc-gbt-adapter)** | |
419
- | **[dsh-talk](https://github.com/PerryLink/dsh-talk)** | |
420
- | **[dsh-tender-extract](https://github.com/PerryLink/dsh-tender-extract)** | |
421
- | **[dsh-tender-matrix](https://github.com/PerryLink/dsh-tender-matrix)** | |
422
- | **[dsh-test-drive](https://github.com/PerryLink/dsh-test-drive)** | |
423
- | **[dsh-ticktick](https://github.com/PerryLink/dsh-ticktick)** | |
424
- | **[dsh-translate](https://github.com/PerryLink/dsh-translate)** | |
425
- | **[dsh-warranty-calc](https://github.com/PerryLink/dsh-warranty-calc)** | |
426
- | **[dsh-budget](https://github.com/PerryLink/dsh-budget)** | 🧊 CONGELADO — ver o README do repositório |
427
- | **[dsh-claude-move](https://github.com/PerryLink/dsh-claude-move)** | 🧊 CONGELADO — ver o README do repositório |
428
- | **[dsh-defend](https://github.com/PerryLink/dsh-defend)** | 🧊 CONGELADO — ver o README do repositório |
429
- | **[dsh-draw](https://github.com/PerryLink/dsh-draw)** | 🧊 CONGELADO — ver o README do repositório |
430
- | **[dsh-reach](https://github.com/PerryLink/dsh-reach)** | 🧊 CONGELADO — ver o README do repositório |
431
- | **[dsh-background-agents](https://github.com/PerryLink/dsh-background-agents)** | 🚫 RETIRADO — ver o README do repositório |
432
- | **[dsh-session-pin](https://github.com/PerryLink/dsh-session-pin)** | 🚫 RETIRADO — ver o README do repositório |
433
- | **[dsh-team-rooms](https://github.com/PerryLink/dsh-team-rooms)** | 🚫 RETIRADO — ver o README do repositório |
434
-
435
- </details>
436
-
437
- ## License
438
-
439
- [Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors
440
-
441
- ### Instalar a partir do mercado do DSH Desktop
442
-
443
- Todos os plugins PerryLink podem ser explorados no mercado integrado do DSH Desktop: **Market → Sources → add source → colar** `https://perrylink-dsh-catalog.perrylink.workers.dev/catalog-source.json` **→ selecionar**. A instalação continua passando pela verificação de identidade npm do mercado e pela sua confirmação.