dsh-permission-rules 0.6.18 → 0.6.20

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 CHANGED
@@ -1,3 +1,29 @@
1
+ ## v0.6.20 - 2026-09-10
2
+
3
+ ### Fixed
4
+
5
+ - **Corrected the mechanism by which this plugin participates in host networking (issue #22).** The five READMEs, `AGENTS.md` and the v0.6.19 note claimed that the process-wide injected proxy environment also placed the harness's own LLM transport under this policy. Measurement on 2026-09-10 (Node 22; `scripts/host-egress-probe.mjs`) shows it does not: the launcher installs undici's global dispatcher from the **launch environment** before the first plugin mounts, that dispatcher routes by its policy rather than by the environment, and Node samples the proxy environment at start — so a mid-process `process.env` write reaches neither `fetch` nor `node:http`. The injection covers spawned shell children, which is what it was always for. The READMEs' known-limitations bullet now says so, and the `llm/stream` annotation shipped in v0.6.19 is recorded as inert: it can only fire when a blocked child-process connection coincides within its window with an unrelated model failure, so it misattributes rather than diagnoses — it has been **removed in this release**, along with its registration, its block-window helper, the type import it needed, and its four tests.
6
+
7
+ ## v0.6.19 - 2026-09-10
8
+
9
+ ### Security
10
+
11
+ - A CONNECT tunnel refuses to dial a hostname when the adjudication resolved no address: `connectUpstream` now fails closed (logged, 502 to the client) instead of falling back to `connect(port, target.host)` — a second DNS resolution whose answer the rules never saw, and the one remaining path governed by Node's 250 ms `autoSelectFamilyAttemptTimeout`. The reported path itself was already fixed in 0.6.17 (`connect` dials the addresses `decideWithResolution` returned, and an IP literal skips the family race entirely); this closes the residual (issue #21).
12
+
13
+ ### Fixed
14
+
15
+ - Session-less host-level traffic is judged against the CONFIGURED chain instead of an empty map. `proxyChains()` consulted only `byCwd`, which `rulesFor(cwd)` populates from a session or tool call, so at boot the harness's own host-level fetches met the whitelist default and were blocked as `[network: blocked pending approval]` even with a matching allow rule already configured. `hostChain()` loads the chain for the host process's own working directory (project file → absolute `rulesFile` → configured fallback → shipped baseline) while no per-cwd chain is loaded; it never becomes a `byCwd` member, so a session workspace chain always outranks it, and an unusable configured chain warns once and degrades to the mode default (issue #18).
16
+ - Rule files are normalized before parsing: CRLF maps onto LF, a stray CR inside a line is dropped, and every CR is a line separator in a CR-only file. A lone CR is not a line break to the YAML parser in every position — it survived into the scalar it terminated (`domains: [registry.npmjs.org\r]`, or a final line ending in a bare CR), compiling a pattern that silently never matched its target (issue #19 item 4).
17
+ - Rule-file watches poll on WSL drvfs mounts: `watchPollingFor` switches a watch to `usePolling` (300 ms interval) when the watched rule file is under `/mnt/<drive>` or `/proc/version` reports a Microsoft kernel, because chokidar's native change events are unreliable on drvfs/9p and a rule edit otherwise stopped hot-reloading silently with no error. Detection is per watch, so every other host keeps the native watcher, and `/rules reload` stays the manual fallback (issue #19 item 1).
18
+
19
+ ### Added
20
+
21
+ - A failing model call now names the policy. The injected proxy environment is process-wide, so the harness's own LLM transport is adjudicated by this policy too, and a blocked provider endpoint surfaced as a bare `Connection error. / TRANSPORT`. A transparent `llm/stream` listener appends the `[network: …]` marker — blocked target, mode/rule, remediation — to the ORIGINAL error object (its class, code and retry facts stay intact) and logs it, so a turn can be attributed to the policy rather than reading as a provider outage. It registers only when `network.enabled`. It does NOT auto-allow provider endpoints: the two other resolutions the issue offers are not reachable from a plugin (`ctx.llm.listProviders()` exposes provider ids/names only, configured base URLs are adapter-owned, and there is no per-spawn environment seam for shell children), which the five READMEs record as a known limitation (issue #22).
22
+
23
+ ### Tests
24
+
25
+ - Gate chain green: 23 files / 302 tests, coverage 92.27% statements / 87.29% branches / 93.62% functions.
26
+
1
27
  ## v0.6.18 - 2026-09-10
2
28
 
3
29
  ### Docs
package/README.es.md CHANGED
@@ -45,7 +45,7 @@ Cada acierto **y** cada paso directo se registra como un evento de sesión `perm
45
45
  - **Línea base de alto riesgo integrada** — un conjunto deny/ask embarcado (comandos destructivos, escalada de privilegios, descarga-y-ejecución, rutas sensibles) habilitado por defecto y añadido después de las reglas de usuario (una regla de usuario más cercana puede sobrescribirlo); se alterna con `builtin.enabled`.
46
46
  - **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 de archivos, el más cercano primero.
47
47
  - **Despliegue en dry-run** — `enforce: false` audita lo que la política *haría* mientras deja pasar cada llamada.
48
- - **Recarga en caliente** — vigilancia Chokidar con debounce; una edición rota conserva las reglas anteriores, nunca falla.
48
+ - **Recarga en caliente** — vigilancia Chokidar con debounce; una edición rota conserva las reglas anteriores, nunca falla. En un host WSL, o para un archivo de reglas bajo `/mnt/<unidad>`, la vigilancia pasa a sondeo (polling) porque allí los eventos nativos de cambio no son fiables.
49
49
  - **Fallo ruidoso** — YAML inválido, acciones/campos desconocidos, globs/regexes malos, patrones propensos a backtracking o más de `maxRules` reglas fallan la carga.
50
50
 
51
51
  ## Rule syntax
@@ -78,6 +78,7 @@ Una **política de red a nivel de proceso** estilo Codex: el tráfico de subproc
78
78
 
79
79
  - **Emparejamiento** — `match.network` con `domains` / `ips` / `ports` / `schemes` (globs, comodines, CIDR, rangos de puertos; se aceptan puertos YAML numéricos). La extracción de candidatos URL en la ruta caliente `tools/pre-execute` se dispara sobre argumentos de herramientas web y URLs embebidas en texto de comandos bash/pwsh; los destinos de loopback pueden cortocircuitar reglas según la política `loopback`. Los literales IPv6 mapeados a IPv4 se normalizan a su forma IPv4 antes de comparar, y el proxy se conecta a las direcciones con las que se tomó la decisión, sin una segunda resolución DNS.
80
80
  - **Auditoría** — las conexiones denegadas anexan `permissionRules/network` a la sesión propietaria (la misma puerta adaptativa `ignorable`), con contadores de bloqueo e intercepciones recientes en `/rules network` y la página de settings.
81
+ - **Diagnóstico** — las conexiones bloqueadas llevan un mensaje `[network: …]` que nombra el destino bloqueado, el modo o la regla que decidió y la solución.
81
82
 
82
83
  ## Quick start
83
84
 
@@ -174,6 +175,7 @@ Todos los parámetros son campos Schemastery `Config` (modificables desde cordis
174
175
  - **Los candidatos de ruta son heurísticos.** Solo las claves de argumento documentadas alimentan el emparejamiento de rutas, y el emparejamiento relativo al workspace es insensible a mayúsculas ASCII solo con `caseInsensitivePaths` activado.
175
176
  - **Los globs son un subconjunto conservador.** Sin expansión de llaves — escribe dos patrones, o usa modo regex.
176
177
  - **La guardia de backtracking de regex es estructural, no exhaustiva.** Prefiere el modo glob para archivos no confiables.
178
+ - **Las peticiones salientes del propio host no pasan por este proxy.** El entorno de proxy inyectado cubre los **subprocesos de shell derivados** —que es para lo que sirve la inyección— y cualquier consumidor que lea los nombres de proxy en el momento de la petición. **No** cubre el tráfico basado en `fetch` del propio proceso del host: 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 que se monte después no puede redirigirlo. Consecuencias: los endpoints del proveedor **no** necesitan una regla allow, y `network.injectEnv: false` no saca al proceso del host de nada. Medido el 2026-09-10 en Node 22; reproducible con `scripts/host-egress-probe.mjs`.
177
179
 
178
180
  ## Collaborating with dsh-auto-review
179
181
 
package/README.hi.md CHANGED
@@ -45,7 +45,7 @@
45
45
  - **अंतर्निहित उच्च-जोखिम आधाररेखा** — एक साथ भेजा गया deny/ask नियम-समूह (विनाशकारी कमांड, विशेषाधिकार वृद्धि, डाउनलोड-और-निष्पादन, संवेदनशील पथ) डिफ़ॉल्ट रूप से सक्षम और उपयोगकर्ता नियमों के बाद जोड़ा गया (निकटतम उपयोगकर्ता नियम इसे अधिरोहित कर सकता है); `builtin.enabled` से टॉगल करें।
46
46
  - **पदानुक्रमित नियम फ़ाइलें** — वैकल्पिक `searchUp` सत्र cwd से फ़ाइल-सिस्टम रूट तक हर `.dsh/rules.yaml` को मर्ज करता है, निकटतम पहले।
47
47
  - **dry-run रोलआउट** — `enforce: false` ऑडिट करता है कि नीति *क्या* करती, हर कॉल को पास करते हुए।
48
- - **हॉट रीलोड** — debounce सहित Chokidar निगरानी; टूटा संपादन पिछले नियम रखता है, कभी क्रैश नहीं।
48
+ - **हॉट रीलोड** — debounce सहित Chokidar निगरानी; टूटा संपादन पिछले नियम रखता है, कभी क्रैश नहीं। WSL होस्ट पर, या `/mnt/<drive>` के नीचे रखी नियम फ़ाइल के लिए, निगरानी polling पर चली जाती है क्योंकि वहाँ मूल परिवर्तन इवेंट भरोसेमंद नहीं होते।
49
49
  - **ज़ोर से विफल** — अमान्य YAML, अज्ञात action/फ़ील्ड, ख़राब globs/regex, बैकट्रैकिंग-प्रवण पैटर्न या `maxRules` से अधिक नियम लोड को विफल करते हैं।
50
50
 
51
51
  ## Rule syntax
@@ -78,6 +78,7 @@ Codex-शैली की **प्रक्रिया-स्तरीय न
78
78
 
79
79
  - **मिलान** — `match.network` `domains` / `ips` / `ports` / `schemes` के साथ (globs, वाइल्डकार्ड, CIDR, पोर्ट श्रेणियाँ; संख्यात्मक YAML पोर्ट स्वीकृत)। `tools/pre-execute` हॉट पथ पर URL-उम्मीदवार निष्कर्षण वेब-टूल तर्कों और bash/pwsh कमांड टेक्स्ट में एम्बेडेड URLs पर चलता है; लूपबैक लक्ष्य `loopback` नीति के अनुसार नियमों को शॉर्ट-सर्किट कर सकते हैं। IPv4-मैप्ड IPv6 लिटरल तुलना से पहले IPv4 रूप में सामान्यीकृत होते हैं, और प्रॉक्सी उन्हीं पतों पर कनेक्ट करता है जिन पर निर्णय लिया गया — दूसरा DNS रिज़ॉल्यूशन नहीं।
80
80
  - **ऑडिट** — अस्वीकृत कनेक्शन स्वामी सत्र में `permissionRules/network` जोड़ते हैं (वही अनुकूली `ignorable` द्वार), `/rules network` और settings पृष्ठ में ब्लॉक काउंटर व हाल की अवरोधन के साथ।
81
+ - **निदान** — अवरुद्ध कनेक्शन `[network: …]` संदेश लेकर आते हैं जो अवरुद्ध लक्ष्य, निर्णय लेने वाला मोड या नियम, और समाधान बताता है।
81
82
 
82
83
  ## Quick start
83
84
 
@@ -174,6 +175,7 @@ dsh --profile web --dump-config | grep -A4 'id: permission-rules'
174
175
  - **पथ उम्मीदवार अनुमानी हैं।** केवल दस्तावेज़ित तर्क कुंजियाँ पथ मिलान को खिलाती हैं, और कार्यक्षेत्र-सापेक्ष मिलान केवल `caseInsensitivePaths` चालू होने पर ASCII-केस-असंवेदी है।
175
176
  - **globs एक रूढ़िवादी उपसमुच्चय हैं।** कोई ब्रेस विस्तार नहीं — दो पैटर्न लिखें, या regex मोड उपयोग करें।
176
177
  - **regex बैकट्रैकिंग गार्ड संरचनात्मक है, संपूर्ण नहीं।** अविश्वसनीय फ़ाइलों के लिए glob मोड पसंद करें।
178
+ - **होस्ट के अपने आउटबाउंड अनुरोध इस प्रॉक्सी से नहीं जाते।** इंजेक्ट किया गया प्रॉक्सी वातावरण **उत्पन्न shell उप-प्रक्रियाओं** को कवर करता है — इंजेक्शन इसी के लिए है — और उन उपभोक्ताओं को जो अनुरोध के समय प्रॉक्सी नाम पढ़ते हैं। यह होस्ट प्रोसेस के अपने `fetch`-आधारित ट्रैफ़िक को **नहीं** कवर करता: launcher पहले प्लगइन के माउंट होने से पहले **लॉन्च वातावरण** से undici का ग्लोबल dispatcher स्थापित कर देता है, वह dispatcher वातावरण से नहीं बल्कि अपनी नीति से रूट करता है, और Node प्रॉक्सी वातावरण को प्रारंभ पर सैंपल करता है — इसलिए बाद में माउंट होने वाला प्लगइन उसे नहीं मोड़ सकता। परिणाम: प्रदाता endpoints के लिए allow नियम की **आवश्यकता नहीं** है, और `network.injectEnv: false` होस्ट प्रोसेस को किसी चीज़ से बाहर नहीं करता। 2026-09-10 को Node 22 पर मापा गया; `scripts/host-egress-probe.mjs` से दोहराएँ।
177
179
 
178
180
  ## Collaborating with dsh-auto-review
179
181
 
package/README.md CHANGED
@@ -46,7 +46,7 @@ Every hit **and** every passthrough is audit-logged as a `permissionRules/decisi
46
46
  - **Built-in high-risk baseline** — a shipped deny/ask ruleset (destructive commands, privilege escalation, download-and-execute, sensitive paths) enabled by default and appended after user rules so a nearer user rule can override it; toggle with `builtin.enabled`.
47
47
  - **Hierarchical rule files** — optional `searchUp` merges every `.dsh/rules.yaml` from the session cwd to the filesystem root, nearest first.
48
48
  - **Dry-run rollout** — `enforce: false` audits what the policy *would* do while passing every call through.
49
- - **Hot reload** — Chokidar watch with debounce; a broken edit keeps the previous rules, never crashes.
49
+ - **Hot reload** — Chokidar watch with debounce; a broken edit keeps the previous rules, never crashes. On a WSL host, or for a rule file under `/mnt/<drive>`, the watch switches to polling because native change events are unreliable there.
50
50
  - **Fail loud** — invalid YAML, unknown actions/fields, bad globs/regexes, backtracking-prone patterns, or more than `maxRules` rules fail the load.
51
51
 
52
52
  ## Rule syntax
@@ -79,6 +79,7 @@ A Codex-style **process-level network policy**: shell subprocess traffic flows t
79
79
 
80
80
  - **Matching** — `match.network` with `domains` / `ips` / `ports` / `schemes` (globs, wildcards, CIDRs, port ranges; numeric YAML ports are accepted). URL-candidate extraction on the `tools/pre-execute` hot path fires on web-tool arguments and URLs embedded in bash/pwsh command text; loopback targets can short-circuit rules per `loopback` policy. IPv4-mapped IPv6 literals are normalized to their IPv4 form before matching, and the proxy connects on the addresses the decision was made on — never a second DNS resolution.
81
81
  - **Audit** — denied connections append `permissionRules/network` to the owning session (same adaptive `ignorable` gate), with block counters and recent interceptions in `/rules network` and the settings page.
82
+ - **Diagnosis** — blocked connections carry a `[network: …]` message naming the blocked target, the mode or rule that decided, and the remediation.
82
83
 
83
84
  ## Quick start
84
85
 
@@ -175,6 +176,7 @@ All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id
175
176
  - **Path candidates are heuristic.** Only the documented argument keys feed path matching, and workspace-relative matching is ASCII-case-insensitive only when `caseInsensitivePaths` is on.
176
177
  - **Globs are a conservative subset.** No brace expansion — write two patterns, or use regex mode.
177
178
  - **The regex backtracking guard is structural, not exhaustive.** Prefer glob mode for untrusted files.
179
+ - **The host's own outbound requests do not go through this proxy.** The injected proxy environment covers **spawned shell children** — which is what the injection is for — and any consumer that reads the proxy names at request time. It does **not** cover the host process's own `fetch`-based traffic: the launcher installs undici's global dispatcher from the **launch environment** before the first plugin mounts, that dispatcher routes by its policy rather than by the environment, and Node samples the proxy environment at start — so a plugin mounting later cannot redirect it. Consequences: provider endpoints do **not** need an allow rule, and `network.injectEnv: false` does not take the host process out of anything. Measured 2026-09-10 on Node 22; reproduce with `scripts/host-egress-probe.mjs`.
178
180
 
179
181
  ## Collaborating with dsh-auto-review
180
182
 
package/README.pt.md CHANGED
@@ -45,7 +45,7 @@ Cada acerto **e** cada passagem direta é registrada como um evento de sessão `
45
45
  - **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`.
46
46
  - **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.
47
47
  - **Implantação em dry-run** — `enforce: false` audita o que a política *faria* enquanto deixa cada chamada passar.
48
- - **Recarga a quente** — vigilância Chokidar com debounce; uma edição quebrada mantém as regras anteriores, nunca falha.
48
+ - **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.
49
49
  - **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.
50
50
 
51
51
  ## Rule syntax
@@ -78,6 +78,7 @@ Uma **política de rede em nível de processo** estilo Codex: o tráfego de subp
78
78
 
79
79
  - **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.
80
80
  - **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.
81
+ - **Diagnóstico** — conexões bloqueadas trazem uma mensagem `[network: …]` nomeando o destino bloqueado, o modo ou a regra que decidiu e a solução.
81
82
 
82
83
  ## Quick start
83
84
 
@@ -174,6 +175,7 @@ Todos os parâmetros são campos Schemastery `Config` (alteráveis pelo cordis.y
174
175
  - **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.
175
176
  - **Globs são um subconjunto conservador.** Sem expansão de chaves — escreva dois padrões, ou use o modo regex.
176
177
  - **A guarda de backtracking de regex é estrutural, não exaustiva.** Prefira o modo glob para arquivos não confiáveis.
178
+ - **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`.
177
179
 
178
180
  ## Collaborating with dsh-auto-review
179
181
 
package/README.zh.md CHANGED
@@ -45,7 +45,7 @@
45
45
  - **内置高危基线** —— 随附的 deny/ask 规则集(破坏性命令、权限提升、下载即执行、敏感路径),默认开启并追加在用户规则之后(更近的用户规则可覆盖);用 `builtin.enabled` 开关。
46
46
  - **分层规则文件** —— 可选 `searchUp` 从会话 cwd 到文件系统根合并每个 `.dsh/rules.yaml`,就近优先。
47
47
  - **试运行上线** —— `enforce: false` 审计策略*会*做什么,同时放行每个调用。
48
- - **热重载** —— Chokidar 监听带去抖;损坏的编辑保留旧规则、绝不崩溃。
48
+ - **热重载** —— Chokidar 监听带去抖;损坏的编辑保留旧规则、绝不崩溃。在 WSL 主机上(或规则文件位于 `/mnt/<盘符>` 下时)监听切换为轮询,因为该处的原生变更事件不可靠。
49
49
  - **失败大声** —— 非法 YAML、未知 action/字段、坏 glob/正则、易回溯模式或超过 `maxRules` 的规则在加载期失败。
50
50
 
51
51
  ## Rule syntax
@@ -78,6 +78,7 @@ Codex 风格的**进程级网络策略**:shell 子进程流量经内置本地
78
78
 
79
79
  - **匹配** —— `match.network` 用 `domains` / `ips` / `ports` / `schemes`(glob、通配符、CIDR、端口范围;数值型 YAML 端口可接受)。`tools/pre-execute` 热路径上的 URL 候选抽取作用于 web 工具参数与嵌入 bash/pwsh 命令文本的 URL;回环目标可按 `loopback` 策略短路规则。IPv4 映射的 IPv6 字面量在匹配前归一化为 IPv4 形式;代理按裁决到的地址建连,不做二次 DNS 解析。
80
80
  - **审计** —— 被拒连接向所属会话追加 `permissionRules/network`(同样的自适应 `ignorable` 门),块计数器与近期拦截在 `/rules network` 与设置页展示。
81
+ - **诊断** —— 被拦截的连接带 `[network: …]` 消息,点名被拦目标、做出裁决的模式或规则,以及处置办法。
81
82
 
82
83
  ## Quick start
83
84
 
@@ -174,6 +175,7 @@ dsh --profile web --dump-config | grep -A4 'id: permission-rules'
174
175
  - **路径候选是启发式的。** 只有文档化的参数键参与路径匹配,且工作区相对匹配仅在 `caseInsensitivePaths` 开启时忽略 ASCII 大小写。
175
176
  - **glob 是保守子集。** 无花括号展开——写两个模式,或用正则模式。
176
177
  - **正则回溯守卫是结构性的、非穷尽的。** 对不可信文件优先用 glob 模式。
178
+ - **宿主自身的出站请求不经过本代理。** 注入的代理环境覆盖**派生的 shell 子进程**(这正是注入的用途),以及在请求时读取代理变量名的消费者;它**不覆盖**宿主进程自身基于 `fetch` 的流量——launcher 在第一个插件挂载之前就用**启动环境**装好了 undici 的全局 dispatcher,该 dispatcher 按策略而非按环境路由,且 Node 在启动时采样代理环境,因此后挂载的插件无法改变它。结论:供应商端点**不需要**允许规则,`network.injectEnv: false` 也不会把宿主进程移出任何东西。2026-09-10 实测于 Node 22;用 `scripts/host-egress-probe.mjs` 可复现。
177
179
 
178
180
  ## Collaborating with dsh-auto-review
179
181
 
package/lib/index.js CHANGED
@@ -516,7 +516,7 @@ var RuleError = class extends Error {
516
516
  * @returns the validated document.
517
517
  */
518
518
  function parseRulesDocument(text) {
519
- const parsed = parseYaml(text);
519
+ const parsed = parseYaml(normalizeLineEndings(text));
520
520
  if (parsed === null || parsed === void 0) return { rules: [] };
521
521
  const root = asRecord(parsed, "rules document root");
522
522
  const unknownRoot = Object.keys(root).filter((key) => key !== "rules");
@@ -875,6 +875,25 @@ function compileParamPatterns(key, patterns, options) {
875
875
  negative
876
876
  };
877
877
  }
878
+ /**
879
+ * Normalize the line endings of one rule-file body before parsing. A file
880
+ * authored or checked out on the Windows side arrives with CRLF, and a lone
881
+ * CR — one not paired with an LF — is NOT a line break to the YAML parser in
882
+ * every position: it survives into the scalar it terminates, so a pattern
883
+ * spelled `domains: [registry.npmjs.org<CR>]`, or a final line ending in a
884
+ * bare CR, compiled a pattern that could never match its target (issue #19
885
+ * item 4). CRLF becomes LF; a stray CR inside a line is dropped (it is junk
886
+ * there — a deliberate CR is written as the YAML escape `\r` and never
887
+ * reaches this text); and a CR-only file (classic Mac line endings, no LF
888
+ * anywhere) treats every CR as its line separator. Every line-ending style
889
+ * therefore parses to the same document.
890
+ * @param text - the raw rule-file text.
891
+ * @returns the same text with LF line breaks and no stray CR.
892
+ */
893
+ function normalizeLineEndings(text) {
894
+ if (!text.includes("\n")) return text.replace(/\r/g, "\n");
895
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "");
896
+ }
878
897
  /** Parse YAML through the `yaml` dependency, mapping parse failures onto {@link RuleError}. */
879
898
  function parseYaml(text) {
880
899
  try {
@@ -2187,13 +2206,22 @@ var NetworkProxy = class {
2187
2206
  }
2188
2207
  /**
2189
2208
  * Connect to the first adjudicated address that accepts, so the tunnel lands
2190
- * on an address the decision approved; a hostname target with no resolution
2191
- * keeps the historical hostname connect. Each candidate is tried in order so
2192
- * a multi-address host does not lose its fallback.
2209
+ * on an address the decision approved. Each candidate is tried in order so a
2210
+ * multi-address host does not lose its fallback.
2211
+ *
2212
+ * A target whose adjudication resolved no address FAILS here instead of
2213
+ * dialing the hostname (issue #21): dialing the name would be a second DNS
2214
+ * resolution — the answer could differ from the one the rules were evaluated
2215
+ * against — and it is the one remaining path where Node's happy-eyeballs
2216
+ * race applies, with its 250 ms `autoSelectFamilyAttemptTimeout` default
2217
+ * that kills any endpoint further away than that. Dialing an already-
2218
+ * resolved literal skips that algorithm entirely (net.js connects an IP
2219
+ * without a lookup), so the tunnel only ever reaches an adjudicated
2220
+ * address; the client's retry resolves and adjudicates again.
2193
2221
  */
2194
2222
  async connectUpstream(target, port) {
2195
2223
  const pinned = pinnedAddresses(target);
2196
- if (pinned.length === 0) return connect(port, target.host);
2224
+ if (pinned.length === 0) throw new Error(`no adjudicated address for ${target.host}`);
2197
2225
  let lastError;
2198
2226
  for (const address of pinned) try {
2199
2227
  return await new Promise((resolve, reject) => {
@@ -2547,6 +2575,53 @@ const WEB_TOOLS = ["web_fetch", "web_search"];
2547
2575
  /** Stale in-flight entries are dropped after this many milliseconds (attribution is best-effort). */
2548
2576
  const IN_FLIGHT_TTL_MS = 6e5;
2549
2577
  /**
2578
+ * Chokidar polling interval used when the watched path lives on a filesystem
2579
+ * whose change events are unreliable (WSL drvfs/9p mounts): polling costs a
2580
+ * stat per interval, which is negligible for a rule file and far cheaper than
2581
+ * a rule edit that silently never hot-reloads.
2582
+ */
2583
+ const POLLING_WATCH_INTERVAL_MS = 300;
2584
+ /**
2585
+ * Whether one watched path lies under a WSL drvfs mount (`/mnt/<drive>/…`),
2586
+ * where inotify-style change events are known to be unreliable — chokidar
2587
+ * then has to poll (issue #19 item 1). The separator is normalized first so
2588
+ * the check also recognizes the path as the Windows side spells it; a
2589
+ * Windows drive path (`D:\…`) never matches.
2590
+ * @param path - the watched file or directory path.
2591
+ * @returns true when the path addresses a drvfs mount.
2592
+ */
2593
+ function isDvrfsPath(path) {
2594
+ return /^\/mnt\/[a-z](?:\/|$)/i.test(path.replace(/\\/g, "/"));
2595
+ }
2596
+ /**
2597
+ * Whether the running kernel is WSL's, as `/proc/version` reports it. Every
2598
+ * WSL kernel string carries `microsoft` (`…-microsoft-standard-WSL2`), which
2599
+ * is what the issue asks the detection to key on; a non-WSL Linux kernel
2600
+ * never does, and hosts without `/proc/version` (Windows, macOS) answer
2601
+ * false.
2602
+ * @param procVersion - the `/proc/version` text, or an empty string when it cannot be read.
2603
+ * @returns true when the kernel is Microsoft's.
2604
+ */
2605
+ function isWslKernel(procVersion) {
2606
+ return procVersion.toLowerCase().includes("microsoft");
2607
+ }
2608
+ /** `/proc/version` is immutable for the process lifetime: read it at most once. */
2609
+ let procVersionText;
2610
+ /** Read `/proc/version`, or an empty string wherever the file is absent (Windows, macOS). */
2611
+ function readProcVersion() {
2612
+ if (procVersionText === void 0) try {
2613
+ procVersionText = readFileSync("/proc/version", "utf8");
2614
+ } catch {
2615
+ procVersionText = "";
2616
+ }
2617
+ return procVersionText;
2618
+ }
2619
+ /** Chokidar options that switch one watch to polling (drvfs mount or WSL host). */
2620
+ const POLLING_WATCH_OPTIONS = {
2621
+ usePolling: true,
2622
+ interval: POLLING_WATCH_INTERVAL_MS
2623
+ };
2624
+ /**
2550
2625
  * State and behavior. One instance per plugin mount; disposals are owned by
2551
2626
  * the watcher/timer/proxy effects registered in {@link apply}.
2552
2627
  */
@@ -2558,6 +2633,10 @@ var PermissionRulesRuntime = class {
2558
2633
  compileCache = /* @__PURE__ */ new Map();
2559
2634
  /** Live watchers per watched path (rule file or candidate ancestor directory), with the cwds each serves. */
2560
2635
  watchers = /* @__PURE__ */ new Map();
2636
+ /** The configured chain session-less proxy connections are judged against (see {@link hostChain}); never a `byCwd` member. */
2637
+ hostLoaded;
2638
+ /** Whether the one-time "configured chain unusable" warning was already logged. */
2639
+ hostChainWarned = false;
2561
2640
  /** Debounce timers per rule-file path. */
2562
2641
  timers = /* @__PURE__ */ new Map();
2563
2642
  /** Whether the host honors the audit envelope's `ignorable` marker: unknown until the first decision (or peer-version check). */
@@ -3015,8 +3094,44 @@ var PermissionRulesRuntime = class {
3015
3094
  ruleset: loaded.compiled,
3016
3095
  sources: loaded.sources
3017
3096
  });
3097
+ if (chains.length === 0) {
3098
+ const host = this.hostChain();
3099
+ if (host !== void 0) chains.push(host);
3100
+ }
3018
3101
  return chains;
3019
3102
  }
3103
+ /**
3104
+ * The CONFIGURED chain a session-less connection is judged against: the
3105
+ * chain for the host process's own working directory (project rule file →
3106
+ * an absolute `rulesFile` → the configured fallback → the shipped
3107
+ * baseline), loaded on first use. Proxy traffic that carries no session —
3108
+ * the harness's own plugin-market catalog/update/npm lookups at boot — used
3109
+ * to be judged against an empty chain and therefore always hit the mode
3110
+ * default, so a target an already-configured allow rule permits stayed
3111
+ * blocked until some session had run a tool call (issue #18). The chain is
3112
+ * kept OUT of `byCwd` on purpose: it must never outrank a session workspace
3113
+ * chain, and it stops being consulted as soon as one is loaded (a host-level
3114
+ * connection is then judged exactly as before, against the loaded workspace
3115
+ * chains). It is not watched either: the session-less window is the boot
3116
+ * window, and the first tool call of any session takes over with the normal
3117
+ * per-workspace chain, which is watched.
3118
+ * @returns the configured chain, or undefined when it cannot be loaded (the mode default then applies).
3119
+ */
3120
+ hostChain() {
3121
+ if (this.hostLoaded === void 0) try {
3122
+ this.hostLoaded = this.load(process.cwd());
3123
+ } catch (error) {
3124
+ if (!this.hostChainWarned) {
3125
+ this.hostChainWarned = true;
3126
+ this.ctx.logger.warn(`permission-rules: cannot load the configured rules for session-less connections at ${process.cwd()}: ${String(error)} (the network mode default applies)`);
3127
+ }
3128
+ return;
3129
+ }
3130
+ return {
3131
+ ruleset: this.hostLoaded.compiled,
3132
+ sources: this.hostLoaded.sources
3133
+ };
3134
+ }
3020
3135
  /** Mark one delegated shell execution as in-flight (newest attribution wins). */
3021
3136
  markShell(exec) {
3022
3137
  this.inFlight.set(String(exec.callId), {
@@ -3534,6 +3649,19 @@ var PermissionRulesRuntime = class {
3534
3649
  throw error instanceof RuleError ? error : new RuleError(`permission-rules: cannot load ${filePath}: ${message}`);
3535
3650
  }
3536
3651
  }
3652
+ /**
3653
+ * Whether one watched path must be polled instead of trusting the platform's
3654
+ * change events. WSL is the case issue #19 item 1 reports: a rule file under
3655
+ * `/mnt/<drive>` (drvfs/9p) or any file on a WSL host can stop delivering
3656
+ * chokidar change events with no error at all, so the watcher edits would
3657
+ * silently stop hot-reloading. Polling is the documented chokidar remedy;
3658
+ * everywhere else the native watcher stays in place.
3659
+ * @param path - the watched rule file or candidate directory.
3660
+ * @returns true when the watch should run in polling mode.
3661
+ */
3662
+ watchPollingFor(path) {
3663
+ return isDvrfsPath(path) || isWslKernel(readProcVersion());
3664
+ }
3537
3665
  /** Attach (once per file path) the Chokidar watcher feeding {@link reload}. */
3538
3666
  attachWatch(cwd, source) {
3539
3667
  if (!this.config.watch || source === "" || this.config.builtin.enabled && source === this.config.builtin.path) return;
@@ -3543,9 +3671,11 @@ var PermissionRulesRuntime = class {
3543
3671
  return;
3544
3672
  }
3545
3673
  const cwds = /* @__PURE__ */ new Set([cwd]);
3674
+ const polling = this.watchPollingFor(source);
3546
3675
  const watcher = chokidar.watch(source, {
3547
3676
  persistent: true,
3548
- ignoreInitial: true
3677
+ ignoreInitial: true,
3678
+ ...polling ? POLLING_WATCH_OPTIONS : {}
3549
3679
  });
3550
3680
  const onEvent = () => this.scheduleReload(source);
3551
3681
  watcher.on("add", onEvent);
@@ -3641,6 +3771,7 @@ var PermissionRulesRuntime = class {
3641
3771
  const watchOptions = {
3642
3772
  persistent: true,
3643
3773
  ignoreInitial: true,
3774
+ ...this.watchPollingFor(candidate) ? POLLING_WATCH_OPTIONS : {},
3644
3775
  ignored: (path) => path.split(sep).includes("node_modules") || path.split(sep).includes(".git")
3645
3776
  };
3646
3777
  const watcher = dir === parent ? chokidar.watch(dir, watchOptions) : chokidar.watch(dir, {
@@ -101,9 +101,18 @@ export declare class NetworkProxy {
101
101
  private handleRequest;
102
102
  /**
103
103
  * Connect to the first adjudicated address that accepts, so the tunnel lands
104
- * on an address the decision approved; a hostname target with no resolution
105
- * keeps the historical hostname connect. Each candidate is tried in order so
106
- * a multi-address host does not lose its fallback.
104
+ * on an address the decision approved. Each candidate is tried in order so a
105
+ * multi-address host does not lose its fallback.
106
+ *
107
+ * A target whose adjudication resolved no address FAILS here instead of
108
+ * dialing the hostname (issue #21): dialing the name would be a second DNS
109
+ * resolution — the answer could differ from the one the rules were evaluated
110
+ * against — and it is the one remaining path where Node's happy-eyeballs
111
+ * race applies, with its 250 ms `autoSelectFamilyAttemptTimeout` default
112
+ * that kills any endpoint further away than that. Dialing an already-
113
+ * resolved literal skips that algorithm entirely (net.js connects an IP
114
+ * without a lookup), so the tunnel only ever reaches an adjudicated
115
+ * address; the client's retry resolves and adjudicates again.
107
116
  */
108
117
  private connectUpstream;
109
118
  /** CONNECT tunneling (HTTPS and friends): adjudicate, then either 403 or an established TCP tunnel. */
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAGhE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE3D,oHAAoH;AACpH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAyF,CAAA;AAEtI,6DAA6D;AAC7D,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAA6B,CAAA;AAE7E,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,QAAQ,CAAC,OAAO,EAAE;YAAE,MAAM,CAAC,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;gBAAE,SAAS,CAAC,EAAE,IAAI,CAAA;aAAE,GAAG,OAAO,CAAA;SAAE,CAAA;KACtH,CAAA;CACF;AAED,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,eAAe,CAAA;IAC3D,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,gBAAgB,GAAG,SAAS,CAAA;IACzD,uEAAuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,GAAG,SAAS,KAAK,IAAI,CAAA;IAClG,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CACjD;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IAOX,OAAO,CAAC,QAAQ,CAAC,OAAO;IANpC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6C;IACnE,OAAO,CAAC,UAAU,CAAI;gBAEO,OAAO,EAAE,mBAAmB;IAEzD,2DAA2D;IAC3D,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,+EAA+E;IAC/E,YAAY,IAAI,SAAS,kBAAkB,EAAE;IAI7C,iCAAiC;IACjC,UAAU,IAAI,YAAY;IAI1B,kDAAkD;IAClD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IA4BxB,kFAAkF;IAClF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtB,oHAAoH;YACtG,aAAa;IAyC3B;;;;;OAKG;YACW,eAAe;IAqB7B,uGAAuG;YACzF,aAAa;IAiD3B,yFAAyF;YAC3E,oBAAoB;IAgBlC,4FAA4F;IAC5F,OAAO,CAAC,WAAW;CA4BpB;AAsCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,IAAI,CAyBtF"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAGhE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE3D,oHAAoH;AACpH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAyF,CAAA;AAEtI,6DAA6D;AAC7D,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAA6B,CAAA;AAE7E,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,QAAQ,CAAC,OAAO,EAAE;YAAE,MAAM,CAAC,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;gBAAE,SAAS,CAAC,EAAE,IAAI,CAAA;aAAE,GAAG,OAAO,CAAA;SAAE,CAAA;KACtH,CAAA;CACF;AAED,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,eAAe,CAAA;IAC3D,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,gBAAgB,GAAG,SAAS,CAAA;IACzD,uEAAuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,GAAG,SAAS,KAAK,IAAI,CAAA;IAClG,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CACjD;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IAOX,OAAO,CAAC,QAAQ,CAAC,OAAO;IANpC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6C;IACnE,OAAO,CAAC,UAAU,CAAI;gBAEO,OAAO,EAAE,mBAAmB;IAEzD,2DAA2D;IAC3D,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,+EAA+E;IAC/E,YAAY,IAAI,SAAS,kBAAkB,EAAE;IAI7C,iCAAiC;IACjC,UAAU,IAAI,YAAY;IAI1B,kDAAkD;IAClD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IA4BxB,kFAAkF;IAClF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtB,oHAAoH;YACtG,aAAa;IAyC3B;;;;;;;;;;;;;;OAcG;YACW,eAAe;IAqB7B,uGAAuG;YACzF,aAAa;IAiD3B,yFAAyF;YAC3E,oBAAoB;IAgBlC,4FAA4F;IAC5F,OAAO,CAAC,WAAW;CA4BpB;AAsCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,IAAI,CAyBtF"}
@@ -1 +1 @@
1
- {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/rules.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/rules.ts"],"names":[],"mappings":"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"}
@@ -33,6 +33,26 @@ interface LoadedRules {
33
33
  /** `true` when the last initial load threw under `badFilePolicy: 'fail'`. */
34
34
  readonly failed?: true;
35
35
  }
36
+ /**
37
+ * Whether one watched path lies under a WSL drvfs mount (`/mnt/<drive>/…`),
38
+ * where inotify-style change events are known to be unreliable — chokidar
39
+ * then has to poll (issue #19 item 1). The separator is normalized first so
40
+ * the check also recognizes the path as the Windows side spells it; a
41
+ * Windows drive path (`D:\…`) never matches.
42
+ * @param path - the watched file or directory path.
43
+ * @returns true when the path addresses a drvfs mount.
44
+ */
45
+ export declare function isDvrfsPath(path: string): boolean;
46
+ /**
47
+ * Whether the running kernel is WSL's, as `/proc/version` reports it. Every
48
+ * WSL kernel string carries `microsoft` (`…-microsoft-standard-WSL2`), which
49
+ * is what the issue asks the detection to key on; a non-WSL Linux kernel
50
+ * never does, and hosts without `/proc/version` (Windows, macOS) answer
51
+ * false.
52
+ * @param procVersion - the `/proc/version` text, or an empty string when it cannot be read.
53
+ * @returns true when the kernel is Microsoft's.
54
+ */
55
+ export declare function isWslKernel(procVersion: string): boolean;
36
56
  /**
37
57
  * State and behavior. One instance per plugin mount; disposals are owned by
38
58
  * the watcher/timer/proxy effects registered in {@link apply}.
@@ -45,6 +65,10 @@ export declare class PermissionRulesRuntime {
45
65
  private readonly compileCache;
46
66
  /** Live watchers per watched path (rule file or candidate ancestor directory), with the cwds each serves. */
47
67
  private readonly watchers;
68
+ /** The configured chain session-less proxy connections are judged against (see {@link hostChain}); never a `byCwd` member. */
69
+ private hostLoaded;
70
+ /** Whether the one-time "configured chain unusable" warning was already logged. */
71
+ private hostChainWarned;
48
72
  /** Debounce timers per rule-file path. */
49
73
  private readonly timers;
50
74
  /** Whether the host honors the audit envelope's `ignorable` marker: unknown until the first decision (or peer-version check). */
@@ -222,6 +246,24 @@ export declare class PermissionRulesRuntime {
222
246
  private decideProxyTarget;
223
247
  /** The loaded rule chains in cache order, nearest workspace first. */
224
248
  private proxyChains;
249
+ /**
250
+ * The CONFIGURED chain a session-less connection is judged against: the
251
+ * chain for the host process's own working directory (project rule file →
252
+ * an absolute `rulesFile` → the configured fallback → the shipped
253
+ * baseline), loaded on first use. Proxy traffic that carries no session —
254
+ * the harness's own plugin-market catalog/update/npm lookups at boot — used
255
+ * to be judged against an empty chain and therefore always hit the mode
256
+ * default, so a target an already-configured allow rule permits stayed
257
+ * blocked until some session had run a tool call (issue #18). The chain is
258
+ * kept OUT of `byCwd` on purpose: it must never outrank a session workspace
259
+ * chain, and it stops being consulted as soon as one is loaded (a host-level
260
+ * connection is then judged exactly as before, against the loaded workspace
261
+ * chains). It is not watched either: the session-less window is the boot
262
+ * window, and the first tool call of any session takes over with the normal
263
+ * per-workspace chain, which is watched.
264
+ * @returns the configured chain, or undefined when it cannot be loaded (the mode default then applies).
265
+ */
266
+ private hostChain;
225
267
  /** Mark one delegated shell execution as in-flight (newest attribution wins). */
226
268
  private markShell;
227
269
  /** Drop one shell execution when it settles. */
@@ -344,6 +386,17 @@ export declare class PermissionRulesRuntime {
344
386
  validateDeploymentFiles(): void;
345
387
  /** Parse and compile one mandated file, rethrowing as a mount failure. */
346
388
  private loadForValidation;
389
+ /**
390
+ * Whether one watched path must be polled instead of trusting the platform's
391
+ * change events. WSL is the case issue #19 item 1 reports: a rule file under
392
+ * `/mnt/<drive>` (drvfs/9p) or any file on a WSL host can stop delivering
393
+ * chokidar change events with no error at all, so the watcher edits would
394
+ * silently stop hot-reloading. Polling is the documented chokidar remedy;
395
+ * everywhere else the native watcher stays in place.
396
+ * @param path - the watched rule file or candidate directory.
397
+ * @returns true when the watch should run in polling mode.
398
+ */
399
+ watchPollingFor(path: string): boolean;
347
400
  /** Attach (once per file path) the Chokidar watcher feeding {@link reload}. */
348
401
  private attachWatch;
349
402
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-permission-rules",
3
- "version": "0.6.18",
3
+ "version": "0.6.20",
4
4
  "description": "Declarative Claude Code-style permission rules plus a Codex-style process-level network policy for DeepSeek Harness: ordered allow/deny/ask rules with tool-name, argument (glob/regex), workspace-path, and network-target (domain/ip/port/scheme) matching on the tools/pre-execute waterfall, a built-in local HTTP/CONNECT proxy governing shell subprocess traffic, three network modes mapped onto the official sandbox presets, full session-log audit, HMR rule reload, and a settings page with a rule editor, block counters, and recent interception lists.",
5
5
  "private": false,
6
6
  "type": "module",
package/src/proxy.ts CHANGED
@@ -199,13 +199,22 @@ export class NetworkProxy {
199
199
 
200
200
  /**
201
201
  * Connect to the first adjudicated address that accepts, so the tunnel lands
202
- * on an address the decision approved; a hostname target with no resolution
203
- * keeps the historical hostname connect. Each candidate is tried in order so
204
- * a multi-address host does not lose its fallback.
202
+ * on an address the decision approved. Each candidate is tried in order so a
203
+ * multi-address host does not lose its fallback.
204
+ *
205
+ * A target whose adjudication resolved no address FAILS here instead of
206
+ * dialing the hostname (issue #21): dialing the name would be a second DNS
207
+ * resolution — the answer could differ from the one the rules were evaluated
208
+ * against — and it is the one remaining path where Node's happy-eyeballs
209
+ * race applies, with its 250 ms `autoSelectFamilyAttemptTimeout` default
210
+ * that kills any endpoint further away than that. Dialing an already-
211
+ * resolved literal skips that algorithm entirely (net.js connects an IP
212
+ * without a lookup), so the tunnel only ever reaches an adjudicated
213
+ * address; the client's retry resolves and adjudicates again.
205
214
  */
206
215
  private async connectUpstream(target: NetworkTarget, port: number): Promise<Duplex> {
207
216
  const pinned = pinnedAddresses(target)
208
- if (pinned.length === 0) return connect(port, target.host)
217
+ if (pinned.length === 0) throw new Error(`no adjudicated address for ${target.host}`)
209
218
  let lastError: unknown
210
219
  for (const address of pinned) {
211
220
  try {
package/src/rules.ts CHANGED
@@ -291,7 +291,7 @@ export interface MatchContext {
291
291
  * @returns the validated document.
292
292
  */
293
293
  export function parseRulesDocument(text: string): RulesFileDoc {
294
- const parsed = parseYaml(text)
294
+ const parsed = parseYaml(normalizeLineEndings(text))
295
295
  // An empty (or comment-only) file is a valid empty rule set.
296
296
  if (parsed === null || parsed === undefined) return { rules: [] }
297
297
  const root = asRecord(parsed, 'rules document root')
@@ -714,6 +714,26 @@ function compileParamPatterns(key: string, patterns: readonly string[], options:
714
714
 
715
715
  // --- YAML/shape validation -------------------------------------------------
716
716
 
717
+ /**
718
+ * Normalize the line endings of one rule-file body before parsing. A file
719
+ * authored or checked out on the Windows side arrives with CRLF, and a lone
720
+ * CR — one not paired with an LF — is NOT a line break to the YAML parser in
721
+ * every position: it survives into the scalar it terminates, so a pattern
722
+ * spelled `domains: [registry.npmjs.org<CR>]`, or a final line ending in a
723
+ * bare CR, compiled a pattern that could never match its target (issue #19
724
+ * item 4). CRLF becomes LF; a stray CR inside a line is dropped (it is junk
725
+ * there — a deliberate CR is written as the YAML escape `\r` and never
726
+ * reaches this text); and a CR-only file (classic Mac line endings, no LF
727
+ * anywhere) treats every CR as its line separator. Every line-ending style
728
+ * therefore parses to the same document.
729
+ * @param text - the raw rule-file text.
730
+ * @returns the same text with LF line breaks and no stray CR.
731
+ */
732
+ function normalizeLineEndings(text: string): string {
733
+ if (!text.includes('\n')) return text.replace(/\r/g, '\n')
734
+ return text.replace(/\r\n/g, '\n').replace(/\r/g, '')
735
+ }
736
+
717
737
  /** Parse YAML through the `yaml` dependency, mapping parse failures onto {@link RuleError}. */
718
738
  function parseYaml(text: string): unknown {
719
739
  try {
package/src/runtime.ts CHANGED
@@ -81,6 +81,58 @@ const WEB_TOOLS: readonly string[] = ['web_fetch', 'web_search']
81
81
  /** Stale in-flight entries are dropped after this many milliseconds (attribution is best-effort). */
82
82
  const IN_FLIGHT_TTL_MS = 10 * 60 * 1000
83
83
 
84
+ /**
85
+ * Chokidar polling interval used when the watched path lives on a filesystem
86
+ * whose change events are unreliable (WSL drvfs/9p mounts): polling costs a
87
+ * stat per interval, which is negligible for a rule file and far cheaper than
88
+ * a rule edit that silently never hot-reloads.
89
+ */
90
+ const POLLING_WATCH_INTERVAL_MS = 300
91
+
92
+ /**
93
+ * Whether one watched path lies under a WSL drvfs mount (`/mnt/<drive>/…`),
94
+ * where inotify-style change events are known to be unreliable — chokidar
95
+ * then has to poll (issue #19 item 1). The separator is normalized first so
96
+ * the check also recognizes the path as the Windows side spells it; a
97
+ * Windows drive path (`D:\…`) never matches.
98
+ * @param path - the watched file or directory path.
99
+ * @returns true when the path addresses a drvfs mount.
100
+ */
101
+ export function isDvrfsPath(path: string): boolean {
102
+ return /^\/mnt\/[a-z](?:\/|$)/i.test(path.replace(/\\/g, '/'))
103
+ }
104
+
105
+ /**
106
+ * Whether the running kernel is WSL's, as `/proc/version` reports it. Every
107
+ * WSL kernel string carries `microsoft` (`…-microsoft-standard-WSL2`), which
108
+ * is what the issue asks the detection to key on; a non-WSL Linux kernel
109
+ * never does, and hosts without `/proc/version` (Windows, macOS) answer
110
+ * false.
111
+ * @param procVersion - the `/proc/version` text, or an empty string when it cannot be read.
112
+ * @returns true when the kernel is Microsoft's.
113
+ */
114
+ export function isWslKernel(procVersion: string): boolean {
115
+ return procVersion.toLowerCase().includes('microsoft')
116
+ }
117
+
118
+ /** `/proc/version` is immutable for the process lifetime: read it at most once. */
119
+ let procVersionText: string | undefined
120
+
121
+ /** Read `/proc/version`, or an empty string wherever the file is absent (Windows, macOS). */
122
+ function readProcVersion(): string {
123
+ if (procVersionText === undefined) {
124
+ try {
125
+ procVersionText = readFileSync('/proc/version', 'utf8')
126
+ } catch {
127
+ procVersionText = ''
128
+ }
129
+ }
130
+ return procVersionText
131
+ }
132
+
133
+ /** Chokidar options that switch one watch to polling (drvfs mount or WSL host). */
134
+ const POLLING_WATCH_OPTIONS = { usePolling: true, interval: POLLING_WATCH_INTERVAL_MS } as const
135
+
84
136
  /**
85
137
  * State and behavior. One instance per plugin mount; disposals are owned by
86
138
  * the watcher/timer/proxy effects registered in {@link apply}.
@@ -95,6 +147,12 @@ export class PermissionRulesRuntime {
95
147
  /** Live watchers per watched path (rule file or candidate ancestor directory), with the cwds each serves. */
96
148
  private readonly watchers = new Map<string, WatcherEntry>()
97
149
 
150
+ /** The configured chain session-less proxy connections are judged against (see {@link hostChain}); never a `byCwd` member. */
151
+ private hostLoaded: LoadedRules | undefined
152
+
153
+ /** Whether the one-time "configured chain unusable" warning was already logged. */
154
+ private hostChainWarned = false
155
+
98
156
  /** Debounce timers per rule-file path. */
99
157
  private readonly timers = new Map<string, ReturnType<typeof setTimeout>>()
100
158
 
@@ -525,9 +583,47 @@ export class PermissionRulesRuntime {
525
583
  for (const loaded of this.byCwd.values()) {
526
584
  chains.push({ ruleset: loaded.compiled, sources: loaded.sources })
527
585
  }
586
+ if (chains.length === 0) {
587
+ const host = this.hostChain()
588
+ if (host !== undefined) chains.push(host)
589
+ }
528
590
  return chains
529
591
  }
530
592
 
593
+ /**
594
+ * The CONFIGURED chain a session-less connection is judged against: the
595
+ * chain for the host process's own working directory (project rule file →
596
+ * an absolute `rulesFile` → the configured fallback → the shipped
597
+ * baseline), loaded on first use. Proxy traffic that carries no session —
598
+ * the harness's own plugin-market catalog/update/npm lookups at boot — used
599
+ * to be judged against an empty chain and therefore always hit the mode
600
+ * default, so a target an already-configured allow rule permits stayed
601
+ * blocked until some session had run a tool call (issue #18). The chain is
602
+ * kept OUT of `byCwd` on purpose: it must never outrank a session workspace
603
+ * chain, and it stops being consulted as soon as one is loaded (a host-level
604
+ * connection is then judged exactly as before, against the loaded workspace
605
+ * chains). It is not watched either: the session-less window is the boot
606
+ * window, and the first tool call of any session takes over with the normal
607
+ * per-workspace chain, which is watched.
608
+ * @returns the configured chain, or undefined when it cannot be loaded (the mode default then applies).
609
+ */
610
+ private hostChain(): NetworkChain | undefined {
611
+ if (this.hostLoaded === undefined) {
612
+ try {
613
+ this.hostLoaded = this.load(process.cwd())
614
+ } catch (error: unknown) {
615
+ // Never throw into the proxy: an unusable configured chain degrades to
616
+ // the mode default (fail closed), with one warning per mount.
617
+ if (!this.hostChainWarned) {
618
+ this.hostChainWarned = true
619
+ this.ctx.logger.warn(`permission-rules: cannot load the configured rules for session-less connections at ${process.cwd()}: ${String(error)} (the network mode default applies)`)
620
+ }
621
+ return undefined
622
+ }
623
+ }
624
+ return { ruleset: this.hostLoaded.compiled, sources: this.hostLoaded.sources }
625
+ }
626
+
531
627
  /** Mark one delegated shell execution as in-flight (newest attribution wins). */
532
628
  private markShell(exec: ToolExecution): void {
533
629
  this.inFlight.set(String(exec.callId), { tool: exec.name, callId: exec.callId, startedAt: Date.now(), agent: exec.agent })
@@ -1014,6 +1110,20 @@ export class PermissionRulesRuntime {
1014
1110
  }
1015
1111
  }
1016
1112
 
1113
+ /**
1114
+ * Whether one watched path must be polled instead of trusting the platform's
1115
+ * change events. WSL is the case issue #19 item 1 reports: a rule file under
1116
+ * `/mnt/<drive>` (drvfs/9p) or any file on a WSL host can stop delivering
1117
+ * chokidar change events with no error at all, so the watcher edits would
1118
+ * silently stop hot-reloading. Polling is the documented chokidar remedy;
1119
+ * everywhere else the native watcher stays in place.
1120
+ * @param path - the watched rule file or candidate directory.
1121
+ * @returns true when the watch should run in polling mode.
1122
+ */
1123
+ watchPollingFor(path: string): boolean {
1124
+ return isDvrfsPath(path) || isWslKernel(readProcVersion())
1125
+ }
1126
+
1017
1127
  /** Attach (once per file path) the Chokidar watcher feeding {@link reload}. */
1018
1128
  private attachWatch(cwd: string, source: string): void {
1019
1129
  if (!this.config.watch || source === '' || (this.config.builtin.enabled && source === this.config.builtin.path)) return
@@ -1023,7 +1133,8 @@ export class PermissionRulesRuntime {
1023
1133
  return
1024
1134
  }
1025
1135
  const cwds = new Set([cwd])
1026
- const watcher = chokidar.watch(source, { persistent: true, ignoreInitial: true })
1136
+ const polling = this.watchPollingFor(source)
1137
+ const watcher = chokidar.watch(source, { persistent: true, ignoreInitial: true, ...(polling ? POLLING_WATCH_OPTIONS : {}) })
1027
1138
  const onEvent = (): void => this.scheduleReload(source)
1028
1139
  watcher.on('add', onEvent)
1029
1140
  watcher.on('change', onEvent)
@@ -1120,9 +1231,11 @@ export class PermissionRulesRuntime {
1120
1231
  }
1121
1232
  const cwds = new Set([cwd])
1122
1233
  const candidates = new Map([[cwd, candidate]])
1234
+ const polling = this.watchPollingFor(candidate)
1123
1235
  const watchOptions = {
1124
1236
  persistent: true,
1125
1237
  ignoreInitial: true,
1238
+ ...(polling ? POLLING_WATCH_OPTIONS : {}),
1126
1239
  ignored: (path: string): boolean => path.split(sep).includes('node_modules') || path.split(sep).includes('.git'),
1127
1240
  }
1128
1241
  const watcher = dir === parent